diff --git a/pom.xml b/pom.xml
index d45bafea9..5ebfb2439 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.mysema.codegen
codegen
- 0.1.2-SNAPSHOT
+ 0.1.3
Codegen
Code generation and compilation for Java
diff --git a/src/main/java/com/mysema/codegen/ClassUtils.java b/src/main/java/com/mysema/codegen/ClassUtils.java
index 27445c32e..b5581dae3 100644
--- a/src/main/java/com/mysema/codegen/ClassUtils.java
+++ b/src/main/java/com/mysema/codegen/ClassUtils.java
@@ -31,6 +31,30 @@ public final class ClassUtils {
}
}
+ public static String getName(Type> cl){
+ return getName(cl, Collections.singleton(Object.class.getPackage()), Collections.>emptySet());
+ }
+
+ public static String getName(Type> type, Set packages, Set> classes){
+ if (type.getParameters().isEmpty()){
+ return getName(type.getJavaClass(), packages, classes);
+ }else{
+ StringBuilder builder = new StringBuilder();
+ builder.append(getName(type.getJavaClass(), packages, classes));
+ builder.append("<");
+ boolean first = true;
+ for (Type> parameter : type.getParameters()){
+ builder.append(getName(parameter, packages, classes));
+ if (!first){
+ builder.append(",");
+ }
+ first = false;
+ }
+ builder.append(">");
+ return builder.toString();
+ }
+ }
+
public static Class> normalize(Class> clazz){
if (List.class.isAssignableFrom(clazz)){
return List.class;
diff --git a/src/main/java/com/mysema/codegen/EvaluatorFactory.java b/src/main/java/com/mysema/codegen/EvaluatorFactory.java
index 8dcfeda65..d1c379fd4 100644
--- a/src/main/java/com/mysema/codegen/EvaluatorFactory.java
+++ b/src/main/java/com/mysema/codegen/EvaluatorFactory.java
@@ -54,8 +54,8 @@ public class EvaluatorFactory {
this.compilationOptions = Arrays.asList("-classpath", classpath, "-g:none");
}
- private void compile(String source, Class> projectionType,
- String[] names, Class>[] types, String id, Map constants) throws IOException {
+ 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);
@@ -75,7 +75,7 @@ public class EvaluatorFactory {
}else{
javaw.beginPublicMethod(ClassUtils.getName(projectionType), "eval", params);
}
- javaw.line("return ", source, ";");
+ javaw.append(source);
javaw.end();
javaw.end();
@@ -95,34 +95,46 @@ public class EvaluatorFactory {
}
}
+
+ @SuppressWarnings("unchecked")
+ 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 Type(classes[i]);
+ }
+ return createEvaluator(source, new Type(projectionType), names, types, classes, constants);
+ }
/**
* Create a new Evaluator instance
*
* @param projection type
* @param source expression in Java source code form
- * @param projectionType type of the source expression
+ * @param projection type of the source expression
* @param names names of the arguments
* @param types types of the arguments
* @param constants
* @return
*/
public Evaluator createEvaluator(
- String source,
- // TODO : support for generic projection types
- Class extends T> projectionType,
- String[] names,
- // TODO : support for generic argument type
- Class>[] types,
- Map constants) {
-
+ String source,
+ Type extends T> projection,
+ String[] names,
+ Type>[] types,
+ Class>[] classes,
+ Map constants) {
try {
- String id = toId(source, projectionType, types);
+ String id = toId(source, projection, types);
Class> clazz;
try{
clazz = loader.loadClass(id);
}catch(ClassNotFoundException e){
- compile(source, projectionType, names, types, id, constants);
+ compile(source, projection, names, types, id, constants);
// reload
clazz = loader.loadClass(id);
}
@@ -134,8 +146,8 @@ public class EvaluatorFactory {
field.set(object, entry.getValue());
}
- Method method = clazz.getMethod("eval", types);
- return new MethodEvaluator(method, object, projectionType);
+ Method method = clazz.getMethod("eval", classes);
+ return new MethodEvaluator(method, object, projection.getJavaClass());
} catch (ClassNotFoundException e) {
throw new CodegenException(e);
} catch (SecurityException e) {
@@ -156,11 +168,11 @@ public class EvaluatorFactory {
}
- protected String toId(String source, Class> returnType, Class>... types) {
+ protected String toId(String source, Type> returnType, Type>... types) {
StringBuilder b = new StringBuilder("Q");
b.append("_").append(source.hashCode());
b.append("_").append(returnType.getName().hashCode());
- for (Class> type : types) {
+ for (Type> type : types) {
b.append("_").append(type.getName().hashCode());
}
return b.toString().replace('-', '0');
diff --git a/src/main/java/com/mysema/codegen/Type.java b/src/main/java/com/mysema/codegen/Type.java
new file mode 100644
index 000000000..2db342dab
--- /dev/null
+++ b/src/main/java/com/mysema/codegen/Type.java
@@ -0,0 +1,57 @@
+package com.mysema.codegen;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Type represents a generic type used in code generation
+ *
+ * @author tiwe
+ *
+ * @param
+ */
+public class Type {
+
+ private final Class javaClass;
+
+ private final List> parameters;
+
+ public Type(Class javaClass, List> parameters) {
+ this.javaClass = javaClass;
+ this.parameters = parameters;
+ }
+
+ public Type(Class clazz, Type>... parameters) {
+ this(clazz, Arrays.asList(parameters));
+ }
+
+ public Class getJavaClass() {
+ return javaClass;
+ }
+
+ public List> getParameters() {
+ return parameters;
+ }
+
+ public String getName() {
+ return javaClass.getName();
+ }
+
+ @Override
+ public int hashCode(){
+ return javaClass.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o){
+ if (o == this){
+ return true;
+ }else if (o instanceof Type>){
+ Type> t = (Type>)o;
+ return t.javaClass.equals(javaClass) && t.parameters.equals(parameters);
+ }else{
+ return false;
+ }
+ }
+
+}
diff --git a/src/test/java/com/mysema/codegen/ComplexEvaluationTest.java b/src/test/java/com/mysema/codegen/ComplexEvaluationTest.java
new file mode 100644
index 000000000..84aaf5ab5
--- /dev/null
+++ b/src/test/java/com/mysema/codegen/ComplexEvaluationTest.java
@@ -0,0 +1,45 @@
+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;
+
+import org.junit.Test;
+
+public class ComplexEvaluationTest {
+
+ private EvaluatorFactory factory = new EvaluatorFactory((URLClassLoader) getClass().getClassLoader());
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testComplex(){Type stringType = new Type(String.class);
+ Type resultType = new Type(List.class, stringType);
+ StringBuilder source = new StringBuilder();
+ source.append("java.util.List rv = new java.util.ArrayList();\n");
+ source.append("for (String a : a_){\n");
+ source.append(" for (String b : b_){\n");
+ source.append(" if (a.equals(b)){\n");
+ source.append(" rv.add(a);\n");
+ source.append(" }\n");
+ source.append(" }\n");
+ source.append("}\n");
+ source.append("return rv;");
+
+ Evaluator evaluator = factory.createEvaluator(
+ source.toString(),
+ resultType,
+ new String[]{"a_","b_"},
+ new Type[]{resultType, resultType},
+ new Class[]{List.class,List.class},
+ Collections.emptyMap());
+
+ List a_ = Arrays.asList("1","2","3","4");
+ List b_ = Arrays.asList("2","4","6","8");
+
+ assertEquals(Arrays.asList("2","4"), evaluator.evaluate(a_, b_));
+ }
+
+}
diff --git a/src/test/java/com/mysema/codegen/EvaluatorFactoryTest.java b/src/test/java/com/mysema/codegen/EvaluatorFactoryTest.java
index cc77d5fea..2d0970251 100644
--- a/src/test/java/com/mysema/codegen/EvaluatorFactoryTest.java
+++ b/src/test/java/com/mysema/codegen/EvaluatorFactoryTest.java
@@ -5,7 +5,7 @@
*/
package com.mysema.codegen;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.net.URLClassLoader;
@@ -94,22 +94,23 @@ public class EvaluatorFactoryTest {
public void testCustomType(){
test("a.getName()", String.class,
Collections.singletonList("a"), Collections.>singletonList(TestEntity.class),
- Arrays.asList(new TestEntity("Hello World")), "Hello World");
-
+ Arrays.asList(new TestEntity("Hello World")), "Hello World");
}
-
+
private void test(String source, Class> projectionType, List names, List> types, List> args, Object expectedResult){
Assert.assertEquals(expectedResult, evaluate(source, projectionType, names, types, args, Collections.emptyMap()));
}
private Object evaluate(String source, Class> projectionType, List names, List> types, List> args, Map constants) {
Evaluator> evaluator = factory.createEvaluator(
- source,
+ "return " + source + ";",
projectionType,
names.toArray(new String[names.size()]),
types.toArray(new Class[types.size()]),
constants);
return evaluator.evaluate(args.toArray());
}
+
+
}