1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3;
18
19 import java.io.File;
20 import java.io.FileWriter;
21 import java.lang.reflect.Method;
22 import java.net.URL;
23 import java.net.URLClassLoader;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27
28 import javax.tools.Diagnostic;
29 import javax.tools.DiagnosticCollector;
30 import javax.tools.JavaCompiler;
31 import javax.tools.JavaFileObject;
32 import javax.tools.StandardJavaFileManager;
33 import javax.tools.ToolProvider;
34
35
36
37
38
39
40 public class ClassCreator {
41
42 public static final boolean canRun = true;
43 static final String JEXL_PACKAGE = "org.apache.commons.jexl3";
44 static final String GEN_PACKAGE = "org.apache.commons.jexl3.generated";
45 static final String GEN_PATH = "/" + GEN_PACKAGE.replace(".", "/");
46 static final String GEN_CLASS = GEN_PACKAGE + ".";
47
48
49
50
51
52 private static boolean comSunToolsJavacMain() {
53 try {
54 final Class<?> javac = ClassCreatorTest.class.getClassLoader().loadClass("com.sun.tools.javac.Main");
55 return javac != null;
56 } catch (final Exception xany) {
57 return false;
58 }
59 }
60
61 private final File base;
62 private File packageDir;
63
64 private int seed;
65 private String ctorBody = "";
66 private String className;
67 private String sourceName;
68
69 private ClassLoader loader;
70
71 public ClassCreator(final JexlEngine theJexl, final File theBase) throws Exception {
72
73 base = theBase;
74 }
75
76 public void clear() {
77 seed = 0;
78 ctorBody = "";
79 packageDir = null;
80 className = null;
81 sourceName = null;
82 packageDir = null;
83 loader = null;
84 }
85
86 Class<?> compile() throws Exception {
87 final String source = packageDir.getPath() + "/" + sourceName;
88 final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
89 final DiagnosticCollector<JavaFileObject> diagnosticsCollector = new DiagnosticCollector<>();
90 final boolean success;
91 try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticsCollector, null, null)) {
92 final Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromStrings(Collections.singletonList(source));
93
94 final List<String> options = new ArrayList<>();
95 options.add("-classpath");
96
97
98 final String currentDir = new File(".").getAbsolutePath();
99 final String classpath = currentDir + File.separator + "target" + File.separator + "classes"
100
101 + File.pathSeparator + System.getProperty("surefire.test.class.path");
102
103 options.add(classpath);
104
105
106 final JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnosticsCollector, options, null, compilationUnits);
107 success = task.call();
108 }
109 if (success) {
110 return getClassLoader().loadClass(GEN_CLASS + className);
111 }
112 final List<Diagnostic<? extends JavaFileObject>> diagnostics = diagnosticsCollector.getDiagnostics();
113 for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics) {
114
115 System.out.println(diagnostic.getMessage(null));
116
117 }
118 return null;
119 }
120
121 public Class<?> createClass() throws Exception {
122 return createClass(false);
123 }
124
125 public Class<?> createClass(final boolean ftor) throws Exception {
126
127 generate(ftor);
128 final Class<?> clazz = compile();
129 if (clazz == null) {
130 throw new Exception("failed to compile foo" + seed);
131 }
132 if (ftor) {
133 return clazz;
134 }
135 final Object v = validate(clazz);
136 if (v instanceof Integer && (Integer) v == seed) {
137 return clazz;
138 }
139 throw new Exception("failed to validate foo" + seed);
140 }
141
142 void generate(final boolean ftor) throws Exception {
143 try (final FileWriter writer = new FileWriter(new File(packageDir, sourceName), false)) {
144 writer.write("package ");
145 writer.write(GEN_PACKAGE);
146 writer.write(";\n");
147 if (ftor) {
148 writer.write("import " + JEXL_PACKAGE + ".JexlContext;");
149 writer.write(";\n");
150 }
151 writer.write("public class " + className);
152 writer.write(" {\n");
153 if (ftor) {
154 writer.write("public " + className + "(JexlContext ctxt) {\n");
155 writer.write(ctorBody);
156 writer.write(" }\n");
157 }
158 writer.write("private int value =");
159 writer.write(Integer.toString(seed));
160 writer.write(";\n");
161 writer.write(" public void setValue(int v) {");
162 writer.write(" value = v;");
163 writer.write(" }\n");
164 writer.write(" public int getValue() {");
165 writer.write(" return value;");
166 writer.write(" }\n");
167 writer.write(" }\n");
168 writer.flush();
169 }
170 }
171
172 public Class<?> getClassInstance() throws Exception {
173 return getClassLoader().loadClass(getClassName());
174 }
175
176 public ClassLoader getClassLoader() throws Exception {
177 if (loader == null) {
178 final URL classpath = new File(base, Integer.toString(seed)).toURI().toURL();
179 loader = new URLClassLoader(new URL[]{classpath}, getClass().getClassLoader());
180 }
181 return loader;
182 }
183
184 public String getClassName() {
185 return GEN_CLASS + className;
186 }
187
188 Object newInstance(final Class<?> clazz, final JexlContext ctxt) throws Exception {
189 return clazz.getConstructor(JexlContext.class).newInstance(ctxt);
190 }
191
192 public void setCtorBody(final String arg) {
193 ctorBody = arg;
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218 public void setSeed(final int s) {
219 seed = s;
220 className = "foo" + s;
221 sourceName = className + ".java";
222 packageDir = new File(base, seed + GEN_PATH);
223 packageDir.mkdirs();
224 loader = null;
225 }
226
227 Object validate(final Class<?> clazz) throws Exception {
228 final Class<?>[] params = {};
229 final Object[] paramsObj = {};
230 final Object iClass = clazz.getConstructor().newInstance();
231 final Method thisMethod = clazz.getDeclaredMethod("getValue", params);
232 return thisMethod.invoke(iClass, paramsObj);
233 }
234
235 }