From d43c95d623148e1367eb6e31ceb34167a86b9eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Westk=C3=A4mper?= Date: Thu, 15 Apr 2010 17:32:58 +0000 Subject: [PATCH] added support for constants in Evaluator --- .../java/com/mysema/codegen/ClassUtils.java | 14 +++++++ .../com/mysema/codegen/EvaluatorFactory.java | 42 +++++++++++++++---- .../mysema/codegen/EvaluatorFactoryTest.java | 29 +++++++++---- 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/mysema/codegen/ClassUtils.java b/src/main/java/com/mysema/codegen/ClassUtils.java index 15a726ac1..08744dbfb 100644 --- a/src/main/java/com/mysema/codegen/ClassUtils.java +++ b/src/main/java/com/mysema/codegen/ClassUtils.java @@ -5,7 +5,9 @@ */ package com.mysema.codegen; +import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Set; /** @@ -27,6 +29,18 @@ public final class ClassUtils { return cl.getName().replace('$', '.'); } } + + public static Class normalize(Class clazz){ + if (List.class.isAssignableFrom(clazz)){ + return List.class; + }else if (Set.class.isAssignableFrom(clazz)){ + return Set.class; + }else if (Collection.class.isAssignableFrom(clazz)){ + return Collection.class; + }else{ + return clazz; + } + } private ClassUtils(){} } diff --git a/src/main/java/com/mysema/codegen/EvaluatorFactory.java b/src/main/java/com/mysema/codegen/EvaluatorFactory.java index 48b2d2945..a3130d5da 100644 --- a/src/main/java/com/mysema/codegen/EvaluatorFactory.java +++ b/src/main/java/com/mysema/codegen/EvaluatorFactory.java @@ -9,12 +9,14 @@ 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.InvocationTargetException; import java.lang.reflect.Method; 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.SimpleJavaFileObject; @@ -54,7 +56,7 @@ public class EvaluatorFactory { } private void compile(String source, Class projectionType, - String[] names, Class[] types, String id) throws IOException { + String[] names, Class[] types, String id, Map constants) throws IOException { // create source StringWriter writer = new StringWriter(); JavaWriter javaw = new JavaWriter(writer); @@ -63,8 +65,17 @@ public class EvaluatorFactory { for (int i = 0; i < params.length; i++) { params[i] = ClassUtils.getName(types[i]) + " " + names[i]; } + + for (Map.Entry entry : constants.entrySet()){ + String className = ClassUtils.getName(ClassUtils.normalize(entry.getValue().getClass())); + javaw.publicField(className, entry.getKey()); + } - javaw.beginStaticMethod(ClassUtils.getName(projectionType), "eval", params); + if (constants.isEmpty()){ + javaw.beginStaticMethod(ClassUtils.getName(projectionType), "eval", params); + }else{ + javaw.beginPublicMethod(ClassUtils.getName(projectionType), "eval", params); + } javaw.line("return ", source, ";"); javaw.end(); javaw.end(); @@ -94,10 +105,14 @@ public class EvaluatorFactory { * @param projectionType 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, - final Class projectionType, String[] names, Class[] types) { + public Evaluator createEvaluator( + String source, + final Class projectionType, + String[] names, Class[] types, + Map constants) { try { String id = toId(source, projectionType, types); @@ -105,10 +120,17 @@ public class EvaluatorFactory { try{ clazz = loader.loadClass(id); }catch(ClassNotFoundException e){ - compile(source, projectionType, names, types, id); + compile(source, projectionType, names, types, id, constants); // reload clazz = loader.loadClass(id); } + + final Object object = !constants.isEmpty() ? clazz.newInstance() : null; + + for (Map.Entry entry : constants.entrySet()){ + Field field = clazz.getField(entry.getKey()); + field.set(object, entry.getValue()); + } final Method method = clazz.getMethod("eval", types); return new Evaluator() { @@ -116,7 +138,7 @@ public class EvaluatorFactory { @Override public T evaluate(Object... args) { try { - return (T) method.invoke(null, args); + return (T) method.invoke(object, args); } catch (IllegalAccessException e) { throw new IllegalArgumentException(e); } catch (InvocationTargetException e) { @@ -135,14 +157,20 @@ public class EvaluatorFactory { 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, Class... types) { StringBuilder b = new StringBuilder("Q"); b.append("_").append(source.hashCode()); diff --git a/src/test/java/com/mysema/codegen/EvaluatorFactoryTest.java b/src/test/java/com/mysema/codegen/EvaluatorFactoryTest.java index e8882bd0e..b71a5298b 100644 --- a/src/test/java/com/mysema/codegen/EvaluatorFactoryTest.java +++ b/src/test/java/com/mysema/codegen/EvaluatorFactoryTest.java @@ -5,11 +5,15 @@ */ package com.mysema.codegen; +import static org.junit.Assert.*; + import java.io.IOException; import java.net.URLClassLoader; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.junit.Assert; import org.junit.Before; @@ -50,11 +54,11 @@ public class EvaluatorFactoryTest { @Test public void testSimple(){ for (String expr : Arrays.asList("a.equals(b)", "a.startsWith(b)", "a.equalsIgnoreCase(b)")){ - test(expr, boolean.class, names, strings, Arrays.asList("a","b")); + evaluate(expr, boolean.class, names, strings, Arrays.asList("a","b"), Collections.emptyMap()); } for (String expr : Arrays.asList("a != b", "a < b", "a > b", "a <= b", "a >= b")){ - test(expr, boolean.class, names, ints, Arrays.asList(0,1)); + evaluate(expr, boolean.class, names, ints, Arrays.asList(0,1), Collections.emptyMap()); } } @@ -70,24 +74,35 @@ public class EvaluatorFactoryTest { test("a + b", int.class, names, ints, Arrays.asList(1,2), 3); } + @Test + public void testWithConstants(){ + Map constants = new HashMap(); + constants.put("x", "Hello World"); + List> types = Arrays.>asList(String.class); + List names = Arrays.asList("a"); + assertEquals(Boolean.TRUE, evaluate("a.equals(x)", boolean.class, names, types, Arrays.asList("Hello World"), constants)); + assertEquals(Boolean.FALSE, evaluate("a.equals(x)", boolean.class, names, types, Arrays.asList("Hello"), constants)); + } + @Test public void testCustomType(){ test("a.getName()", String.class, - Collections.singletonList("a"), Collections.singletonList(TestEntity.class), + Collections.singletonList("a"), Collections.>singletonList(TestEntity.class), 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, test(source, projectionType, names, types, args)); + 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 test(String source, Class projectionType, List names, List> types, List args) { + private Object evaluate(String source, Class projectionType, List names, List> types, List args, Map constants) { Evaluator evaluator = factory.createEvaluator( source, projectionType, names.toArray(new String[names.size()]), - types.toArray(new Class[types.size()])); + types.toArray(new Class[types.size()]), + constants); return evaluator.evaluate(args.toArray()); }