Author: henrib Date: Wed Aug 24 15:11:15 2011 New Revision: 1161143 URL: http://svn.apache.org/viewvc?rev=1161143&view=rev Log: Constructors wrapping in JexlMethod; Allows to cache during interpretation and overload discovery related to constructor in Uberspect (for instance, using factories)
Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Uberspect.java commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java?rev=1161143&r1=1161142&r2=1161143&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java (original) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java Wed Aug 24 15:11:15 2011 @@ -16,7 +16,6 @@ */ package org.apache.commons.jexl2; -import java.lang.reflect.Constructor; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.util.Collection; @@ -335,10 +334,10 @@ public class Interpreter implements Pars // allow namespace to be instantiated as functor with context if possible, not an error otherwise if (namespace instanceof Class<?>) { Object[] args = new Object[]{context}; - Constructor<?> ctor = uberspect.getConstructor(namespace, args, node); + JexlMethod ctor = uberspect.getConstructor(namespace, args, node); if (ctor != null) { try { - namespace = ctor.newInstance(args); + namespace = ctor.invoke(namespace, args); if (functors == null) { functors = new HashMap<String, Object>(); } @@ -416,10 +415,9 @@ public class Interpreter implements Pars /** {@inheritDoc} */ public Object visit(ASTArrayAccess node, Object data) { - // first objectNode is the identifier + // first objectNode is the identifier Object object = node.jjtGetChild(0).jjtAccept(this, data); - // can have multiple nodes - either an expression, integer literal or - // reference + // can have multiple nodes - either an expression, integer literal or reference int numChildren = node.jjtGetNumChildren(); for (int i = 1; i < numChildren; i++) { JexlNode nindex = node.jjtGetChild(i); @@ -855,7 +853,7 @@ public class Interpreter implements Pars int n = 0; try { Object result = null; - /* first objectNode is the expression */ + /* first objectNode is the condition */ Object expression = node.jjtGetChild(0).jjtAccept(this, data); if (arithmetic.toBoolean(expression)) { // first objectNode is true statement @@ -1012,7 +1010,8 @@ public class Interpreter implements Pars } } if (xjexl == null) { - Object eval = vm.invoke(bean, argv); // vm cannot be null if xjexl is null + // vm cannot be null if xjexl is null + Object eval = vm.invoke(bean, argv); // cache executor in volatile JexlNode.value if (cacheable && vm.isCacheable()) { node.jjtSetValue(vm); @@ -1072,10 +1071,20 @@ public class Interpreter implements Pars } JexlException xjexl = null; - try { - Constructor<?> ctor = uberspect.getConstructor(cobject, argv, node); - // DG: If we can't find an exact match, narrow the parameters and - // try again! + try { + // attempt to reuse last constructor cached in volatile JexlNode.value + if (cache) { + Object cached = node.jjtGetValue(); + if (cached instanceof JexlMethod) { + JexlMethod mctor = (JexlMethod) cached; + Object eval = mctor.tryInvoke(null, cobject, argv); + if (!mctor.tryFailed(eval)) { + return eval; + } + } + } + JexlMethod ctor = uberspect.getConstructor(cobject, argv, node); + // DG: If we can't find an exact match, narrow the parameters and try again if (ctor == null) { if (arithmetic.narrowArguments(argv)) { ctor = uberspect.getConstructor(cobject, argv, node); @@ -1085,7 +1094,12 @@ public class Interpreter implements Pars } } if (xjexl == null) { - return ctor.newInstance(argv); + Object instance = ctor.invoke(cobject, argv); + // cache executor in volatile JexlNode.value + if (cache && ctor.isCacheable()) { + node.jjtSetValue(ctor); + } + return instance; } } catch (InvocationTargetException e) { xjexl = new JexlException(node, "constructor invocation error", e.getCause()); Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java?rev=1161143&r1=1161142&r2=1161143&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java (original) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java Wed Aug 24 15:11:15 2011 @@ -26,7 +26,6 @@ import java.io.Reader; import java.net.URL; import java.net.URLConnection; import java.lang.ref.SoftReference; -import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Map; import java.util.Set; @@ -725,12 +724,12 @@ public class JexlEngine { Object result = null; JexlInfo info = debugInfo(); try { - Constructor<?> ctor = uberspect.getConstructor(clazz, args, info); + JexlMethod ctor = uberspect.getConstructor(clazz, args, info); if (ctor == null && arithmetic.narrowArguments(args)) { ctor = uberspect.getConstructor(clazz, args, info); } if (ctor != null) { - result = ctor.newInstance(args); + result = ctor.invoke(clazz, args); } else { xjexl = new JexlException(info, "failed finding constructor for " + clazz.toString()); } Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Uberspect.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Uberspect.java?rev=1161143&r1=1161142&r2=1161143&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Uberspect.java (original) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/Uberspect.java Wed Aug 24 15:11:15 2011 @@ -18,7 +18,6 @@ package org.apache.commons.jexl2.introspection; import java.util.Iterator; -import java.lang.reflect.Constructor; import org.apache.commons.jexl2.JexlInfo; /** @@ -41,7 +40,7 @@ public interface Uberspect { * @param info contextual information * @return a {@link Constructor} */ - Constructor<?> getConstructor(Object ctorHandle, Object[] args, JexlInfo info); + JexlMethod getConstructor(Object ctorHandle, Object[] args, JexlInfo info); /** * Returns a JexlMethod. * @param obj the object Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java?rev=1161143&r1=1161142&r2=1161143&view=diff ============================================================================== --- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java (original) +++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java Wed Aug 24 15:11:15 2011 @@ -20,10 +20,12 @@ import org.apache.commons.jexl2.internal import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.lang.reflect.InvocationTargetException; + import java.util.Enumeration; import java.util.Iterator; - import java.util.Map; + import org.apache.commons.jexl2.JexlInfo; import org.apache.commons.jexl2.JexlException; import org.apache.commons.jexl2.internal.AbstractExecutor; @@ -44,7 +46,7 @@ public class UberspectImpl extends Intro * Publicly exposed special failure object returned by tryInvoke. */ public static final Object TRY_FAILED = AbstractExecutor.TRY_FAILED; - + /** * Creates a new UberspectImpl. * @param runtimeLogger the logger used for all logging needs @@ -52,7 +54,7 @@ public class UberspectImpl extends Intro public UberspectImpl(Log runtimeLogger) { super(runtimeLogger); } - + /** * Resets this Uberspect class loader. * @param cloader the class loader to use @@ -72,8 +74,8 @@ public class UberspectImpl extends Intro if (obj.getClass().isArray()) { return new ArrayIterator(obj); } - if (obj instanceof Map<?,?>) { - return ((Map<?,?>) obj).values().iterator(); + if (obj instanceof Map<?, ?>) { + return ((Map<?, ?>) obj).values().iterator(); } if (obj instanceof Enumeration<?>) { return new EnumerationIterator<Object>((Enumeration<Object>) obj); @@ -89,7 +91,7 @@ public class UberspectImpl extends Intro if (it != null && Iterator.class.isAssignableFrom(it.getReturnType())) { return (Iterator<Object>) it.execute(obj, null); } - } catch(Exception xany) { + } catch (Exception xany) { throw new JexlException(info, "unable to generate iterator()", xany); } return null; @@ -102,7 +104,7 @@ public class UberspectImpl extends Intro * @param info debug info * @return a {@link Field}. */ - public Field getField(Object obj, String name, JexlInfo info) { + protected Field getField(Object obj, String name, JexlInfo info) { final Class<?> clazz = obj instanceof Class<?> ? (Class<?>) obj : obj.getClass(); return getField(clazz, name); } @@ -110,8 +112,67 @@ public class UberspectImpl extends Intro /** * {@inheritDoc} */ - public Constructor<?> getConstructor(Object ctorHandle, Object[] args, JexlInfo info) { - return getConstructor(ctorHandle, args); + public JexlMethod getConstructor(Object ctorHandle, Object[] args, JexlInfo info) { + final Constructor<?> ctor = getConstructor(ctorHandle, args); + if (ctor != null) { + JexlMethod jctor = new JexlMethod() { + public Object invoke(Object obj, Object[] params) throws Exception { + Class<?> clazz = null; + if (obj instanceof Class<?>) { + clazz = (Class<?>) obj; + } else if (obj != null) { + clazz = base().getClassByName(obj.toString()); + } else { + clazz = ctor.getDeclaringClass(); + } + if (clazz.equals(ctor.getDeclaringClass())) { + return ctor.newInstance(params); + } else { + return null; + } + } + + public Object tryInvoke(String name, Object obj, Object[] params) { + Class<?> clazz = null; + if (obj instanceof Class<?>) { + clazz = (Class<?>) obj; + } else if (obj != null) { + clazz = base().getClassByName(obj.toString()); + } else { + clazz = ctor.getDeclaringClass(); + } + if (clazz.equals(ctor.getDeclaringClass()) + && (name == null || name.equals(clazz.getName()))) { + try { + return ctor.newInstance(params); + } catch (InstantiationException xinstance) { + return TRY_FAILED; + } catch (IllegalAccessException xaccess) { + return TRY_FAILED; + } catch (IllegalArgumentException xargument) { + return TRY_FAILED; + } catch (InvocationTargetException xinvoke) { + return TRY_FAILED; + } + } + return TRY_FAILED; + } + + public boolean tryFailed(Object rval) { + return rval == TRY_FAILED; + } + + public boolean isCacheable() { + return true; + } + + public Class<?> getReturnType() { + return ctor.getDeclaringClass(); + } + }; + return jctor; + } + return null; } /** @@ -218,8 +279,8 @@ public class UberspectImpl extends Intro */ public Object tryInvoke(Object obj, Object key, Object value) { if (obj.getClass().equals(field.getDeclaringClass()) - && key.equals(field.getName()) - && (value == null || MethodKey.isInvocationConvertible(field.getType(), value.getClass(), false))) { + && key.equals(field.getName()) + && (value == null || MethodKey.isInvocationConvertible(field.getType(), value.getClass(), false))) { try { field.set(obj, value); return value; @@ -253,8 +314,8 @@ public class UberspectImpl extends Intro if (set == null && obj != null && identifier != null) { Field field = getField(obj, identifier.toString(), info); if (field != null - && !Modifier.isFinal(field.getModifiers()) - && (arg == null || MethodKey.isInvocationConvertible(field.getType(), arg.getClass(), false))) { + && !Modifier.isFinal(field.getModifiers()) + && (arg == null || MethodKey.isInvocationConvertible(field.getType(), arg.getClass(), false))) { return new FieldPropertySet(field); } }