diff --git a/pom.xml b/pom.xml
index ae01288f5..15dfd3acb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.mysema.codegen
codegen
- 0.5.1
+ 0.5.2
Codegen
Code generation and compilation for Java
@@ -20,6 +20,7 @@
4.01
3.0.1
11.0.2
+ 3.7.2
@@ -28,6 +29,12 @@
guava
11.0.2
+
+
+ org.eclipse.jdt.core.compiler
+ ecj
+ ${ecj.version}
+
@@ -47,7 +54,8 @@
validation-api
1.0.CR3
test
-
+
+
diff --git a/src/main/java/com/mysema/codegen/AbstractEvaluatorFactory.java b/src/main/java/com/mysema/codegen/AbstractEvaluatorFactory.java
new file mode 100644
index 000000000..2a1af1f41
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/AbstractEvaluatorFactory.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2012 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import com.mysema.codegen.model.ClassType;
+import com.mysema.codegen.model.Type;
+import com.mysema.codegen.model.TypeCategory;
+
+/**
+ * @author tiwe
+ *
+ */
+public abstract class AbstractEvaluatorFactory implements EvaluatorFactory{
+
+ protected ClassLoader loader;
+
+ /**
+ * @param source
+ * @param projection
+ * @param names
+ * @param types
+ * @param id
+ * @param constants
+ * @throws IOException
+ */
+ protected abstract void compile(String source, ClassType projection, String[] names, Type[] types,
+ String id, Map constants) throws IOException;
+
+
+ @Override
+ public Evaluator createEvaluator(String source, Class extends T> projectionType,
+ String[] names, Class>[] classes, Map constants) {
+ Type[] types = new Type[classes.length];
+ for (int i = 0; i < types.length; i++) {
+ types[i] = new ClassType(TypeCategory.SIMPLE, classes[i]);
+ }
+ return createEvaluator(source, new ClassType(TypeCategory.SIMPLE, projectionType), names,
+ types, classes, constants);
+ }
+
+
+ /**
+ * Create a new Evaluator instance
+ *
+ * @param
+ * projection type
+ * @param source
+ * expression in Java source code form
+ * @param projection
+ * type of the source expression
+ * @param names
+ * names of the arguments
+ * @param types
+ * types of the arguments
+ * @param constants
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public Evaluator createEvaluator(String source, ClassType projection, String[] names,
+ Type[] types, Class>[] classes, Map constants) {
+ try {
+ String id = toId(source, projection.getJavaClass(), types);
+ Class> clazz;
+ try {
+ clazz = loader.loadClass(id);
+ } catch (ClassNotFoundException e) {
+ compile(source, projection, names, types, id, constants);
+ // reload
+ clazz = loader.loadClass(id);
+ }
+
+ Object object = !constants.isEmpty() ? clazz.newInstance() : null;
+
+ for (Map.Entry entry : constants.entrySet()) {
+ Field field = clazz.getField(entry.getKey());
+ field.set(object, entry.getValue());
+ }
+
+ Method method = clazz.getMethod("eval", classes);
+ return new MethodEvaluator(method, object, (Class) projection.getJavaClass());
+ } catch (ClassNotFoundException e) {
+ throw new CodegenException(e);
+ } catch (SecurityException e) {
+ throw new CodegenException(e);
+ } catch (NoSuchMethodException e) {
+ throw new CodegenException(e);
+ } catch (NoSuchFieldException e) {
+ throw new CodegenException(e);
+ } catch (InstantiationException e) {
+ throw new CodegenException(e);
+ } catch (IOException e) {
+ throw new CodegenException(e);
+ } catch (IllegalAccessException e) {
+ throw new CodegenException(e);
+ }
+
+ }
+
+
+ protected String toId(String source, Class> returnType, Type... types) {
+ StringBuilder b = new StringBuilder("Q");
+ b.append("_").append(source.hashCode());
+ b.append("_").append(returnType.getName().hashCode());
+ for (Type type : types) {
+ b.append("_").append(type.getFullName().hashCode());
+ }
+ return b.toString().replace('-', '0');
+ }
+
+}
diff --git a/src/main/java/com/mysema/codegen/ECJEvaluatorFactory.java b/src/main/java/com/mysema/codegen/ECJEvaluatorFactory.java
new file mode 100644
index 000000000..f8436beb9
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/ECJEvaluatorFactory.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.tools.JavaFileObject;
+import javax.tools.StandardLocation;
+
+import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
+import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
+import org.eclipse.jdt.internal.compiler.IProblemFactory;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+import org.eclipse.jdt.internal.compiler.tool.EclipseFileManager;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.io.ByteStreams;
+import com.mysema.codegen.model.ClassType;
+import com.mysema.codegen.model.Parameter;
+import com.mysema.codegen.model.SimpleType;
+import com.mysema.codegen.model.Type;
+import com.mysema.codegen.model.TypeCategory;
+import com.mysema.codegen.support.ClassUtils;
+
+/**
+ * EvaluatorFactory is a factory implementation for creating Evaluator instances
+ *
+ * @author tiwe
+ *
+ */
+public class ECJEvaluatorFactory extends AbstractEvaluatorFactory {
+
+ private final MemFileManager fileManager;
+
+ private final ClassLoader parentClassLoader;
+
+ private final List problemList = Lists.newArrayList();
+
+ private final CompilerOptions compilerOptions;
+
+ public static CompilerOptions getDefaultCompilerOptions() {
+ String javaSpecVersion = System.getProperty("java.specification.version");
+ Map settings = Maps.newHashMap();
+ settings.put(CompilerOptions.OPTION_Source, javaSpecVersion);
+ settings.put(CompilerOptions.OPTION_TargetPlatform, javaSpecVersion);
+ settings.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.IGNORE);
+ return new CompilerOptions(settings);
+ }
+
+ public ECJEvaluatorFactory(ClassLoader parent) {
+ this(parent, getDefaultCompilerOptions());
+ }
+
+ public ECJEvaluatorFactory(ClassLoader parent, CompilerOptions compilerOptions) {
+ this.parentClassLoader = parent;
+ this.fileManager = new MemFileManager(parent, new EclipseFileManager(Locale.getDefault(), Charset.defaultCharset()));
+ this.loader = fileManager.getClassLoader(StandardLocation.CLASS_OUTPUT);
+ this.compilerOptions = compilerOptions;
+ }
+
+ protected void compile(String source, ClassType projectionType, String[] names, Type[] types,
+ String id, Map constants) throws IOException {
+ // create source
+ StringWriter writer = new StringWriter();
+ JavaWriter javaw = new JavaWriter(writer);
+ SimpleType idType = new SimpleType(id, "", id);
+ javaw.beginClass(idType, null);
+ Parameter[] params = new Parameter[names.length];
+ for (int i = 0; i < params.length; i++) {
+ params[i] = new Parameter(names[i], types[i]);
+ }
+
+ for (Map.Entry entry : constants.entrySet()) {
+ Type type = new ClassType(TypeCategory.SIMPLE, ClassUtils.normalize(entry.getValue().getClass()));
+ javaw.publicField(type, entry.getKey());
+ }
+
+ if (constants.isEmpty()) {
+ javaw.beginStaticMethod(projectionType, "eval", params);
+ } else {
+ javaw.beginPublicMethod(projectionType, "eval", params);
+ }
+ javaw.append(source);
+ javaw.end();
+ javaw.end();
+
+ // compile
+ final char[] targetContents = writer.toString().toCharArray();
+ final String targetName = idType.getFullName();
+ final ICompilationUnit[] targetCompilationUnits = new ICompilationUnit[] { new ICompilationUnit() {
+ @Override
+ public char[] getContents() {
+ return targetContents;
+ }
+
+ @Override
+ public char[] getMainTypeName() {
+ int dot = targetName.lastIndexOf('.');
+ if (dot > 0)
+ return targetName.substring(dot + 1).toCharArray();
+ else
+ return targetName.toCharArray();
+ }
+
+ @Override
+ public char[][] getPackageName() {
+ StringTokenizer tok = new StringTokenizer(targetName, ".");
+ char[][] result = new char[tok.countTokens() - 1][];
+ for (int j = 0; j < result.length; j++) {
+ result[j] = tok.nextToken().toCharArray();
+ }
+ return result;
+ }
+
+ @Override
+ public char[] getFileName() {
+ return CharOperation.concat(targetName.toCharArray(), ".java".toCharArray());
+ }
+ } };
+
+ INameEnvironment env = new INameEnvironment() {
+
+ private String join(char[][] compoundName, char separator) {
+ if (compoundName == null) {
+ return "";
+ } else {
+ List parts = Lists.newArrayListWithCapacity(compoundName.length);
+ for (char[] part: compoundName) {
+ parts.add(new String(part));
+ }
+ return Joiner.on(separator).join(parts);
+ }
+ }
+
+ @Override
+ public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
+ return findType(join(compoundTypeName, '.'));
+ }
+
+ @Override
+ public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
+ return findType(CharOperation.arrayConcat(packageName, typeName));
+ }
+
+ private boolean isClass(String result) {
+ if (Strings.isNullOrEmpty(result))
+ return false;
+
+ // if it's the class we're compiling, then of course it's a class
+ if (result.equals(targetName)) {
+ return true;
+ }
+ InputStream is = null;
+ try {
+ // if this is a class we've already compiled, it's a class
+ is = loader.getResourceAsStream(result);
+ if (is == null) {
+ // use our normal class loader now...
+ String resourceName = result.replace('.', '/') + ".class";
+ is = parentClassLoader.getResourceAsStream(resourceName);
+ if (is == null && !result.contains(".")) {
+ // we couldn't find the class, and it has no package; is it a core class?
+ is = parentClassLoader.getResourceAsStream("java/lang/" + resourceName);
+ }
+ }
+ if (is == null) {
+ return false; // if it's a class, we sure couldn't load it
+ } else {
+ return true; // we actually loaded the class, so it must be one
+ }
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException ex) {}
+ }
+ }
+ }
+
+ @Override
+ public boolean isPackage(char[][] parentPackageName, char[] packageName) {
+ // if the parent is a class, the child can't be a package
+ String parent = join(parentPackageName, '.');
+ if (isClass(parent))
+ return false;
+
+ // if the child is a class, it's not a package
+ String qualifiedName = (parent.isEmpty() ? "" : parent + ".") + new String(packageName);
+ return !isClass(qualifiedName);
+ }
+
+ @Override
+ public void cleanup() {
+ }
+
+ private NameEnvironmentAnswer findType(String className) {
+ String resourceName = className.replace('.', '/') + ".class";
+ InputStream is = null;
+ try {
+ // we're only asking ECJ to compile a single class; we shouldn't need this
+ if (className.equals(targetName)) {
+ return new NameEnvironmentAnswer(targetCompilationUnits[0], null);
+ }
+
+ is = loader.getResourceAsStream(resourceName);
+ if (is == null) {
+ is = parentClassLoader.getResourceAsStream(resourceName);
+ }
+
+ if (is != null) {
+ ClassFileReader cfr = new ClassFileReader(ByteStreams.toByteArray(is), className.toCharArray(), true);
+ return new NameEnvironmentAnswer(cfr, null);
+ } else {
+ return null;
+ }
+ } catch (ClassFormatException ex) {
+ throw new RuntimeException(ex);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {}
+ }
+ }
+
+ }
+ };
+
+ ICompilerRequestor requestor = new ICompilerRequestor() {
+
+ @Override
+ public void acceptResult(CompilationResult result) {
+ if (result.hasErrors()) {
+ for (CategorizedProblem problem: result.getProblems()) {
+ if (problem.isError()) {
+ problemList.add(problem.getMessage());
+ }
+ }
+ } else {
+ for (ClassFile clazz: result.getClassFiles()) {
+ try {
+ MemJavaFileObject jfo = (MemJavaFileObject) fileManager
+ .getJavaFileForOutput(StandardLocation.CLASS_OUTPUT,
+ new String(clazz.fileName()), JavaFileObject.Kind.CLASS, null);
+ OutputStream os = jfo.openOutputStream();
+ os.write(clazz.getBytes());
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+ }
+ };
+
+ problemList.clear();
+
+ IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.exitAfterAllProblems();
+ IProblemFactory problemFactory = new DefaultProblemFactory(Locale.getDefault());
+
+ try {
+ //Compiler compiler = new Compiler(env, policy, getCompilerOptions(), requestor, problemFactory, true);
+ Compiler compiler = new Compiler(env, policy, compilerOptions, requestor, problemFactory);
+ compiler.compile(targetCompilationUnits);
+ if (!problemList.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+ for (String problem: problemList) {
+ sb.append("\t").append(problem).append("\n");
+ }
+ throw new CodegenException("Compilation of " + id + " failed:\n" + source + "\n" + sb.toString());
+ }
+ } catch (RuntimeException ex) {
+ // if we encountered an IOException, unbox and throw it;
+ // if we encountered a ClassFormatException, box it as an IOException and throw it
+ // otherwise, it's a legit RuntimeException,
+ // not one of our checked exceptions boxed as unchecked; just rethrow
+ Throwable cause = ex.getCause();
+ if (cause != null) {
+ if (cause instanceof IOException)
+ throw (IOException)cause;
+ else if (cause instanceof ClassFormatException)
+ throw new IOException(cause);
+ }
+ throw ex;
+ }
+ }
+
+ public CompilerOptions getCompilerOptions() {
+ return compilerOptions;
+ }
+
+
+}
diff --git a/src/main/java/com/mysema/codegen/EvaluatorFactory.java b/src/main/java/com/mysema/codegen/EvaluatorFactory.java
index f75d9fde6..85e4212e2 100644
--- a/src/main/java/com/mysema/codegen/EvaluatorFactory.java
+++ b/src/main/java/com/mysema/codegen/EvaluatorFactory.java
@@ -1,180 +1,38 @@
/*
- * Copyright (c) 2010 Mysema Ltd.
- * All rights reserved.
- *
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
*/
package com.mysema.codegen;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.net.URLClassLoader;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+import com.mysema.codegen.model.ClassType;
+import com.mysema.codegen.model.Type;
import java.util.Map;
-import javax.tools.JavaCompiler;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.StandardLocation;
-import javax.tools.ToolProvider;
-import javax.tools.JavaCompiler.CompilationTask;
-
-import com.mysema.codegen.model.ClassType;
-import com.mysema.codegen.model.Parameter;
-import com.mysema.codegen.model.SimpleType;
-import com.mysema.codegen.model.Type;
-import com.mysema.codegen.model.TypeCategory;
-import com.mysema.codegen.support.ClassUtils;
-
/**
- * EvaluatorFactory is a factory implementation for creating Evaluator instances
- *
- * @author tiwe
- *
+ *
+ * @author pgrant
*/
-public class EvaluatorFactory {
+public interface EvaluatorFactory {
- private final MemFileManager fileManager;
-
- private final String classpath;
-
- private final List compilationOptions;
-
- private final JavaCompiler compiler;
-
- private final ClassLoader loader;
-
- public EvaluatorFactory(URLClassLoader parent) {
- this(parent, ToolProvider.getSystemJavaCompiler());
- }
-
- public EvaluatorFactory(URLClassLoader parent, JavaCompiler compiler) {
- this.fileManager = new MemFileManager(parent, compiler.getStandardFileManager(null, null, null));
- this.compiler = compiler;
- this.classpath = SimpleCompiler.getClassPath(parent);
- this.loader = fileManager.getClassLoader(StandardLocation.CLASS_OUTPUT);
- this.compilationOptions = Arrays.asList("-classpath", classpath, "-g:none");
- }
-
- private void compile(String source, Type projectionType, String[] names, Type[] types,
- String id, Map constants) throws IOException {
- // create source
- StringWriter writer = new StringWriter();
- JavaWriter javaw = new JavaWriter(writer);
- SimpleType idType = new SimpleType(id, "", id);
- javaw.beginClass(idType, null);
- Parameter[] params = new Parameter[names.length];
- for (int i = 0; i < params.length; i++) {
- params[i] = new Parameter(names[i], types[i]);
- }
-
- for (Map.Entry entry : constants.entrySet()) {
- Type type = new ClassType(TypeCategory.SIMPLE, ClassUtils.normalize(entry.getValue().getClass()));
- javaw.publicField(type, entry.getKey());
- }
-
- if (constants.isEmpty()) {
- javaw.beginStaticMethod(projectionType, "eval", params);
- } else {
- javaw.beginPublicMethod(projectionType, "eval", params);
- }
- javaw.append(source);
- javaw.end();
- javaw.end();
-
- // compile
- SimpleJavaFileObject javaFileObject = new MemSourceFileObject(id, writer.toString());
- Writer out = new StringWriter();
-
- CompilationTask task = compiler.getTask(out, fileManager, null, compilationOptions, null,
- Collections.singletonList(javaFileObject));
- if (!task.call().booleanValue()) {
- throw new CodegenException("Compilation of " + source + " failed.\n" + out.toString());
- }
-
- }
-
- public Evaluator createEvaluator(String source, Class extends T> projectionType,
- String[] names, Class>[] classes, Map constants) {
- Type[] types = new Type[classes.length];
- for (int i = 0; i < types.length; i++) {
- types[i] = new ClassType(TypeCategory.SIMPLE, classes[i]);
- }
- return createEvaluator(source, new ClassType(TypeCategory.SIMPLE, projectionType), names,
- types, classes, constants);
- }
+ Evaluator createEvaluator(String source, Class extends T> projectionType, String[] names, Class>[] classes, Map constants);
/**
* Create a new Evaluator instance
- *
+ *
* @param
- * projection type
+ * projection type
* @param source
- * expression in Java source code form
+ * expression in Java source code form
* @param projection
- * type of the source expression
+ * type of the source expression
* @param names
- * names of the arguments
+ * names of the arguments
* @param types
- * types of the arguments
+ * types of the arguments
* @param constants
* @return
*/
- @SuppressWarnings("unchecked")
- public Evaluator createEvaluator(String source, ClassType projection, String[] names,
- Type[] types, Class>[] classes, Map constants) {
- try {
- String id = toId(source, projection.getJavaClass(), types);
- Class> clazz;
- try {
- clazz = loader.loadClass(id);
- } catch (ClassNotFoundException e) {
- compile(source, projection, names, types, id, constants);
- // reload
- clazz = loader.loadClass(id);
- }
-
- Object object = !constants.isEmpty() ? clazz.newInstance() : null;
-
- for (Map.Entry entry : constants.entrySet()) {
- Field field = clazz.getField(entry.getKey());
- field.set(object, entry.getValue());
- }
-
- Method method = clazz.getMethod("eval", classes);
- return new MethodEvaluator(method, object, (Class) projection.getJavaClass());
- } catch (ClassNotFoundException e) {
- throw new CodegenException(e);
- } catch (SecurityException e) {
- throw new CodegenException(e);
- } catch (NoSuchMethodException e) {
- throw new CodegenException(e);
- } catch (NoSuchFieldException e) {
- throw new CodegenException(e);
- } catch (UnsupportedEncodingException e) {
- throw new CodegenException(e);
- } catch (IOException e) {
- throw new CodegenException(e);
- } catch (InstantiationException e) {
- throw new CodegenException(e);
- } catch (IllegalAccessException e) {
- throw new CodegenException(e);
- }
-
- }
-
- protected String toId(String source, Class> returnType, Type... types) {
- StringBuilder b = new StringBuilder("Q");
- b.append("_").append(source.hashCode());
- b.append("_").append(returnType.getName().hashCode());
- for (Type type : types) {
- b.append("_").append(type.getFullName().hashCode());
- }
- return b.toString().replace('-', '0');
- }
-
+ @SuppressWarnings(value = "unchecked")
+ Evaluator createEvaluator(String source, ClassType projection, String[] names, Type[] types, Class>[] classes, Map constants);
+
}
diff --git a/src/main/java/com/mysema/codegen/JDKEvaluatorFactory.java b/src/main/java/com/mysema/codegen/JDKEvaluatorFactory.java
new file mode 100644
index 000000000..60231c44e
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/JDKEvaluatorFactory.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2010 Mysema Ltd.
+ * All rights reserved.
+ *
+ */
+package com.mysema.codegen;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.tools.JavaCompiler;
+import javax.tools.JavaCompiler.CompilationTask;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import com.mysema.codegen.model.ClassType;
+import com.mysema.codegen.model.Parameter;
+import com.mysema.codegen.model.SimpleType;
+import com.mysema.codegen.model.Type;
+import com.mysema.codegen.model.TypeCategory;
+import com.mysema.codegen.support.ClassUtils;
+
+/**
+ * JDKEvaluatorFactory is a factory implementation for creating Evaluator instances
+ *
+ * @author tiwe
+ *
+ */
+public class JDKEvaluatorFactory extends AbstractEvaluatorFactory {
+
+ private final MemFileManager fileManager;
+
+ private final String classpath;
+
+ private final List compilationOptions;
+
+ private final JavaCompiler compiler;
+
+ public JDKEvaluatorFactory(URLClassLoader parent) {
+ this(parent, ToolProvider.getSystemJavaCompiler());
+ }
+
+ public JDKEvaluatorFactory(URLClassLoader parent, JavaCompiler compiler) {
+ this.fileManager = new MemFileManager(parent, compiler.getStandardFileManager(null, null, null));
+ this.compiler = compiler;
+ this.classpath = SimpleCompiler.getClassPath(parent);
+ this.loader = fileManager.getClassLoader(StandardLocation.CLASS_OUTPUT);
+ this.compilationOptions = Arrays.asList("-classpath", classpath, "-g:none");
+ }
+
+ protected void compile(String source, ClassType projectionType, String[] names, Type[] types,
+ String id, Map constants) throws IOException {
+ // create source
+ StringWriter writer = new StringWriter();
+ JavaWriter javaw = new JavaWriter(writer);
+ SimpleType idType = new SimpleType(id, "", id);
+ javaw.beginClass(idType, null);
+ Parameter[] params = new Parameter[names.length];
+ for (int i = 0; i < params.length; i++) {
+ params[i] = new Parameter(names[i], types[i]);
+ }
+
+ for (Map.Entry entry : constants.entrySet()) {
+ Type type = new ClassType(TypeCategory.SIMPLE, ClassUtils.normalize(entry.getValue().getClass()));
+ javaw.publicField(type, entry.getKey());
+ }
+
+ if (constants.isEmpty()) {
+ javaw.beginStaticMethod(projectionType, "eval", params);
+ } else {
+ javaw.beginPublicMethod(projectionType, "eval", params);
+ }
+ javaw.append(source);
+ javaw.end();
+ javaw.end();
+
+ // compile
+ SimpleJavaFileObject javaFileObject = new MemSourceFileObject(id, writer.toString());
+ Writer out = new StringWriter();
+
+ CompilationTask task = compiler.getTask(out, fileManager, null, compilationOptions, null,
+ Collections.singletonList(javaFileObject));
+ if (!task.call().booleanValue()) {
+ throw new CodegenException("Compilation of " + source + " failed.\n" + out.toString());
+ }
+
+ }
+
+}
diff --git a/src/test/java/com/mysema/codegen/ComplexEvaluationTest.java b/src/test/java/com/mysema/codegen/ComplexEvaluationTest.java
index b6ac331b2..6a9d55294 100644
--- a/src/test/java/com/mysema/codegen/ComplexEvaluationTest.java
+++ b/src/test/java/com/mysema/codegen/ComplexEvaluationTest.java
@@ -7,7 +7,6 @@ package com.mysema.codegen;
import static org.junit.Assert.*;
-import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -18,11 +17,11 @@ import com.mysema.codegen.model.ClassType;
import com.mysema.codegen.model.Type;
import com.mysema.codegen.model.TypeCategory;
import com.mysema.codegen.model.Types;
+import com.mysema.codegen.support.Cat;
public class ComplexEvaluationTest {
- private EvaluatorFactory factory = new EvaluatorFactory((URLClassLoader) getClass()
- .getClassLoader());
+ private EvaluatorFactory factory = new ECJEvaluatorFactory(getClass().getClassLoader());
@Test
@SuppressWarnings("unchecked")
@@ -49,4 +48,116 @@ public class ComplexEvaluationTest {
assertEquals(Arrays.asList("2", "4"), evaluator.evaluate(a_, b_));
}
+ @Test
+ @SuppressWarnings("unchecked")
+ public void ComplexClassLoading() {
+ ClassType resultType = new ClassType(TypeCategory.LIST, List.class, Types.OBJECTS);
+ StringBuilder source = new StringBuilder();
+ source.append("java.util.List