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