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();