| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.netbeans.modules.refactoring.java.plugins; |
| |
| import com.sun.source.tree.*; |
| import com.sun.source.util.TreePath; |
| import java.io.IOException; |
| import java.util.*; |
| import javax.lang.model.element.*; |
| import javax.lang.model.type.TypeKind; |
| import javax.lang.model.type.TypeMirror; |
| import javax.lang.model.util.Types; |
| import org.netbeans.api.java.classpath.ClassPath; |
| import org.netbeans.api.java.source.*; |
| import org.netbeans.modules.refactoring.api.AbstractRefactoring; |
| import org.netbeans.modules.refactoring.api.Problem; |
| import org.netbeans.modules.refactoring.java.RefactoringUtils; |
| import org.netbeans.modules.refactoring.java.api.ExtractInterfaceRefactoring; |
| import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; |
| import org.netbeans.modules.refactoring.java.spi.DiffElement; |
| import org.netbeans.modules.refactoring.java.spi.JavaRefactoringPlugin; |
| import org.netbeans.modules.refactoring.spi.RefactoringElementsBag; |
| import org.openide.filesystems.FileObject; |
| import org.openide.filesystems.FileUtil; |
| import org.openide.util.NbBundle; |
| import org.openide.util.Utilities; |
| |
| /** |
| * Plugin that implements the core functionality of Extract Interface refactoring. |
| * <br>Extracts: <ul> |
| * <li>implements interfaces</li> |
| * <li>public nonstatic methods</li> |
| * <li>public static final fields</li> |
| * <li>XXX public static class/interface/enum/annotation type.<br><i>dangerous, it might contain |
| * elements that will be unaccessible from the new interface. Maybe reusing Move Class refactoring |
| * would be appropriate. Not implemented in 6.0 yet. Pre-6.0 implementation was not solved references at all.</i></li> |
| * </ul> |
| * XXX there should be option Copy/Move/AsIs javadoc. |
| * |
| * @author Martin Matula, Jan Pokorsky |
| */ |
| public final class ExtractInterfaceRefactoringPlugin extends JavaRefactoringPlugin { |
| |
| /** Reference to the parent refactoring instance */ |
| private final ExtractInterfaceRefactoring refactoring; |
| |
| private String pkgName; |
| |
| /** class for extracting interface */ |
| private ElementHandle<TypeElement> classHandle; |
| |
| /** Creates a new instance of ExtractInterfaceRefactoringPlugin |
| * @param refactoring Parent refactoring instance. |
| */ |
| ExtractInterfaceRefactoringPlugin(ExtractInterfaceRefactoring refactoring) { |
| this.refactoring = refactoring; |
| } |
| |
| @Override |
| public Problem fastCheckParameters() { |
| Problem result = null; |
| |
| String newName = refactoring.getInterfaceName(); |
| |
| if (!Utilities.isJavaIdentifier(newName)) { |
| result = createProblem(result, true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_InvalidIdentifier", newName)); // NOI18N |
| return result; |
| } |
| |
| FileObject primFile = refactoring.getSourceType().getFileObject(); |
| FileObject folder = primFile.getParent(); |
| FileObject[] children = folder.getChildren(); |
| for (FileObject child: children) { |
| if (!child.isVirtual() && child.getName().equalsIgnoreCase(newName) && "java".equalsIgnoreCase(child.getExt())) { // NOI18N |
| result = createProblem(result, true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ClassClash", newName, pkgName)); // NOI18N |
| return result; |
| } |
| } |
| |
| return super.fastCheckParameters(); |
| } |
| |
| @Override |
| protected Problem fastCheckParameters(CompilationController javac) throws IOException { |
| Problem result = null; |
| String newName = refactoring.getInterfaceName(); |
| TypeMirror parsedType = javac.getTreeUtilities().parseType(newName, classHandle.resolve(javac)); |
| if(parsedType != null && parsedType.getKind() != TypeKind.ERROR) { |
| result = createProblem(result, true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ClassClash", newName, pkgName)); // NOI18N |
| return result; |
| } |
| return super.fastCheckParameters(javac); |
| } |
| |
| @Override |
| public Problem prepare(RefactoringElementsBag bag) { |
| FileObject primFile = refactoring.getSourceType().getFileObject(); |
| try { |
| UpdateClassTask.create(bag, primFile, refactoring, classHandle); |
| } catch (IOException ex) { |
| throw new RuntimeException(ex); |
| } |
| return null; |
| } |
| |
| @Override |
| protected JavaSource getJavaSource(Phase p) { |
| return JavaSource.forFileObject(refactoring.getSourceType().getFileObject()); |
| } |
| |
| @Override |
| protected Problem preCheck(CompilationController javac) throws IOException { |
| // fire operation start on the registered progress listeners (1 step) |
| fireProgressListenerStart(AbstractRefactoring.PRE_CHECK, 1); |
| javac.toPhase(JavaSource.Phase.RESOLVED); |
| try { |
| TreePathHandle sourceType = refactoring.getSourceType(); |
| |
| // check whether the element is valid |
| Problem result = isElementAvail(sourceType, javac); |
| if (result != null) { |
| // fatal error -> don't continue with further checks |
| return result; |
| } |
| |
| // check whether the element is an unresolved class |
| Element sourceElm = sourceType.resolveElement(javac); |
| result = JavaPluginUtils.isSourceElement(sourceElm, javac); |
| if (result != null) { |
| return result; |
| } |
| if (sourceElm == null || (sourceElm.getKind() != ElementKind.CLASS && sourceElm.getKind() != ElementKind.INTERFACE && sourceElm.getKind() != ElementKind.ENUM)) { |
| // fatal error -> return |
| return new Problem(true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ElementNotAvailable")); // NOI18N |
| } |
| |
| classHandle = ElementHandle.<TypeElement>create((TypeElement) sourceElm); |
| |
| PackageElement pkgElm = (PackageElement) javac.getElementUtilities().outermostTypeElement(sourceElm).getEnclosingElement(); |
| pkgName = pkgElm.getQualifiedName().toString(); |
| |
| // increase progress (step 1) |
| fireProgressListenerStep(); |
| |
| // all checks passed -> return null |
| return null; |
| } finally { |
| // fire operation end on the registered progress listeners |
| fireProgressListenerStop(); |
| } |
| } |
| |
| @Override |
| protected Problem checkParameters(CompilationController javac) throws IOException { |
| if (refactoring.getMethods().isEmpty() && refactoring.getFields().isEmpty() && refactoring.getImplements().isEmpty()) { |
| return new Problem(true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ExtractInterface_MembersNotAvailable")); // NOI18N); |
| } |
| // check whether the selected members are public and non-static in case of methods, static in other cases |
| // check whether all members belong to the source type |
| // XXX check if method params and return type will be accessible after extraction; likely not fatal |
| javac.toPhase(JavaSource.Phase.RESOLVED); |
| |
| TypeElement sourceType = (TypeElement) refactoring.getSourceType().resolveElement(javac); |
| assert sourceType != null; |
| |
| Set<? extends Element> members = new HashSet<Element>(sourceType.getEnclosedElements()); |
| |
| for (ElementHandle<ExecutableElement> elementHandle : refactoring.getMethods()) { |
| ExecutableElement elm = elementHandle.resolve(javac); |
| if (elm == null) { |
| return new Problem(true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ElementNotAvailable")); // NOI18N |
| } |
| if (javac.getElementUtilities().isSynthetic(elm) || elm.getKind() != ElementKind.METHOD) { |
| return new Problem(true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ExtractInterface_UnknownMember", // NOI18N |
| elm.toString())); |
| } |
| if (!members.contains(elm)) { |
| return new Problem(true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ExtractInterface_UnknownMember", // NOI18N |
| elm.toString())); |
| } |
| Set<Modifier> mods = elm.getModifiers(); |
| if (!mods.contains(Modifier.PUBLIC) || mods.contains(Modifier.STATIC)) { |
| return new Problem(true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ExtractInterface_WrongModifiers", elm.getSimpleName().toString())); // NOI18N |
| } |
| } |
| |
| for (ElementHandle<VariableElement> elementHandle : refactoring.getFields()) { |
| VariableElement elm = elementHandle.resolve(javac); |
| if (elm == null) { |
| return new Problem(true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ElementNotAvailable")); // NOI18N |
| } |
| if (javac.getElementUtilities().isSynthetic(elm) || elm.getKind() != ElementKind.FIELD) { |
| return new Problem(true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ExtractInterface_UnknownMember", // NOI18N |
| elm.toString())); |
| } |
| if (!members.contains(elm)) { |
| return new Problem(true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ExtractInterface_UnknownMember", // NOI18N |
| elm.toString())); |
| } |
| Set<Modifier> mods = elm.getModifiers(); |
| if (mods.contains(Modifier.PUBLIC) && mods.contains(Modifier.STATIC) && mods.contains(Modifier.FINAL)) { |
| VariableTree tree = (VariableTree) javac.getTrees().getTree(elm); |
| if (tree.getInitializer() != null) { |
| continue; |
| } |
| } |
| return new Problem(true, NbBundle.getMessage(ExtractInterfaceRefactoringPlugin.class, "ERR_ExtractInterface_WrongModifiers", elm.getSimpleName().toString())); // NOI18N |
| } |
| |
| // XXX check refactoring.getImplements() |
| |
| return null; |
| } |
| |
| /** |
| * Finds all type parameters of <code>javaClass</code> that are referenced by |
| * any member that is going to be extract. |
| * @param refactoring the refactoring containing members to extract |
| * @param javac compilation info |
| * @param javaClass java class declaring parameters to find |
| * @return type parameters to extract |
| */ |
| private static List<TypeMirror> findUsedGenericTypes(ExtractInterfaceRefactoring refactoring, CompilationInfo javac, TypeElement javaClass) { |
| List<TypeMirror> typeArgs = JavaRefactoringUtils.elementsToTypes(javaClass.getTypeParameters()); |
| if (typeArgs.isEmpty()) { |
| return typeArgs; |
| } |
| |
| Types typeUtils = javac.getTypes(); |
| Set<TypeMirror> used = Collections.newSetFromMap(new IdentityHashMap<TypeMirror, Boolean>()); |
| // do not check fields since static fields cannot use type parameter of the enclosing class |
| |
| // check methods |
| for (Iterator<ElementHandle<ExecutableElement>> methodIter = refactoring.getMethods().iterator(); methodIter.hasNext() && !typeArgs.isEmpty();) { |
| ElementHandle<ExecutableElement> handle = methodIter.next(); |
| ExecutableElement elm = handle.resolve(javac); |
| |
| RefactoringUtils.findUsedGenericTypes(typeUtils, typeArgs, used, elm.getReturnType()); |
| |
| for (Iterator<? extends VariableElement> paramIter = elm.getParameters().iterator(); paramIter.hasNext() && !typeArgs.isEmpty();) { |
| VariableElement param = paramIter.next(); |
| RefactoringUtils.findUsedGenericTypes(typeUtils, typeArgs, used, param.asType()); |
| } |
| } |
| |
| // check implements |
| for (Iterator<TypeMirrorHandle<TypeMirror>> it = refactoring.getImplements().iterator(); it.hasNext() && !typeArgs.isEmpty();) { |
| TypeMirrorHandle<TypeMirror> handle = it.next(); |
| TypeMirror implemetz = handle.resolve(javac); |
| RefactoringUtils.findUsedGenericTypes(typeUtils, typeArgs, used, implemetz); |
| } |
| |
| return RefactoringUtils.filterTypes(typeArgs, used); |
| } |
| |
| // --- REFACTORING ELEMENTS ------------------------------------------------ |
| |
| private final static class UpdateClassTask implements CancellableTask<WorkingCopy> { |
| private final ExtractInterfaceRefactoring refactoring; |
| private final ElementHandle<TypeElement> sourceType; |
| |
| private UpdateClassTask(ExtractInterfaceRefactoring refactoring, ElementHandle<TypeElement> sourceType) { |
| this.sourceType = sourceType; |
| this.refactoring = refactoring; |
| } |
| |
| public static void create(RefactoringElementsBag bag, FileObject fo, ExtractInterfaceRefactoring refactoring, ElementHandle<TypeElement> sourceType) throws IOException { |
| JavaSource js = JavaSource.forFileObject(fo); |
| ModificationResult modification = js.runModificationTask(new UpdateClassTask(refactoring, sourceType)); |
| List<? extends ModificationResult.Difference> diffs = modification.getDifferences(fo); |
| for (ModificationResult.Difference diff : diffs) { |
| bag.add(refactoring, DiffElement.create(diff, fo, modification)); |
| } |
| bag.registerTransaction(createTransaction(Collections.singletonList(modification))); |
| } |
| |
| @Override |
| public void cancel() { |
| } |
| |
| @Override |
| public void run(WorkingCopy wc) throws Exception { |
| wc.toPhase(JavaSource.Phase.RESOLVED); |
| createCu(wc); |
| TypeElement clazz = this.sourceType.resolve(wc); |
| assert clazz != null; |
| ClassTree classTree = wc.getTrees().getTree(clazz); |
| TreeMaker maker = wc.getTreeMaker(); |
| // fake interface since interface file does not exist yet |
| Tree interfaceTree; |
| List<TypeMirror> typeParams = findUsedGenericTypes(refactoring, wc, clazz); |
| if (typeParams.isEmpty()) { |
| interfaceTree = maker.Identifier(refactoring.getInterfaceName()); |
| } else { |
| List<ExpressionTree> typeParamTrees = new ArrayList<ExpressionTree>(typeParams.size()); |
| for (TypeMirror typeParam : typeParams) { |
| Tree t = maker.Type(typeParam); |
| typeParamTrees.add((ExpressionTree) t); |
| } |
| interfaceTree = maker.ParameterizedType( |
| maker.Identifier(refactoring.getInterfaceName()), |
| typeParamTrees |
| ); |
| } |
| |
| Set<Tree> members2Remove = new HashSet<Tree>(); |
| Set<Tree> interfaces2Remove = new HashSet<Tree>(); |
| |
| members2Remove.addAll(getFields2Remove(wc, refactoring.getFields())); |
| members2Remove.addAll(getMethods2Remove(wc, refactoring.getMethods(), clazz)); |
| interfaces2Remove.addAll(getImplements2Remove(wc, refactoring.getImplements(), clazz)); |
| |
| for (ElementHandle el : refactoring.getMethods()) { |
| ExecutableElement e = (ExecutableElement) el.resolve(wc); |
| Tree tree = wc.getTrees().getTree(e); |
| MethodTree mt = (MethodTree) tree; |
| if (e.getAnnotation(Override.class)==null) { |
| TreeMaker make = wc.getTreeMaker(); |
| AnnotationTree ann = make.Annotation(make.Identifier("Override"), Collections.<ExpressionTree>emptyList()); |
| ModifiersTree modifiers = wc.getTreeMaker().addModifiersAnnotation(mt.getModifiers(), ann); |
| wc.rewrite(mt.getModifiers(), modifiers); |
| } |
| |
| } |
| |
| // filter out obsolete members |
| List<Tree> members2Add = new ArrayList<Tree>(); |
| for (Tree tree : classTree.getMembers()) { |
| if (!members2Remove.contains(tree)) { |
| members2Add.add(tree); |
| } |
| } |
| // filter out obsolete implements trees |
| List<Tree> impls2Add = resolveImplements(classTree.getImplementsClause(), interfaces2Remove, interfaceTree); |
| |
| ClassTree nc; |
| if (clazz.getKind() == ElementKind.CLASS) { |
| nc = maker.Class( |
| classTree.getModifiers(), |
| classTree.getSimpleName(), |
| classTree.getTypeParameters(), |
| classTree.getExtendsClause(), |
| impls2Add, |
| members2Add); |
| } else if (clazz.getKind() == ElementKind.INTERFACE) { |
| nc = maker.Interface( |
| classTree.getModifiers(), |
| classTree.getSimpleName(), |
| classTree.getTypeParameters(), |
| impls2Add, |
| members2Add); |
| } else if (clazz.getKind() == ElementKind.ENUM) { |
| nc = maker.Enum( |
| classTree.getModifiers(), |
| classTree.getSimpleName(), |
| impls2Add, |
| members2Add); |
| } else { |
| throw new IllegalStateException(classTree.toString()); |
| } |
| |
| wc.rewrite(classTree, nc); |
| } |
| |
| private List<Tree> getFields2Remove(CompilationInfo javac, List<ElementHandle<VariableElement>> members) { |
| if (members.isEmpty()) { |
| return Collections.<Tree>emptyList(); |
| } |
| List<Tree> result = new ArrayList<Tree>(members.size()); |
| for (ElementHandle<VariableElement> handle : members) { |
| VariableElement elm = handle.resolve(javac); |
| assert elm != null; |
| Tree t = javac.getTrees().getTree(elm); |
| assert t != null; |
| result.add(t); |
| } |
| |
| return result; |
| } |
| |
| private List<Tree> getMethods2Remove(CompilationInfo javac, List<ElementHandle<ExecutableElement>> members, TypeElement clazz) { |
| if (members.isEmpty()) { |
| return Collections.<Tree>emptyList(); |
| } |
| boolean isInterface = clazz.getKind() == ElementKind.INTERFACE; |
| List<Tree> result = new ArrayList<Tree>(members.size()); |
| for (ElementHandle<ExecutableElement> handle : members) { |
| ExecutableElement elm = handle.resolve(javac); |
| assert elm != null; |
| |
| |
| if (isInterface || elm.getModifiers().contains(Modifier.ABSTRACT)) { |
| // it is interface method nor abstract method |
| Tree t = javac.getTrees().getTree(elm); |
| assert t != null; |
| result.add(t); |
| } |
| } |
| |
| return result; |
| } |
| |
| private List<Tree> getImplements2Remove(CompilationInfo javac, List<TypeMirrorHandle<TypeMirror>> members, TypeElement clazz) { |
| if (members.isEmpty()) { |
| return Collections.<Tree>emptyList(); |
| } |
| |
| // resolve members to remove |
| List<TypeMirror> memberTypes = new ArrayList<TypeMirror>(members.size()); |
| for (TypeMirrorHandle<TypeMirror> handle : members) { |
| TypeMirror tm = handle.resolve(javac); |
| memberTypes.add(tm); |
| } |
| |
| |
| ClassTree classTree = javac.getTrees().getTree(clazz); |
| List<Tree> result = new ArrayList<Tree>(); |
| Types types = javac.getTypes(); |
| |
| // map TypeMirror to Tree |
| for (Tree tree : classTree.getImplementsClause()) { |
| TreePath path = javac.getTrees().getPath(javac.getCompilationUnit(), tree); |
| TypeMirror existingTM = javac.getTrees().getTypeMirror(path); |
| |
| for (TypeMirror tm : memberTypes) { |
| if (types.isSameType(tm, existingTM)) { |
| result.add(tree); |
| break; |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| private static List<Tree> resolveImplements(List<? extends Tree> allImpls, Set<Tree> impls2Remove, Tree impl2Add) { |
| List<Tree> ret; |
| if (allImpls == null) { |
| ret = new ArrayList<Tree>(1); |
| } else { |
| ret = new ArrayList<Tree>(allImpls.size() + 1); |
| ret.addAll(allImpls); |
| } |
| |
| if (impls2Remove != null && !impls2Remove.isEmpty()) { |
| ret.removeAll(impls2Remove); |
| } |
| ret.add(impl2Add); |
| return ret; |
| } |
| |
| public void createCu(WorkingCopy wc) throws Exception { |
| wc.toPhase(JavaSource.Phase.RESOLVED); |
| TreeMaker make = wc.getTreeMaker(); |
| GeneratorUtilities genUtils = GeneratorUtilities.get(wc); |
| |
| // add type parameters |
| List<TypeMirror> typeParams = findUsedGenericTypes(refactoring, wc, sourceType.resolve(wc)); |
| List<TypeParameterTree> newTypeParams = new ArrayList<TypeParameterTree>(typeParams.size()); |
| // lets retrieve param type trees from origin class since it is |
| // almost impossible to create them via TreeMaker |
| TypeElement sourceTypeElm = sourceType.resolve(wc); |
| for (TypeParameterElement typeParam : sourceTypeElm.getTypeParameters()) { |
| TypeMirror origParam = typeParam.asType(); |
| for (TypeMirror newParam : typeParams) { |
| if (wc.getTypes().isSameType(origParam, newParam)) { |
| Tree t = wc.getTrees().getTree(typeParam); |
| if (t.getKind() == Tree.Kind.TYPE_PARAMETER) { |
| TypeParameterTree typeParamTree = (TypeParameterTree) t; |
| if (!typeParamTree.getBounds().isEmpty()) { |
| typeParamTree = (TypeParameterTree) genUtils.importFQNs(t); |
| } |
| newTypeParams.add(typeParamTree); |
| } |
| } |
| } |
| |
| } |
| |
| // add new fields |
| List<Tree> members = new ArrayList<Tree>(); |
| for (ElementHandle<VariableElement> handle : refactoring.getFields()) { |
| VariableElement memberElm = handle.resolve(wc); |
| VariableTree tree = (VariableTree) wc.getTrees().getTree(memberElm); |
| VariableTree newVarTree = make.Variable( |
| make.Modifiers(Collections.<Modifier>emptySet(), tree.getModifiers().getAnnotations()), |
| tree.getName(), |
| tree.getType(), |
| tree.getInitializer()); |
| newVarTree = genUtils.importFQNs(newVarTree); |
| tree = genUtils.importComments(tree, wc.getTrees().getPath(memberElm).getCompilationUnit()); |
| genUtils.copyComments(tree, newVarTree, false); |
| genUtils.copyComments(tree, newVarTree, true); |
| members.add(newVarTree); |
| } |
| // add newmethods |
| for (ElementHandle<ExecutableElement> handle : refactoring.getMethods()) { |
| ExecutableElement memberElm = handle.resolve(wc); |
| TreePath mpath = wc.getTrees().getPath(memberElm); |
| MethodTree tree = wc.getTrees().getTree(memberElm); |
| List<? extends AnnotationTree> annotations = |
| filterOutOverrideAnnotation(tree.getModifiers().getAnnotations(), wc, mpath); |
| MethodTree newMethodTree = make.Method( |
| make.Modifiers(Collections.<Modifier>emptySet(), annotations), |
| tree.getName(), |
| tree.getReturnType(), |
| tree.getTypeParameters(), |
| tree.getParameters(), |
| tree.getThrows(), |
| (BlockTree) null, |
| null); |
| newMethodTree = genUtils.importFQNs(newMethodTree); |
| tree = genUtils.importComments(tree, wc.getTrees().getPath(memberElm).getCompilationUnit()); |
| genUtils.copyComments(tree, newMethodTree, false); |
| genUtils.copyComments(tree, newMethodTree, true); |
| members.add(newMethodTree); |
| } |
| // add super interfaces |
| List <Tree> extendsList = new ArrayList<Tree>(); |
| for (TypeMirrorHandle<? extends TypeMirror> handle : refactoring.getImplements()) { |
| // XXX check if interface is not aready there; the templates might be changed by user :-( |
| TypeMirror implMirror = handle.resolve(wc); |
| extendsList.add(make.Type(implMirror)); |
| } |
| // create new interface |
| ClassTree newInterfaceTree = make.Interface( |
| make.Modifiers(EnumSet.of(Modifier.PUBLIC)), |
| refactoring.getInterfaceName(), |
| newTypeParams, |
| extendsList, |
| Collections.<Tree>emptyList()); |
| |
| newInterfaceTree = genUtils.insertClassMembers(newInterfaceTree, members); |
| |
| FileObject fileObject = refactoring.getSourceType().getFileObject(); |
| FileObject sourceRoot = ClassPath.getClassPath(fileObject, ClassPath.SOURCE).findOwnerRoot(fileObject); |
| String relativePath = FileUtil.getRelativePath(sourceRoot, fileObject.getParent()) + "/" + refactoring.getInterfaceName() + ".java"; |
| |
| CompilationUnitTree cu = JavaPluginUtils.createCompilationUnit(sourceRoot, relativePath, newInterfaceTree, wc, make); |
| wc.rewrite(null, cu); |
| } |
| |
| // --- helper methods ---------------------------------- |
| private static List<? extends AnnotationTree> filterOutOverrideAnnotation(List<? extends AnnotationTree> annotations, CompilationInfo javac, TreePath pathToMethod) { |
| if (annotations.isEmpty()) { |
| return annotations; |
| } |
| List<AnnotationTree> newAnnotations = new ArrayList<AnnotationTree>(annotations.size()); |
| TypeElement overrideAnn = javac.getElements().getTypeElement("java.lang.Override"); // NOI18N |
| for (AnnotationTree annotationTree : annotations) { |
| Element annotation = javac.getTrees().getElement(new TreePath(pathToMethod, annotationTree)); |
| if (annotation == null || annotation != overrideAnn) { |
| newAnnotations.add(annotationTree); |
| } |
| } |
| return newAnnotations; |
| } |
| } |
| |
| } |