You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by pr...@apache.org on 2007/10/12 07:14:39 UTC
svn commit: r584046 [2/2] - in
/commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util: ./
introspection/
Modified: commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java?rev=584046&r1=584045&r2=584046&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java (original)
+++ commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java Thu Oct 11 22:14:37 2007
@@ -17,33 +17,39 @@
package org.apache.commons.jexl.util.introspection;
+import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
-import java.util.Map;
import java.util.List;
+import java.util.Map;
import org.apache.commons.jexl.util.AbstractExecutor;
import org.apache.commons.jexl.util.ArrayIterator;
+import org.apache.commons.jexl.util.ArrayListWrapper;
import org.apache.commons.jexl.util.BooleanPropertyExecutor;
import org.apache.commons.jexl.util.EnumerationIterator;
import org.apache.commons.jexl.util.GetExecutor;
import org.apache.commons.jexl.util.PropertyExecutor;
+import org.apache.commons.jexl.util.MapGetExecutor;
import org.apache.commons.logging.Log;
/**
* Implementation of Uberspect to provide the default introspective
- * functionality of Velocity.
+ * functionality of Velocity
*
* @since 1.0
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
+ * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
* @version $Id$
*/
public class UberspectImpl implements Uberspect, UberspectLoggable {
- /** index of the first character of the property. */
+ /**
+ * index of the first character of the property.
+ */
private static final int PROPERTY_START_INDEX = 3;
/**
@@ -87,21 +93,39 @@
return ((Map) obj).values().iterator();
} else if (obj instanceof Iterator) {
rlog.warn("Warning! The iterative " + " is an Iterator in the #foreach() loop at [" + i.getLine() + ","
- + i.getColumn() + "]" + " in template " + i.getTemplateName() + ". Because it's not resetable,"
- + " if used in more than once, this may lead to" + " unexpected results.");
+ + i.getColumn() + "]" + " in template " + i.getTemplateName() + ". Because it's not resetable,"
+ + " if used in more than once, this may lead to" + " unexpected results.");
return ((Iterator) obj);
} else if (obj instanceof Enumeration) {
rlog.warn("Warning! The iterative " + " is an Enumeration in the #foreach() loop at [" + i.getLine() + ","
- + i.getColumn() + "]" + " in template " + i.getTemplateName() + ". Because it's not resetable,"
- + " if used in more than once, this may lead to" + " unexpected results.");
+ + i.getColumn() + "]" + " in template " + i.getTemplateName() + ". Because it's not resetable,"
+ + " if used in more than once, this may lead to" + " unexpected results.");
return new EnumerationIterator((Enumeration) obj);
+ } else {
+ // look for an iterator() method to support the JDK5 Iterable
+ // interface or any user tools/DTOs that want to work in
+ // foreach without implementing the Collection interface
+ Class type = obj.getClass();
+ try {
+ Method iter = type.getMethod("iterator", null);
+ Class returns = iter.getReturnType();
+ if (Iterator.class.isAssignableFrom(returns)) {
+ return (Iterator) iter.invoke(obj, null);
+ } else {
+ rlog.error("iterator() method of reference in #foreach loop at "
+ + i + " does not return a true Iterator.");
+ }
+ }
+ catch (NoSuchMethodException nsme) {
+ // eat this one, but let all other exceptions thru
+ }
}
- /* we have no clue what this is */
+ /* we have no clue what this is */
rlog.warn("Could not determine type of iterator in " + "#foreach loop " + " at [" + i.getLine() + ","
- + i.getColumn() + "]" + " in template " + i.getTemplateName());
+ + i.getColumn() + "]" + " in template " + i.getTemplateName());
return null;
}
@@ -115,7 +139,17 @@
}
Method m = introspector.getMethod(obj.getClass(), methodName, args);
- if (m == null && obj instanceof Class) {
+ if (m != null) {
+ return new VelMethodImpl(m);
+ } else if (obj.getClass().isArray()) {
+ // check for support via our array->list wrapper
+ m = introspector.getMethod(ArrayListWrapper.class, methodName, args);
+ if (m != null) {
+ // and create a method that knows to wrap the value
+ // before invoking the method
+ return new VelMethodImpl(m, true);
+ }
+ } else if (obj instanceof Class) {
m = introspector.getMethod((Class) obj, methodName, args);
}
@@ -137,9 +171,15 @@
executor = new PropertyExecutor(rlog, introspector, claz, identifier);
/*
- * look for boolean isFoo()
+ * Let's see if we are a map...
*/
+ if (!executor.isAlive()) {
+ executor = new MapGetExecutor(rlog, claz, identifier);
+ }
+ /*
+ * look for boolean isFoo()
+ */
if (!executor.isAlive()) {
executor = new BooleanPropertyExecutor(rlog, introspector, claz, identifier);
}
@@ -213,22 +253,40 @@
/**
* An implementation of {@link VelMethod}.
*/
- public class VelMethodImpl implements VelMethod {
- /** the method. */
- protected Method method = null;
+ public static class VelMethodImpl implements VelMethod {
+ final Method method;
+ Boolean isVarArg;
+ final boolean wrapArray;
+
/**
* Create a new instance.
*
* @param m the method.
*/
public VelMethodImpl(Method m) {
- method = m;
+ this(m, false);
+ }
+
+ public VelMethodImpl(Method method, boolean wrapArray) {
+ this.method = method;
+ this.wrapArray = wrapArray;
}
/**
* {@inheritDoc}
*/
public Object invoke(Object o, Object[] params) throws Exception {
+ if (isVarArg()) {
+ Class[] formal = method.getParameterTypes();
+ int index = formal.length - 1;
+ Class type = formal[index].getComponentType();
+ if (params.length >= index) {
+ params = handleVarArg(type, index, params);
+ }
+ } else if (wrapArray) {
+ o = new ArrayListWrapper(o);
+ }
+
try {
return method.invoke(o, params);
} catch (InvocationTargetException e) {
@@ -245,6 +303,74 @@
}
/**
+ * @returns true if this method can accept a variable number of arguments
+ */
+ public boolean isVarArg() {
+ if (isVarArg == null) {
+ Class[] formal = method.getParameterTypes();
+ if (formal == null || formal.length == 0) {
+ this.isVarArg = Boolean.FALSE;
+ } else {
+ Class last = formal[formal.length - 1];
+ // if the last arg is an array, then
+ // we consider this a varargs method
+ this.isVarArg = Boolean.valueOf(last.isArray());
+ }
+ }
+ return isVarArg.booleanValue();
+ }
+
+ /**
+ * @param type The vararg class type (aka component type
+ * of the expected array arg)
+ * @param index The index of the vararg in the method declaration
+ * (This will always be one less than the number of
+ * expected arguments.)
+ * @param actual The actual parameters being passed to this method
+ * @returns The actual parameters adjusted for the varargs in order
+ * to fit the method declaration.
+ */
+ private Object[] handleVarArg(Class type, int index, Object[] actual) {
+ // if no values are being passed into the vararg
+ if (actual.length == index) {
+ // create an empty array of the expected type
+ actual = new Object[]{Array.newInstance(type, 0)};
+ }
+ // if one value is being passed into the vararg
+ else if (actual.length == index + 1) {
+ // make sure the last arg is an array of the expected type
+ if (IntrospectionUtils.isMethodInvocationConvertible(type,
+ actual[index].getClass(),
+ false)) {
+ // create a 1-length array to hold and replace the last param
+ Object lastActual = Array.newInstance(type, 1);
+ Array.set(lastActual, 0, actual[index]);
+ actual[index] = lastActual;
+ }
+ }
+ // if multiple values are being passed into the vararg
+ else if (actual.length > index + 1) {
+ // put the last and extra actual in an array of the expected type
+ int size = actual.length - index;
+ Object lastActual = Array.newInstance(type, size);
+ for (int i = 0; i < size; i++) {
+ Array.set(lastActual, i, actual[index + i]);
+ }
+
+ // put all into a new actual array of the appropriate size
+ Object[] newActual = new Object[index + 1];
+ for (int i = 0; i < index; i++) {
+ newActual[i] = actual[i];
+ }
+ newActual[index] = lastActual;
+
+ // replace the old actual array
+ actual = newActual;
+ }
+ return actual;
+ }
+
+ /**
* {@inheritDoc}
*/
public boolean isCacheable() {
@@ -270,12 +396,15 @@
* {@inheritDoc}
*/
public static class VelGetterImpl implements VelPropertyGet {
- /** executor for performing the get. */
- protected AbstractExecutor ae = null;
+ /**
+ * executor for performing the get.
+ */
+ protected final AbstractExecutor ae;
/**
* Create the getter using an {@link AbstractExecutor} to
* do the work.
+ *
* @param exec the executor.
*/
public VelGetterImpl(AbstractExecutor exec) {
@@ -299,13 +428,6 @@
/**
* {@inheritDoc}
*/
- public boolean isAlive() {
- return ae.isAlive();
- }
-
- /**
- * {@inheritDoc}
- */
public String getMethodName() {
return ae.getMethod().getName();
}
@@ -314,14 +436,19 @@
/**
* {@inheritDoc}
*/
- public class VelSetterImpl implements VelPropertySet {
- /** the method to call. */
+ public static class VelSetterImpl implements VelPropertySet {
+ /**
+ * the method to call.
+ */
protected VelMethod vm = null;
- /** the key for indexed and other properties. */
+ /**
+ * the key for indexed and other properties.
+ */
protected String putKey = null;
/**
* Create an instance.
+ *
* @param velmethod the method to call on set.
*/
public VelSetterImpl(VelMethod velmethod) {
@@ -330,16 +457,19 @@
/**
* Create an instance.
+ *
* @param velmethod the method to call on set.
- * @param key the index or other value passed to a
- * setProperty(xxx, value) method.
+ * @param key the index or other value passed to a
+ * setProperty(xxx, value) method.
*/
public VelSetterImpl(VelMethod velmethod, String key) {
this.vm = velmethod;
putKey = key;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
public Object invoke(Object o, Object value) throws Exception {
List al = new ArrayList();
@@ -353,12 +483,16 @@
return vm.invoke(o, al.toArray());
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
public boolean isCacheable() {
return true;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ */
public String getMethodName() {
return vm.getMethodName();
}
Modified: commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelMethod.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelMethod.java?rev=584046&r1=584045&r2=584046&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelMethod.java (original)
+++ commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelMethod.java Thu Oct 11 22:14:37 2007
@@ -1,61 +1,63 @@
+package org.apache.commons.jexl.util.introspection;
+
/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
*/
-package org.apache.commons.jexl.util.introspection;
-
/**
- * Method used for regular method invocation.
- *
- * $foo.bar()
- *
- *
- * @since 1.0
+ * Method used for regular method invocation
+ *
+ * $foo.bar()
+ *
+ *
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @version $Id$
*/
-public interface VelMethod {
+public interface VelMethod
+{
/**
- * invocation method - called when the method invocation should be performed
- * and a value returned.
-
- * @param o the object
- * @param params method parameters.
- * @return the result
- * @throws Exception on any error.
+ * invocation method - called when the method invocation should be
+ * performed and a value returned
+ * @param o
+ * @param params
+ * @return The resulting object.
+ * @throws Exception
*/
- Object invoke(Object o, Object[] params) throws Exception;
+ public Object invoke(Object o, Object[] params)
+ throws Exception;
/**
- * specifies if this VelMethod is cacheable and able to be reused for this
- * class of object it was returned for.
- *
- * @return true if can be reused for this class, false if not
+ * specifies if this VelMethod is cacheable and able to be
+ * reused for this class of object it was returned for
+ *
+ * @return true if can be reused for this class, false if not
*/
- boolean isCacheable();
+ public boolean isCacheable();
/**
- * Gets the method name used.
- * @return method name
+ * returns the method name used
+ * @return The method name used
*/
- String getMethodName();
+ public String getMethodName();
/**
- * returns the return type of the method invoked.
- * @return return type
+ * returns the return type of the method invoked
+ * @return The return type of the method invoked
*/
- Class getReturnType();
+ public Class getReturnType();
}
Modified: commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelPropertyGet.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelPropertyGet.java?rev=584046&r1=584045&r2=584046&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelPropertyGet.java (original)
+++ commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelPropertyGet.java Thu Oct 11 22:14:37 2007
@@ -1,61 +1,55 @@
+package org.apache.commons.jexl.util.introspection;
+
/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
*/
-package org.apache.commons.jexl.util.introspection;
-
/**
- * Interface defining a 'getter'. For uses when looking for resolution of
- * property references
+ * Interface defining a 'getter'. For uses when looking for resolution of
+ * property references
*
- * $foo.bar
+ * $foo.bar
*
- * @since 1.0
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @version $Id$
*/
-public interface VelPropertyGet {
+public interface VelPropertyGet
+{
/**
- * invocation method - called when the 'get action' should be performed and
- * a value returned.
- * @param o the object to get the property from.
- * @return the property value.
- * @throws Exception on any error.
+ * invocation method - called when the 'get action' should be
+ * preformed and a value returned
+ * @param o
+ * @return The resulting Object.
+ * @throws Exception
*/
- Object invoke(Object o) throws Exception;
+ public Object invoke(Object o) throws Exception;
/**
- * specifies if this VelPropertyGet is cacheable and able to be reused for
- * this class of object it was returned for.
+ * specifies if this VelPropertyGet is cacheable and able to be
+ * reused for this class of object it was returned for
*
- * @return true if can be reused for this class, false if not
+ * @return true if can be reused for this class, false if not
*/
- boolean isCacheable();
+ public boolean isCacheable();
/**
- * returns the method name used to return this 'property'.
- * @return the method name.
- */
- String getMethodName();
-
- /**
- * Tell whether the method underlying this 'property' is alive by
- * checking to see if represents a successful name resolution.
- *
- * @return boolean Whether 'property' is alive.
+ * returns the method name used to return this 'property'
+ * @return The method name used to return this 'property'
*/
- boolean isAlive();
+ public String getMethodName();
}
Modified: commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelPropertySet.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelPropertySet.java?rev=584046&r1=584045&r2=584046&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelPropertySet.java (original)
+++ commons/proper/jexl/trunk/src/java/org/apache/commons/jexl/util/introspection/VelPropertySet.java Thu Oct 11 22:14:37 2007
@@ -22,7 +22,7 @@
* Ex.
*
* #set($foo.bar = "hello")
- *
+ *
* @since 1.0
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @version $Id$
@@ -30,7 +30,7 @@
public interface VelPropertySet {
/**
* method used to set the value in the object.
- *
+ *
* @param o Object on which the method will be called with the arg
* @param arg value to be set
* @return the value returned from the set operation (impl specific)
@@ -41,7 +41,7 @@
/**
* specifies if this VelPropertySet is cacheable and able to be reused for
* this class of object it was returned for.
- *
+ *
* @return true if can be reused for this class, false if not
*/
boolean isCacheable();