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