# HG changeset patch # Parent 15d78eb9f5b2222834480df2d8ae01129b629635 # User Ralph Benjamin Ruijs [no commit message] diff --git a/java.source/apichanges.xml b/java.source/apichanges.xml --- a/java.source/apichanges.xml +++ b/java.source/apichanges.xml @@ -108,6 +108,20 @@ + + + Added GeneratorUtilities.createFromTemplate. + + + + + + Added the method createFromTemplate to class GeneratorUtilities, + which will create a new CompilationUnitTree from a template. + + + + Added GeneratorUtilities.appendToAnnotationValue. diff --git a/java.source/src/org/netbeans/api/java/source/AssignComments.java b/java.source/src/org/netbeans/api/java/source/AssignComments.java --- a/java.source/src/org/netbeans/api/java/source/AssignComments.java +++ b/java.source/src/org/netbeans/api/java/source/AssignComments.java @@ -106,7 +106,7 @@ boolean oldMapComments = mapComments; try { mapComments |= tree == commentMapTarget; - if ((commentMapTarget != null) && info.getTreeUtilities().isSynthetic(new TreePath(new TreePath(info.getCompilationUnit()), tree))) + if ((commentMapTarget != null) && info.getTreeUtilities().isSynthetic(new TreePath(new TreePath(unit), tree))) return null; if (commentMapTarget != null) { mapComments2(tree, true); diff --git a/java.source/src/org/netbeans/api/java/source/GeneratorUtilities.java b/java.source/src/org/netbeans/api/java/source/GeneratorUtilities.java --- a/java.source/src/org/netbeans/api/java/source/GeneratorUtilities.java +++ b/java.source/src/org/netbeans/api/java/source/GeneratorUtilities.java @@ -120,6 +120,7 @@ import javax.lang.model.util.Elements; import javax.swing.text.Document; import javax.swing.text.JTextComponent; +import javax.tools.JavaFileObject; import org.netbeans.api.editor.EditorRegistry; import org.netbeans.api.java.lexer.JavaTokenId; @@ -127,10 +128,13 @@ import org.netbeans.editor.GuardedDocument; import org.netbeans.modules.java.source.builder.CommentHandlerService; import org.netbeans.modules.java.source.builder.CommentSetImpl; +import org.netbeans.modules.java.source.parsing.FileObjects; import org.netbeans.modules.java.source.parsing.SourceFileObject; import org.netbeans.modules.java.source.query.CommentSet.RelativePosition; import org.netbeans.modules.java.source.save.DiffContext; import org.openide.cookies.EditorCookie; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; import org.openide.loaders.DataObject; import org.openide.util.Exceptions; @@ -159,6 +163,32 @@ } /** + * Create a new CompilationUnitTree from a template. + * + * @param sourceRoot a source root under which the new file is created + * @param path a relative path to file separated by '/' + * @param kind the kind of Element to use for the template, can be null or + * CLASS, INTERFACE, ANNOTATION_TYPE, ENUM, PACKAGE + * @return new CompilationUnitTree created from a template + * @throws IOException when an exception occurs while creating the template + * @since 0.100 + */ + public CompilationUnitTree createFromTemplate(FileObject sourceRoot, String path, ElementKind kind) throws IOException { + String[] nameComponent = FileObjects.getFolderAndBaseName(path, '/'); + JavaFileObject sourceFile = FileObjects.templateFileObject(sourceRoot, nameComponent[0], nameComponent[1]); + FileObject template = FileUtil.getConfigFile(copy.template(kind)); + FileObject targetFile = copy.doCreateFromTemplate(template, sourceFile); + CompilationUnitTree templateCUT = copy.impl.getJavacTask().parse(FileObjects.nbFileObject(targetFile, targetFile.getParent())).iterator().next(); + CompilationUnitTree importComments = GeneratorUtilities.get(copy).importComments(templateCUT, templateCUT); + CompilationUnitTree result = copy.getTreeMaker().CompilationUnit(importComments.getPackageAnnotations(), + sourceRoot, + path, + importComments.getImports(), + importComments.getTypeDecls()); + return result; + } + + /** * Inserts a member to a class. Using the rules specified in the {@link CodeStyle} * it finds the proper place for the member and calls {@link TreeMaker.insertClassMember} * diff --git a/java.source/src/org/netbeans/api/java/source/WorkingCopy.java b/java.source/src/org/netbeans/api/java/source/WorkingCopy.java --- a/java.source/src/org/netbeans/api/java/source/WorkingCopy.java +++ b/java.source/src/org/netbeans/api/java/source/WorkingCopy.java @@ -74,6 +74,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; import javax.swing.text.BadLocationException; import javax.tools.JavaFileObject; @@ -550,8 +551,9 @@ try { FileObject targetFile = doCreateFromTemplate(t); CompilationUnitTree templateCUT = impl.getJavacTask().parse(FileObjects.nbFileObject(targetFile, targetFile.getParent())).iterator().next(); + CompilationUnitTree importComments = GeneratorUtilities.get(this).importComments(templateCUT, templateCUT); - changes.put(templateCUT, t); + changes.put(importComments, t); StringWriter target = new StringWriter(); @@ -568,26 +570,54 @@ return result; } - private static String template(CompilationUnitTree cut) { - if ("package-info.java".equals(cut.getSourceFile().getName())) return "Templates/Classes/package-info.java"; - if (cut.getTypeDecls().isEmpty()) return "Templates/Classes/Empty.java"; - - switch (cut.getTypeDecls().get(0).getKind()) { + String template(ElementKind kind) { + if(kind == null) { + return "Templates/Classes/Empty.java"; // NOI18N + } + switch (kind) { case CLASS: return "Templates/Classes/Class.java"; // NOI18N case INTERFACE: return "Templates/Classes/Interface.java"; // NOI18N case ANNOTATION_TYPE: return "Templates/Classes/AnnotationType.java"; // NOI18N case ENUM: return "Templates/Classes/Enum.java"; // NOI18N + case PACKAGE: return "Templates/Classes/package-info.java"; // NOI18N default: - Logger.getLogger(WorkingCopy.class.getName()).log(Level.SEVERE, "Cannot resolve template for {0}", cut.getTypeDecls().get(0).getKind()); - return "Templates/Classes/Empty.java"; + Logger.getLogger(WorkingCopy.class.getName()).log(Level.SEVERE, "Cannot resolve template for {0}", kind); + return "Templates/Classes/Empty.java"; // NOI18N } } - private static FileObject doCreateFromTemplate(CompilationUnitTree t) throws IOException { + FileObject doCreateFromTemplate(CompilationUnitTree cut) throws IOException { + ElementKind kind; + if ("package-info.java".equals(cut.getSourceFile().getName())) { + kind = ElementKind.PACKAGE; + } else if (cut.getTypeDecls().isEmpty()) { + kind = null; + } else { + switch (cut.getTypeDecls().get(0).getKind()) { + case CLASS: + kind = ElementKind.CLASS; + break; + case INTERFACE: + kind = ElementKind.INTERFACE; + break; + case ANNOTATION_TYPE: + kind = ElementKind.ANNOTATION_TYPE; + break; + case ENUM: + kind = ElementKind.ENUM; + break; + default: + Logger.getLogger(WorkingCopy.class.getName()).log(Level.SEVERE, "Cannot resolve template for {0}", cut.getTypeDecls().get(0).getKind()); + kind = null; + } + } + FileObject template = FileUtil.getConfigFile(template(kind)); + return doCreateFromTemplate(template, cut.getSourceFile()); + } + + FileObject doCreateFromTemplate(FileObject template, JavaFileObject sourceFile) throws IOException { FileObject scratchFolder = FileUtil.createMemoryFileSystem().getRoot(); - FileObject template = FileUtil.getConfigFile(template(t)); - if (template == null) { return scratchFolder.createData("out", "java"); } @@ -598,7 +628,7 @@ return scratchFolder.createData("out", "java"); } - File pack = new File(t.getSourceFile().toUri()).getParentFile(); + File pack = new File(sourceFile.toUri()).getParentFile(); while (FileUtil.toFileObject(pack) == null) { pack = pack.getParentFile(); diff --git a/java.source/src/org/netbeans/modules/java/source/parsing/FileObjects.java b/java.source/src/org/netbeans/modules/java/source/parsing/FileObjects.java --- a/java.source/src/org/netbeans/modules/java/source/parsing/FileObjects.java +++ b/java.source/src/org/netbeans/modules/java/source/parsing/FileObjects.java @@ -1056,6 +1056,10 @@ assert parentFo != null; DataFolder target = DataFolder.findFolder(parentFo); FileObject template = FileUtil.getConfigFile("Templates/Classes/Empty.java"); //NOI18N + if(template == null) { + FileUtil.createData(parentFo, f.getName()); + return; + } DataObject templateDobj = DataObject.find(template); String simpleName = FileObjects.stripExtension(f.getName()); DataObject newDobj = templateDobj.createFromTemplate(target, simpleName); diff --git a/java.source/test/unit/src/org/netbeans/api/java/source/gen/CompilationUnitTest.java b/java.source/test/unit/src/org/netbeans/api/java/source/gen/CompilationUnitTest.java --- a/java.source/test/unit/src/org/netbeans/api/java/source/gen/CompilationUnitTest.java +++ b/java.source/test/unit/src/org/netbeans/api/java/source/gen/CompilationUnitTest.java @@ -39,6 +39,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.Map; +import javax.lang.model.element.ElementKind; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeKind; @@ -85,9 +86,151 @@ @Override protected void setUp() throws Exception { super.setUp(); - FileObject templates = FileUtil.getConfigFile("Templates/Classes/Class.java"); + FileObject template = FileUtil.getConfigFile("Templates/Classes/Class.java"); + if (template != null) template.delete(); + FileObject template2 = FileUtil.getConfigFile("Templates/Classes/package-info.java"); + if (template2 != null) template2.delete(); + } - if (templates != null) templates.delete(); + public void testNewCompilationUnitFromTemplate() throws Exception { + testFile = new File(getWorkDir(), "Test.java"); + + File fakeFile = new File(getWorkDir(), "Fake.java"); + FileObject fakeFO = FileUtil.createData(fakeFile); + + FileObject emptyJava = FileUtil.createData(FileUtil.getConfigRoot(), "Templates/Classes/Empty.java"); + emptyJava.setAttribute("template", Boolean.TRUE); + + FileObject classJava = FileUtil.createData(FileUtil.getConfigRoot(), "Templates/Classes/Class.java"); + classJava.setAttribute("template", Boolean.TRUE); + classJava.setAttribute("verbatim-create-from-template", Boolean.TRUE); + Writer w = new OutputStreamWriter(classJava.getOutputStream(), "UTF-8"); + w.write("/*\n * License\n */\npackage zoo;\n\n/**\n * trida\n */\npublic class Template {\n}"); + w.close(); + + FileObject packageJava = FileUtil.createData(FileUtil.getConfigRoot(), "Templates/Classes/package-info.java"); + packageJava.setAttribute("template", Boolean.TRUE); + packageJava.setAttribute("verbatim-create-from-template", Boolean.TRUE); + Writer w2 = new OutputStreamWriter(packageJava.getOutputStream(), "UTF-8"); + w2.write("/*\n * License\n */\npackage zoo;\n"); + w2.close(); + + FileObject testSourceFO = FileUtil.createData(testFile); assertNotNull(testSourceFO); + ClassPath sourcePath = ClassPath.getClassPath(testSourceFO, ClassPath.SOURCE); assertNotNull(sourcePath); + FileObject[] roots = sourcePath.getRoots(); assertEquals(1, roots.length); + final FileObject sourceRoot = roots[0]; assertNotNull(sourceRoot); + ClassPath compilePath = ClassPath.getClassPath(testSourceFO, ClassPath.COMPILE); assertNotNull(compilePath); + ClassPath bootPath = ClassPath.getClassPath(testSourceFO, ClassPath.BOOT); assertNotNull(bootPath); + ClasspathInfo cpInfo = ClasspathInfo.create(bootPath, compilePath, sourcePath); + JavaSource javaSource = JavaSource.create(cpInfo, fakeFO); + + Task task = new Task() { + + public void cancel() { + } + + public void run(WorkingCopy workingCopy) throws Exception { + workingCopy.toPhase(JavaSource.Phase.PARSED); + TreeMaker make = workingCopy.getTreeMaker(); + String path = "zoo/Krtek.java"; + GeneratorUtilities genUtils = GeneratorUtilities.get(workingCopy); + CompilationUnitTree newTree = genUtils.createFromTemplate(sourceRoot, path, ElementKind.CLASS); + MethodTree nju = make.Method( + make.Modifiers(Collections.emptySet()), + "m", + make.PrimitiveType(TypeKind.VOID), // return type - void + Collections.emptyList(), + Collections.emptyList(), + Collections.emptyList(), + make.Block(Collections.emptyList(), false), + null // default value - not applicable + ); + ClassTree clazz = make.Class( + make.Modifiers(Collections.singleton(Modifier.PUBLIC)), + "Krtek", + Collections.emptyList(), + null, + Collections.emptyList(), + Collections.singletonList(nju) + ); + if(newTree.getTypeDecls().isEmpty()) { + newTree = make.addCompUnitTypeDecl(newTree, clazz); + } else { + Tree templateClass = newTree.getTypeDecls().get(0); + genUtils.copyComments(templateClass, clazz, true); + genUtils.copyComments(templateClass, clazz, false); + newTree = make.removeCompUnitTypeDecl(newTree, 0); + newTree = make.insertCompUnitTypeDecl(newTree, 0, clazz); + } + workingCopy.rewrite(null, newTree); + + String packagePath = "zoo/package-info.java"; + CompilationUnitTree newPackageTree = genUtils.createFromTemplate(sourceRoot, packagePath, ElementKind.PACKAGE); + workingCopy.rewrite(null, newPackageTree); + } + }; + ModificationResult result = javaSource.runModificationTask(task); + result.commit(); + + String goldenClass = + "/*\n * License\n */\n" + + "package zoo;\n" + + "\n" + + "/**\n * trida\n */\n" + + "public class Krtek {\n" + + "\n" + + " void m() {\n" + + " }\n" + + "}"; + String res = TestUtilities.copyFileToString(new File(getDataDir().getAbsolutePath() + "/zoo/Krtek.java")); + assertEquals(goldenClass, res); + + String goldenPackage = + "/*\n * License\n */\n" + + "package zoo;\n"; + res = TestUtilities.copyFileToString(new File(getDataDir().getAbsolutePath() + "/zoo/package-info.java")); + assertEquals(goldenPackage, res); + } + + public void testNewCompilationUnitFromNonExistingTemplate() throws Exception { + testFile = new File(getWorkDir(), "Test.java"); + + File fakeFile = new File(getWorkDir(), "Fake.java"); + FileObject fakeFO = FileUtil.createData(fakeFile); + + FileObject template = FileUtil.getConfigFile("Templates/Classes/Class.java"); + if (template != null) template.delete(); + template = FileUtil.getConfigFile("Templates/Classes/Empty.java"); + if(template != null) template.delete(); + + FileObject testSourceFO = FileUtil.createData(testFile); assertNotNull(testSourceFO); + ClassPath sourcePath = ClassPath.getClassPath(testSourceFO, ClassPath.SOURCE); assertNotNull(sourcePath); + FileObject[] roots = sourcePath.getRoots(); assertEquals(1, roots.length); + final FileObject sourceRoot = roots[0]; assertNotNull(sourceRoot); + ClassPath compilePath = ClassPath.getClassPath(testSourceFO, ClassPath.COMPILE); assertNotNull(compilePath); + ClassPath bootPath = ClassPath.getClassPath(testSourceFO, ClassPath.BOOT); assertNotNull(bootPath); + ClasspathInfo cpInfo = ClasspathInfo.create(bootPath, compilePath, sourcePath); + JavaSource javaSource = JavaSource.create(cpInfo, fakeFO); + + Task task = new Task() { + + public void cancel() { + } + + public void run(WorkingCopy workingCopy) throws Exception { + workingCopy.toPhase(JavaSource.Phase.PARSED); + TreeMaker make = workingCopy.getTreeMaker(); + String path = "zoo/Krtek.java"; + GeneratorUtilities genUtils = GeneratorUtilities.get(workingCopy); + CompilationUnitTree newTree = genUtils.createFromTemplate(sourceRoot, path, ElementKind.CLASS); + workingCopy.rewrite(null, newTree); + } + }; + ModificationResult result = javaSource.runModificationTask(task); + result.commit(); + + String res = TestUtilities.copyFileToString(new File(getDataDir().getAbsolutePath() + "/zoo/Krtek.java")); + assertEquals(res, "package zoo;\n\n"); } public void testNewCompilationUnit() throws Exception {