You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by cb...@apache.org on 2019/04/18 15:08:25 UTC
svn commit: r1857758 -
/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/ModelUberspector.java
Author: cbrisson
Date: Thu Apr 18 15:08:25 2019
New Revision: 1857758
URL: http://svn.apache.org/viewvc?rev=1857758&view=rev
Log:
[tools/model] Initial import: ModelUberspector
Added:
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/ModelUberspector.java
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/ModelUberspector.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/ModelUberspector.java?rev=1857758&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/ModelUberspector.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/ModelUberspector.java Thu Apr 18 15:08:25 2019
@@ -0,0 +1,205 @@
+package org.apache.velocity.tools.model;
+
+import org.apache.velocity.tools.model.impl.AttributeHolder;
+import org.apache.velocity.util.introspection.AbstractChainableUberspector;
+import org.apache.velocity.util.introspection.Info;
+import org.apache.velocity.util.introspection.VelMethod;
+import org.apache.velocity.util.introspection.VelPropertyGet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * This uberspector allows getting a property while specifying extra external parameters
+ * to the property. It resolves calls that look like a method call, with one Map argument,
+ * but where the method name is in fact a property of the underlying object, which must implement
+ * the HasParapetrizedGetter interface.
+ *
+ * @see org.apache.velocity.util.introspection.Uberspect#getMethod(java.lang.Object, java.lang.String,
+ * java.lang.Object[], org.apache.velocity.util.introspection.Info)
+ */
+public class ModelUberspector extends AbstractChainableUberspector
+{
+ protected static Logger logger = LoggerFactory.getLogger(ModelUberspector.class);
+
+ @Override
+ public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i)
+ {
+ VelMethod ret = super.getMethod(obj, methodName, args, i);
+ if (ret == null)
+ {
+ try
+ {
+ if (obj instanceof ModelTool)
+ {
+ ret = getAttributeMethod(ModelTool.class, ((ModelTool)obj).getModel(), methodName, args);
+ }
+ else if (obj instanceof InstanceReference)
+ {
+ ret = getAttributeMethod(InstanceReference.class, ((InstanceReference)obj).getInstance().getEntity(), methodName, args);
+ }
+ }
+ catch(NoSuchMethodException e)
+ {
+ logger.trace("model uberspector failed", e);
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i)
+ {
+ VelPropertyGet ret = super.getPropertyGet(obj, identifier, i);
+ if (ret == null)
+ {
+ try
+ {
+ if (obj instanceof ModelTool)
+ {
+ ret = getAttributeGetter(ModelTool.class, ((ModelTool)obj).getModel(), identifier);
+ }
+ else if (obj instanceof InstanceReference)
+ {
+ ret = getAttributeGetter(InstanceReference.class, ((InstanceReference)obj).getInstance().getEntity(), identifier);
+ }
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ logger.trace("model uberspector failed",nsme);
+ }
+ }
+ return ret;
+ }
+
+ private VelMethod getAttributeMethod(Class targetClass, AttributeHolder attributeHolder, String attributeName, Object[] args) throws NoSuchMethodException
+ {
+ VelMethod ret = null;
+ Attribute attribute = attributeHolder.getAttribute(attributeName);
+ if (attribute != null)
+ {
+ Class[] classes;
+ boolean vararg;
+ if (args.length == 1 && args[0] instanceof Map)
+ {
+ vararg = false;
+ classes = new Class[] { String.class, Map.class };
+ }
+ else
+ {
+ vararg = true;
+ classes = new Class[] { String.class, Serializable[].class };
+ }
+ Method method = targetClass.getMethod(attribute.getQueryMethodName(), classes);
+ ret = new AttributeMethod(method, attributeName, vararg);
+
+ }
+ return ret;
+ }
+
+ private VelPropertyGet getAttributeGetter(Class targetClass, AttributeHolder attributeHolder, String attributeName) throws NoSuchMethodException
+ {
+ VelPropertyGet ret = null;
+ Attribute attribute = attributeHolder.getAttribute(attributeName);
+ if (attribute != null)
+ {
+ Class[] classes = new Class[] { String.class, Serializable[].class };
+ Method method = targetClass.getMethod(attribute.getQueryMethodName(), classes);
+ ret = new AttributeGetter(attributeName, method);
+
+ }
+ return ret;
+ }
+
+ public static class AttributeMethod implements VelMethod
+ {
+ private String property;
+ private Method method;
+ private boolean vararg;
+
+ public AttributeMethod(Method m, String p, boolean v)
+ {
+ property = p;
+ method = m;
+ vararg = v;
+ }
+
+ public Object invoke(Object obj, Object[] args)
+ {
+ Object ret= null;
+ try
+ {
+ Object[] arguments;
+ if (vararg)
+ {
+ arguments = new Object[] { property, args };
+ }
+ else
+ {
+ arguments = new Object[] { property, args[0] };
+ }
+ ret = method.invoke(obj, arguments);
+ }
+ catch(IllegalAccessException | InvocationTargetException e)
+ {
+ logger.error("attribute call failed", e);
+ }
+ return ret;
+ }
+
+ public boolean isCacheable()
+ {
+ return true;
+ }
+
+ public String getMethodName()
+ {
+ return method.getName();
+ }
+
+ public Class getReturnType()
+ {
+ return method.getReturnType();
+ }
+
+ public Method getMethod()
+ {
+ return method;
+ }
+ }
+
+ public static class AttributeGetter implements VelPropertyGet
+ {
+ private String property;
+ private Method method;
+
+ public AttributeGetter(String p, Method m)
+ {
+ property = p;
+ method = m;
+ }
+
+ @Override
+ public Object invoke(Object o) throws Exception
+ {
+ return method.invoke(o, property, new Serializable[0]);
+ }
+
+ @Override
+ public boolean isCacheable()
+ {
+ return true;
+ }
+
+ @Override
+ public String getMethodName()
+ {
+ return method.getName();
+ }
+ }
+
+}