1/* 2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24import java.io.File; 25import java.io.IOException; 26import java.net.URI; 27import java.net.URISyntaxException; 28import java.util.Arrays; 29import java.util.Iterator; 30 31import javax.tools.Diagnostic; 32import javax.tools.DiagnosticCollector; 33import javax.tools.JavaCompiler; 34import javax.tools.JavaCompiler.CompilationTask; 35import javax.tools.JavaFileObject; 36import javax.tools.SimpleJavaFileObject; 37import javax.tools.StandardJavaFileManager; 38import javax.tools.StandardLocation; 39import javax.tools.ToolProvider; 40 41import com.sun.source.util.JavacTask; 42 43public class Helper { 44 45 enum ContentVars { 46 47 IMPORTCONTAINERSTMTS("\nimport java.lang.annotation.Repeatable;\n"), 48 IMPORTDEPRECATED("import java.lang.Deprecated;\n"), 49 IMPORTDOCUMENTED("import java.lang.annotation.Documented;\n"), 50 IMPORTINHERITED("import java.lang.annotation.Inherited;\n"), 51 IMPORTRETENTION("import java.lang.annotation.Retention;\n" 52 + "\nimport java.lang.annotation.RetentionPolicy;\n"), 53 IMPORTSTMTS("import java.lang.annotation.*;\n"), 54 IMPORTEXPECTED("import expectedFiles.*;\n"), 55 REPEATABLE("\n@Repeatable(FooContainer.class)\n"), 56 CONTAINER("@interface FooContainer {\n" + " Foo[] value();\n}\n"), 57 BASE("@interface Foo {int value() default Integer.MAX_VALUE;}\n"), 58 BASEANNO("@Foo(0)"), 59 LEGACYCONTAINER("@FooContainer(value = {@Foo(1), @Foo(2)})\n"), 60 REPEATABLEANNO("\n@Foo(1) @Foo(2)"), 61 DEPRECATED("\n@Deprecated"), 62 DOCUMENTED("\n@Documented"), 63 INHERITED("\n@Inherited"), 64 TARGET("\n@Target(#VAL)\n"), 65 RETENTION("@Retention(RetentionPolicy.#VAL)\n"), 66 RETENTIONRUNTIME("@Retention(RetentionPolicy.RUNTIME)\n"); 67 private String val; 68 69 private ContentVars(String val) { 70 this.val = val; 71 } 72 73 public String getVal() { 74 return val; 75 } 76 } 77 78 // Create and compile FileObject using values for className and contents 79 public static boolean compileCode(String className, String contents, 80 DiagnosticCollector<JavaFileObject> diagnostics) { 81 boolean ok = false; 82 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 83 if (compiler == null) { 84 throw new RuntimeException("can't get javax.tools.JavaCompiler!"); 85 } 86 87 JavaFileObject file = getFile(className, contents); 88 Iterable<? extends JavaFileObject> compilationUnit = Arrays.asList(file); 89 90 CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnit); 91 ok = task.call(); 92 return ok; 93 } 94 // Compile a list of FileObjects 95 // Used when packages are needed and classes need to be loaded at runtime 96 static File destDir = new File(System.getProperty("user.dir")); 97 98 public static boolean compileCode(DiagnosticCollector<JavaFileObject> diagnostics, Iterable<? extends JavaFileObject> files) { 99 boolean ok = false; 100 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 101 if (compiler == null) { 102 throw new RuntimeException("can't get javax.tools.JavaCompiler!"); 103 } 104 105 try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) { 106 // Assuming filesCount can maximum be 2 and if true, one file is package-info.java 107 if (isPkgInfoPresent(files)) { 108 JavacTask task = (JavacTask) compiler.getTask(null, fm, diagnostics, null, null, files); 109 try { 110 fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir)); 111 task.generate(); 112 } catch (IOException ioe) { 113 throw new RuntimeException("Compilation failed for package level tests", ioe); 114 } 115 int err = 0; 116 for (Diagnostic<? extends JavaFileObject> d : diagnostics.getDiagnostics()) { 117 if(d.getKind() == Diagnostic.Kind.ERROR) { 118 err++; 119 } 120 } 121 ok = (err == 0); 122 } else { 123 CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, files); 124 ok = task.call(); 125 } 126 return ok; 127 } catch (IOException e) { 128 throw new Error(e); 129 } 130 } 131 132 static private boolean isPkgInfoPresent(Iterable<? extends JavaFileObject> files) { 133 Iterator<? extends JavaFileObject> itr = files.iterator(); 134 while (itr.hasNext()) { 135 String name = itr.next().getName(); 136 if (name.contains("package-info")) { 137 return true; 138 } 139 } 140 return false; 141 } 142 /* String template where /*<TYPE>*/ /*gets replaced by repeating anno 143 * Used to generate test src for combo tests 144 * - BasicSyntaxCombo.java 145 * - TargetAnnoCombo.java 146 */ 147 148 public static final String template = 149 "/*PACKAGE*/\n" 150 + "//pkg test;\n\n" 151 + "/*ANNODATA*/\n" // import statements, declaration of Foo/FooContainer 152 + "/*TYPE*/ //class\n" 153 + "class #ClassName {\n" 154 + " /*FIELD*/ //instance var\n" 155 + " public int x = 0;\n\n" 156 + " /*FIELD*/ //Enum constants\n" 157 + " TestEnum testEnum;\n\n" 158 + " /*FIELD*/ // Static field\n" 159 + " public static int num;\n\n" 160 + " /*STATIC_INI*/\n" 161 + " static { \n" + "num = 10; \n }\n\n" 162 + " /*CONSTRUCTOR*/\n" 163 + " #ClassName() {}\n\n" 164 + " /*INSTANCE_INI*/\n" 165 + " { \n x = 10; \n }" 166 + " /*INNER_CLASS*/\n" 167 + " class innerClass {}\n" 168 + " /*METHOD*/\n" 169 + " void bar(/*PARAMETER*/ int baz) {\n" 170 + " /*LOCAL_VARIABLE*/\n" 171 + " int y = 0;\n" 172 + " }\n" 173 + "}\n\n" 174 + "/*TYPE*/ //Enum\n" 175 + "enum TestEnum {}\n\n" 176 + "/*TYPE*/ //Interface\n" 177 + "interface TestInterface {}\n\n" 178 + "/*TYPE*/\n" 179 + "/*ANNOTATION_TYPE*/\n" 180 + "@interface TestAnnotationType{}\n" 181 + "class TestPkg {}\n" 182 + "class TestTypeAnno </*TYPE_PARAMETER*/ T extends Object> {\n" 183 + " String /*TYPE_USE*/[] arr;\n" 184 + "}"; 185 186 static JavaFileObject getFile(String name, String code) { 187 JavaFileObject o = null; 188 try { 189 o = new JavaStringFileObject(name, code); 190 } catch (URISyntaxException e) { 191 throw new RuntimeException(e); 192 } 193 return o; 194 } 195 196 static class JavaStringFileObject extends SimpleJavaFileObject { 197 198 final String theCode; 199 200 public JavaStringFileObject(String fileName, String theCode) throws URISyntaxException { 201 super(new URI("string:///" + fileName.replace('.', '/') + ".java"), Kind.SOURCE); 202 this.theCode = theCode; 203 } 204 205 @Override 206 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 207 return theCode; 208 } 209 } 210} 211