/* * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * @bug 8013497 * @summary Utility class for constructing, compiling and execute code * @author Charlie Wang */ import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.JavaFileObject.Kind; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import javax.tools.ToolProvider; import com.sun.source.util.JavacTask; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedType; import java.lang.reflect.AnnotatedArrayType; import java.lang.reflect.Method; import java.util.Collections; import java.util.Map; /** * Helper provides below features for annotation test: * 1. Code construction - SrcType * SrcType contains all parts of source code needed to construct a class * for annotation test. In each enum's getSrc(), it supports to replace [#ANNO] * and [TYPE] AND [NAME], which is usually all the elements needed to construct * a small snippet like package, class, method, field etc. * 2. Code compile and load * compilecode() and loadClass compiles test code and then load it to * memory. All users need to do is to construct a class code, send it to Helper, * then they would get a class object of the test object which is enough for * annotation test. */ public class Helper { // Set it to true to get more debug information static final boolean DEBUG = true; public enum Declaration implements DeclarationGenerator { PACKAGE_INFO("[#ANNO] \npackage #NAME; \n"), PACKAGE("\npackage #NAME; \n"), IMPORT("\nimport java.io.*;\n" + "import java.util.*;\n" + "import java.lang.*;\n" + "import java.lang.reflect.*;\n" + "import java.lang.annotation.*;\n") { public String getSrc(String... annoStr) { if (null == annoStr) { return template; } else if (0 == annoStr.length) { return ""; } else if (1 == annoStr.length) { return annoStr[0]; } else { throw new RuntimeException("illegal input for declaration!"); } } }, CLASS("\n[#ANNO] \nclass #NAME"), INTERFACE("\n[#ANNO] \ninterface #NAME"), EXTENDS(" extends [#ANNO] #NAME"), IMPLEMENTS(" implements [[#ANNO] #NAME, ]") { public String getSrc(String... annoStr) { return IMPLEMENTS.replaceMultipleAnnoStr(annoStr); } }, GENERICS1("<[[#ANNO1] #TYPE1 [#INHERITANCE [#ANNO2] #TYPE2], ]>") { // input should be like ["@realanno1 Type1 //extends @realanno2 Type2", "@realanno3 Type3 //super @realanno4 Type4"] public String getSrc(String... annoStr) { if (null == annoStr || 0 == annoStr.length) { return ""; } String temp = template; for (String as : annoStr) { temp = temp.replaceAll("\\[\\[#ANNO1\\] #TYPE1 " + "\\[#INHERITANCE \\[#ANNO2\\] #TYPE2\\], \\]", "[#ANNO1] #TYPE1 [#INHERITANCE [#ANNO2] #TYPE2], " + "[[#TMP_ANNO1] #TMP_TYPE1 [#TMP_INHERITANCE " + "[#TMP_ANNO2] #TMP_TYPE2], ]"); int j = 0; // index of ) String ss = as.trim(); // put @anno to [#ANNO1] String[] sa = GENERICS1.replaceAnnoStr(ss, temp, "\\[#ANNO1\\]", " [#ANNO1]"); ss = sa[0]; temp = sa[1]; // get #TYPE1 if (0 == ss.length()) { throw new RuntimeException("illegal generics1."); } j = ss.indexOf(" "); String type = (j == -1 ? ss : ss.substring(0, j)); temp = temp.replaceFirst("#TYPE1", type); if (-1 != j) { ss = ss.substring(j).trim(); } // get #INHERITANCE if (ss.startsWith("extends") || ss.startsWith("super")) { temp = temp.replaceAll("\\[#INHERITANCE " + "\\[#ANNO2\\] #TYPE2\\]", "#INHERITANCE \\[#ANNO2\\] #TYPE2"); j = ss.indexOf(" "); if (-1 == j) { throw new RuntimeException("illegal generics1."); } String inheritance = ss.substring(0, j); temp = temp.replaceFirst("#INHERITANCE", inheritance); ss = ss.substring(j).trim(); // put @anno to [#ANNO2] sa = GENERICS1.replaceAnnoStr(ss, temp, "\\[#ANNO2\\]", " [#ANNO2]"); ss = sa[0]; temp = sa[1]; // get #TYPE2 if (0 == ss.length() || -1 < ss.indexOf(" ")) { throw new RuntimeException("illegal generics1."); } type = ss; temp = temp.replaceFirst("#TYPE2", type); } else { temp = temp.replaceAll("\\[#INHERITANCE \\[#ANNO2\\] " + "#TYPE2\\]", ""); } temp = temp.replaceAll("TMP_", ""); } return temp.replaceAll(", \\[\\[#ANNO1\\] #TYPE1 " + "\\[#INHERITANCE \\[#ANNO2\\] #TYPE2\\], \\]", ""); } }, GENERICS2("<[[#ANNO1] #TYPE1 " + "extends [#ANNO2] #TYPE2 & [#ANNO3] #TYPE3, ]>") { // input should be like ["@realanno1 Type1 // @realanno2 Type2" "@realanno3 Type3] public String getSrc(String... annoStr) { if (null == annoStr || 0 == annoStr.length) { return ""; } String temp = template; for (String as : annoStr) { temp = temp.replaceAll("\\[\\[#ANNO1\\] #TYPE1 " + "extends \\[#ANNO2\\] #TYPE2 " + "& \\[#ANNO3\\] #TYPE3, \\]", "[#ANNO1\\] #TYPE1 extends \\[#ANNO2\\] #TYPE2 " + "& \\[#ANNO3\\] #TYPE3, " + "\\[\\[#TMP_ANNO1\\] #TTMP_YPE1 " + "extends \\[#TMP_ANNO2\\] #TMP_TYPE2 " + "& \\[#TMP_ANNO3\\] #TMP_TYPE3, \\]"); int j = 0; String ss = as.trim(); // put @anno to [#ANNO1] String[] sa = GENERICS2.replaceAnnoStr(ss, temp, "\\[#ANNO1\\]", " [#ANNO1]"); ss = sa[0]; temp = sa[1]; // get #TYPE1 if (0 == ss.length()) { throw new RuntimeException("illegal generics2."); } j = ss.indexOf(" "); if (-1 == j) { throw new RuntimeException("illegal generics2."); } String type = ss.substring(0, j).trim(); ss = ss.substring(j).trim(); temp = temp.replaceFirst("#TYPE1", type); // put @anno to [#ANNO2] sa = GENERICS2.replaceAnnoStr(ss, temp, "\\[#ANNO2\\]", " [#ANNO2]"); ss = sa[0]; temp = sa[1]; // get #TYPE2 if (0 == ss.length()) { throw new RuntimeException("illegal generics2."); } j = ss.indexOf(" "); if (-1 == j) { throw new RuntimeException("illegal generics2."); } type = ss.substring(0, j).trim(); ss = ss.substring(j).trim(); temp = temp.replaceFirst("#TYPE2", type); // put @anno to [#ANNO3] sa = GENERICS2.replaceAnnoStr(ss, temp, "\\[#ANNO3\\]", " [#ANNO3]"); ss = sa[0]; temp = sa[1]; // get #TYPE1 if (0 == ss.length()) { throw new RuntimeException("illegal generics2."); } j = ss.indexOf(" "); if (-1 != j) { throw new RuntimeException("illegal generics2."); } type = ss.trim(); temp = temp.replaceFirst("#TYPE3", type); temp = temp.replaceAll("TMP_", ""); } return temp.replaceAll(", \\[\\[#ANNO1\\] #TYPE1 " + "extends \\[#ANNO2\\] #TYPE2 " + "& \\[#ANNO3\\] #TYPE3, \\]", ""); } }, CLASS_BODY_START(" {\n") { public String getSrc(String... annoStr) { if (0 == annoStr.length) { return ""; } else { return template; } } }, FIELD_TYPE(" public [#ANNO] #NAME"), FIELD_ARRAY(" [[#ANNO] [] ] ") { // input should be like ["@A() @B()", "@C() @D()"...] public String getSrc(String... annoStr) { if (null == annoStr || 0 == annoStr.length) { return ""; } String temp = template; for (String as : annoStr) { temp = temp.replaceAll("\\[\\[#ANNO\\] \\[\\] \\]", "[#ANNO] [] [[#TMP_ANNO] [] ]"); // replace "[#ANNO]..." with "@realannotation [#ANNO]..." String ss = as.trim(); String[] sa = FIELD_ARRAY.replaceAnnoStr(ss, temp, "\\[#ANNO\\]", " [#ANNO]"); ss = sa[0]; temp = sa[1].replaceAll("TMP_", ""); } return temp.replaceAll("\\[\\[#ANNO\\] \\[\\] \\]", ""); } }, FIELD_NAME(" #NAME;\n"), CONSTRUCTOR_HEADER("\n public [#ANNO] #NAME"), METHOD_HEADER("\n public [#ANNO] #TYPE #NAME") { // input should be like "@realanno Type method" public String getSrc(String... annoStr) { if (0 == annoStr.length) { return ""; } String temp = template; for (String as : annoStr) { int j = 0; // index of ")" String ss = as.trim(); String[] sa = METHOD_HEADER.replaceAnnoStr(ss, temp, "\\[#ANNO\\]", " [#ANNO]"); ss = sa[0]; temp = sa[1]; // get #TYPE if (j == ss.length()) { throw new RuntimeException("illegal method head."); } j = ss.indexOf(" ") + 1; if (0 == j) { throw new RuntimeException("illegal method head."); } String type = ss.substring(0, j); temp = temp.replaceFirst("#TYPE", type); ss = ss.substring(j).trim(); // get #NAME if (0 <= ss.indexOf(" ") || 0 == ss.length()) { throw new RuntimeException("illegal method head."); } temp = temp.replaceFirst("#NAME", ss); } return temp; } }, METHOD_PARAMETER("([[#ANNO] #TYPE #NAME, ])") { // input should be like "@realanno Type arg" public String getSrc(String... annoStr) { if (null == annoStr || 0 == annoStr.length) { return ""; } if (1 == annoStr.length && "".equals(annoStr[0])) { return "()"; } String temp = template; for (String as : annoStr) { temp = temp.replaceFirst("\\[\\[#ANNO\\] #TYPE #NAME, \\]", "[#ANNO] #TYPE #NAME, " + "[[#TMP_ANNO] #TMP_TYPE #TMP_NAME, ]"); int j = 0; String ss = as.trim(); String[] sa = METHOD_PARAMETER.replaceAnnoStr(ss, temp, "\\[#ANNO\\]", " [#ANNO]"); ss = sa[0]; temp = sa[1]; // get #TYPE if (j == ss.length()) { throw new RuntimeException("illegal method parameter."); } j = ss.indexOf(" ") + 1; if (0 == j) { throw new RuntimeException("illegal method parameter."); } String type = ss.substring(0, j); temp = temp.replaceFirst("#TYPE", type); ss = ss.substring(j).trim(); // get #NAME if (0 <= ss.indexOf(" ") || 0 == ss.length()) { throw new RuntimeException("illegal method parameter."); } temp = temp.replaceFirst("#NAME", ss); temp = temp.replaceAll("TMP_", ""); } return temp.replaceAll(", \\[\\[#ANNO\\] #TYPE #NAME, \\]", ""); } }, METHOD_EXCEPTION(" throws [[#ANNO] #NAME, ]") { public String getSrc(String... annoStr) { return METHOD_EXCEPTION.replaceMultipleAnnoStr(annoStr); } }, METHOD_BODY(" {return null;}\n") { public String getSrc(String... annoStr) { if (null == annoStr || 0 == annoStr.length) { return ""; } else if (1 == annoStr.length && !"".equals(annoStr[0])) { return annoStr[0]; } else { return template; } } }, CLASS_BODY_END("\n}\n") { public String getSrc(String... annoStr) { return CLASS_BODY_END.getDefSrc(annoStr); } }, ANNOTATION_TYPE_1("\n@Target(ElementType.TYPE_USE)" + "\n@Retention(RetentionPolicy.RUNTIME)" + "\n@Repeatable(TypeAnno1Container.class)" + "\n@interface TypeAnno1 {" + "\n String value();" + "\n}") { public String getSrc(String... annoStr) { return ANNOTATION_TYPE_1.getDefSrc(annoStr); } public String toString() { return "@TypeAnno1(\"TypeAnno1\")"; } }, ANNOTATION_TYPE_2("\n@Target(ElementType.TYPE_USE)" + "\n@Retention(RetentionPolicy.RUNTIME)" + "\n@Repeatable(TypeAnno2Container.class)" + "\n@interface TypeAnno2 {" + "\n String value();" + "\n}") { public String getSrc(String... annoStr) { return ANNOTATION_TYPE_2.getDefSrc(annoStr); } public String toString() { return "@TypeAnno2(\"TypeAnno2\")"; } }, ANNOTATION_TYPE_3("\n@Target(ElementType.TYPE_USE)" + "\n@Retention(RetentionPolicy.RUNTIME)" + "\n@Repeatable(TypeAnno3Container.class)" + "\n@interface TypeAnno3 {" + "\n}") { public String getSrc(String... annoStr) { return ANNOTATION_TYPE_3.getDefSrc(annoStr); } public String toString() { return "@TypeAnno3"; } }, CONTAINING_ANNOTATION_TYPE_1("\n@Target(ElementType.TYPE_USE)" + "\n@Retention(RetentionPolicy.RUNTIME)" + "\n@interface TypeAnno1Container {" + "\n TypeAnno1[] value();" + "\n}") { public String getSrc(String... annoStr) { return CONTAINING_ANNOTATION_TYPE_1.getDefSrc(annoStr); } }, CONTAINING_ANNOTATION_TYPE_2("\n@Target(ElementType.TYPE_USE)" + "\n@Retention(RetentionPolicy.RUNTIME)" + "\n@interface TypeAnno2Container {" + "\n TypeAnno2[] value();" + "\n}") { public String getSrc(String... annoStr) { return CONTAINING_ANNOTATION_TYPE_2.getDefSrc(annoStr); } }, CONTAINING_ANNOTATION_TYPE_3("\n@Target(ElementType.TYPE_USE)" + "\n@Retention(RetentionPolicy.RUNTIME)" + "\n@interface TypeAnno3Container {" + "\n TypeAnno3[] value();" + "\n}") { public String getSrc(String... annoStr) { return CONTAINING_ANNOTATION_TYPE_3.getDefSrc(annoStr); } }, PACKAGE_ANNOTATION_1("\n@Target(ElementType.PACKAGE)" + "\n@Retention(RetentionPolicy.RUNTIME)" + "\npublic @interface PkgAnno1 {" + "\n String value();" + "\n}") { public String getSrc(String... annoStr) { return PACKAGE_ANNOTATION_1.getDefSrc(annoStr); } public String toString() { return "@pkg.PkgAnno1(\"PkgAnno1\")"; } }, PACKAGE_ANNOTATION_2("\n@Target(ElementType.PACKAGE)" + "\n@Retention(RetentionPolicy.RUNTIME)" + "\npublic @interface PkgAnno2 {" + "\n String value();" + "\n}") { public String getSrc(String... annoStr) { return PACKAGE_ANNOTATION_2.getDefSrc(annoStr); } public String toString() { return "@pkg.PkgAnno2(\"PkgAnno2\")"; } }; String template = ""; private Declaration(String template) { this.template = template; } /** * Gets the first annotation of the input string * @param str a string headed by annotation(s) * @return [first anno, the rest of the str] */ private static String[] getFirstAnno(String str) { if (null == str) { throw new RuntimeException("illegal input."); } String[] ret = new String[2]; str = str.trim(); int i = str.indexOf("@"); int j = str.indexOf(" "); if (-1 == j) { j = str.length(); } // annotation check - should be like @A or @A() or @A("...") if (2 > j - i) { throw new RuntimeException("illegal annotation."); } ret[0] = str.substring(i, j); ret[1] = str.substring(j).trim(); return ret; } /** * Change [#ANNO] #NAME into @annotation name * @param annoStr @annotation + name to be extracted * @return desired string with @annotation and name */ private String replaceMultipleAnnoStr(String... annoStr) { if (0 == annoStr.length) { return ""; } String temp = template; for (String as : annoStr) { temp = temp.replaceAll("\\[\\[#ANNO\\] #NAME, \\]", "[#ANNO] #NAME, [[#TMP_ANNO] #TMP_NAME, ]"); // replace "[#ANNO]..." with "@realannotation [#ANNO]..." int i = 0; // index of @ int j = 0; // index of " " for (; -1 != as.indexOf("@", j);) { i = as.indexOf("@", j); j = as.indexOf(" ", i); // annotation check - should be like @A or @A() or @A("...") if (2 > j - i) { throw new RuntimeException("illegal annotation."); } String anno = as.substring(i, j); temp = temp.replaceFirst("\\[#ANNO\\]", anno + " [#ANNO]"); } String name = as.substring(j, as.length()).trim(); temp = temp.replaceAll("#NAME", name).replaceAll( "\\[#ANNO\\]", ""); temp = temp.replaceAll("\\[\\[#TMP_ANNO\\] #TMP_NAME, \\]", "[[#ANNO] #NAME, ]"); } return temp.replaceAll(", \\[\\[#ANNO\\] #NAME, \\]", ""); } /** * Extract annotations from input string and put them in * declarations * @param ss * @param temp * @param decl * @param rep1 * @param rep2 * @return [the rest of the input string after stripping heading * annotations, the rest of declaration after stripping [ANNO]] */ private static String[] replaceAnnoStr(String ss, String temp, String rep1, String rep2) { while (ss.startsWith("@")) { String[] sa = getFirstAnno(ss); String anno = sa[0]; ss = sa[1].trim(); temp = temp.replaceFirst(rep1, anno + rep2); } temp = temp.replaceAll(rep1, ""); return new String[] {ss, temp}; } private String getDefSrc(String... annoStr) { if (0 == annoStr.length) { return ""; } else { return template; } } /** * Get the template * @return template */ public String getTemplate() { return template; } /** * Get the desired source code declaration * @param annoStr @annotation , type, name combinations * @return desired source code declaration */ public String getSrc(String... annoStr) { if (0 == annoStr.length || 1 == annoStr.length) { return replaceMultipleAnnoStr(annoStr); } else { throw new RuntimeException( "illegal input for declaration!"); } } } // Compile a list of FileObjects // Used when packages are needed and classes need to be loaded at runtime static File destDir = new File(System.getProperty("user.dir")); /** * Compile code * @param diagnostics diagnostics of the compilation * @param files files to compile * @return true - successful compilation, false failed compilation */ public static boolean compileCode( DiagnosticCollector diagnostics, Iterable files) { boolean ok = false; JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); if (compiler == null) { throw new RuntimeException("can't get javax.tools.JavaCompiler!"); } StandardJavaFileManager fm = compiler.getStandardFileManager( null, null, null); if (isPkgInfoPresent(files)) { JavacTask task = (JavacTask) compiler.getTask(null, fm, diagnostics, null, null, files); try { fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir)); task.generate(); } catch (IOException ioe) { throw new RuntimeException( "Compilation failed for package level tests", ioe); } ok = diagnostics.getDiagnostics().stream().anyMatch(d -> d.getKind() == Diagnostic.Kind.ERROR); } else { CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, files); ok = task.call(); } return ok; } /** * Check if package needs to be generated * @param files * @return true - yes, false - no */ static private boolean isPkgInfoPresent( Iterable files) { for (JavaFileObject jfo : files) { String name = jfo.getName(); if (name.contains("package-info") || name.contains("PkgAnno")) { return true; } } return false; } static JavaFileObject getFile(String name, String code) throws Exception{ return new JavaStringFileObject(name, code); } static class JavaStringFileObject extends SimpleJavaFileObject { final String theCode; public JavaStringFileObject(String fileName, String theCode) throws URISyntaxException { super(new URI("string:///" + fileName.replace('.', '/') + ".java"), Kind.SOURCE); this.theCode = theCode; } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return theCode; } } private static URLClassLoader URLCL = null; private static URLClassLoader getClassLoader() throws Exception { if (null != URLCL) return URLCL; ClassLoader parentClassLoader = new Helper().getClass().getClassLoader(); URLCL = getClassLoader(parentClassLoader, destDir); return URLCL; } private static URLClassLoader getClassLoader(ClassLoader parentClassLoader, File... destDirs) throws Exception { List list = new ArrayList<>(); for (File f : destDirs) { list.add(new URL( "file:" + f.toString().replace("\\", "/") + "/")); } return new URLClassLoader(list.toArray(new URL[list.size()]), parentClassLoader); } /** * Load class to class loader * @param className * @return loaded class * @throws Exception */ public static Class loadClass(String className) throws Exception { try { return Class.forName(className, true, getClassLoader()); } catch (ClassNotFoundException | MalformedURLException e) { throw new RuntimeException("Error loading class " + className, e); } } /** * Generate class from test code * @param testCode * @param parentClassLoader * @param clsName * @throws Exception */ public static void genClass(String testCode, ClassLoader parentClassLoader, String clsName) throws Exception { Map lhm = new LinkedHashMap(); lhm.put(clsName, testCode); genClasses(parentClassLoader, lhm); } /** * Generate classes from test code * @param parentClassLoader * @param clsList class name - class code correspondences * @throws Exception */ public static void genClasses(ClassLoader parentClassLoader, Map clsList) throws Exception { Iterable files = new ArrayList(); for (String clsName : clsList.keySet()) { String testCode = clsList.get(clsName); ((List) files).add(getFile(clsName, testCode)); } DiagnosticCollector diagnostics = new DiagnosticCollector<>(); // Compile the list of JavaFileObjects try { Helper.compileCode(diagnostics, files); } catch (Exception ex) { throw new RuntimeException( "Exception when compiling class "); } } /** * Get annotations from annotation object * @param annotation annotation object * @return annotation string like @Anno("Anno") * @throws Exception */ public static String getAnno(Annotation annotation) throws Exception { if (null == annotation) { return ""; } StringBuilder result = new StringBuilder(""); String annoName = ""; Object value = null; try { Method method = annotation.annotationType().getMethod("value", new Class[]{}); method.setAccessible(true); value = method.invoke(annotation, new Object[]{}); } catch (NoSuchMethodException e) { //expected exception for annotations without value } if (null == value) { annoName = annotation.annotationType().getSimpleName(); result.append("@" + annoName); result.append(" "); } else if (value instanceof String) { annoName = annotation.annotationType().getSimpleName(); result.append("@" + annoName); result.append("(\"" + value + "\") "); } else { //for repeated anno Annotation[] av = (Annotation[]) value; for (int j = 0; j < av.length; j++) { annoName = av[j].annotationType().getSimpleName(); value = " "; try { Method method = av[j].annotationType().getMethod("value", new Class[]{}); method.setAccessible(true); value = method.invoke(av[j], new Object[]{}); value = "(\"" + value + "\") "; } catch (NoSuchMethodException e) { //expected exception for annotations without value } result.append("@" + annoName); result.append(value); } } return result.toString(); } /** * Get annotations from annotation object array * @param annotations annotation objects * @return annotation string like @Anno1("Anno1")@Anno2("Anno2") * @throws Exception */ public static String getAnno(Annotation[] annotations) throws Exception { StringBuilder result = new StringBuilder(""); if (null != annotations) { for (int i = 0; i < annotations.length; i++) { String anno = getAnno(annotations[i]); if (!"".equals(anno)) { result.append(anno); } } } return result.toString(); } /** * Get AnnotatedType type and value, output as string * @param at * @return annotation string like @Anno1("Anno1")@Anno2("Anno2") * @throws Exception */ public static String getAT(AnnotatedType at) throws Exception { if (null == at) System.out.println(23); Annotation[] annotations = at.getAnnotations(); return getAnno(annotations); } /** * Get AnnotatedArrayType type and value, output as string * @param at * @return annotation string like @Anno1("Anno1")@Anno2("Anno2") * @throws Exception */ public static String getArrAT(AnnotatedType at) throws Exception { String ret = ""; if (at instanceof AnnotatedArrayType) { at = ((AnnotatedArrayType) at).getAnnotatedGenericComponentType(); ret += getArrAT(at); } Annotation[] annotations = at.getAnnotations(); return getAnno(annotations) + ";" + ret; } /** * Get multiple AnnotatedType type and value, output as string * @param as * @return list of annotations * @throws Exception */ public static List getMultipleAT(AnnotatedType[] as) throws Exception { List result = new ArrayList<>(); for (int i = 0; i < as.length; i++) { if (null != as[i]) { result.add(getAT(as[i])); } } return result; } /** * Compare two string of annotations and check if they contain * the same annotations * @param anno1 * @param anno2 * @return true - yes, false - no */ public static boolean compareAnnoWithDiffSeq(String anno1, String anno2) { String[] split1 = anno1.trim().split("\\s+"); String[] split2 = anno2.trim().split("\\s+"); Arrays.sort(split1); Arrays.sort(split2); return Arrays.equals(split1, split2); } /** * For debug use * @param string */ public static void debugPrint(String string) { if (DEBUG) { System.out.println(string); } } /** * For debug use * @param string */ public static void debugPrintToFile(String string, String fileName) { if (DEBUG) { try { String path = System.getProperty("test.classes", ".") + File.separator + fileName; File dirFile = new File(path); if (!(dirFile.exists()) && !(dirFile.isDirectory())) { if (!dirFile.mkdirs()) { throw new IOException(); } } FileOutputStream fos = new FileOutputStream(path + File.separator + "TypeAnnoClsBase.java"); OutputStreamWriter osw = new OutputStreamWriter(fos); BufferedWriter bw = new BufferedWriter(osw); bw.write(string); bw.close(); } catch (IOException e) { e.printStackTrace(); System.out.println("Error output test source to file."); } } } }