On 4/8/07, Henning P. Schmiedehausen <[EMAIL PROTECTED]> wrote:
[EMAIL PROTECTED] writes:

While I hope to grasp the intention of this patch; why can't you wrap
the Array into Arrays.asList(), which does turn an array into a fixed
size list?

i believe that would break $object.expectsArray($array)

        Best regards
                Henning



>Author: nbubna
>Date: Wed Apr  4 22:03:07 2007
>New Revision: 525698

>URL: http://svn.apache.org/viewvc?view=rev&rev=525698
>Log:
>VELTOOLS-533: initial support for treating arrays like fixed-size lists

>Added:
>    
velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/VelArrayMethod.java
   (with props)
>    
velocity/engine/trunk/src/test/org/apache/velocity/test/ArrayMethodsTestCase.java  
 (with props)
>Modified:
>    
velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java

>Modified: 
velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java
>URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java?view=diff&rev=525698&r1=525697&r2=525698
>==============================================================================
>--- 
velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java
 (original)
>+++ 
velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/UberspectImpl.java
 Wed Apr  4 22:03:07 2007
>@@ -163,8 +163,19 @@
>         }
>
>         Method m = introspector.getMethod(obj.getClass(), methodName, args);
>-
>-        return (m != null) ? new VelMethodImpl(m) : null;
>+        if (m != null)
>+        {
>+            return new VelMethodImpl(m);
>+        }
>+        else if (obj.getClass().isArray())
>+        {
>+            // only return *supported* array methods
>+            if (VelArrayMethod.supports(methodName, args))
>+            {
>+                return new VelArrayMethod(obj.getClass(), methodName, args);
>+            }
>+        }
>+        return null;
>     }
>
>     /**

>Added: 
velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/VelArrayMethod.java
>URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/VelArrayMethod.java?view=auto&rev=525698
>==============================================================================
>--- 
velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/VelArrayMethod.java
 (added)
>+++ 
velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/VelArrayMethod.java
 Wed Apr  4 22:03:07 2007
>@@ -0,0 +1,173 @@
>+package org.apache.velocity.util.introspection;
>+
>+/*
>+ * Copyright 2006 The Apache Software Foundation.
>+ *
>+ * Licensed 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
>+ *
>+ * 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.
>+ */
>+
>+import java.lang.reflect.Array;
>+import java.lang.reflect.InvocationTargetException;
>+import java.lang.reflect.Method;
>+import java.util.List;
>+
>+/**
>+ * Implementation of VelMethod to provide introspective "methods" for
>+ * arrays that match those that would work on a fixed-size [EMAIL PROTECTED] 
List}.
>+ * Currently only size(), isEmpty(), get(int), and set(int,Object) are
>+ * supported.  Later, support may be added for other read-only methods
>+ * such as contains(Object) or subList(int,int).  Patches are welcome! :)
>+ *
>+ * @author Nathan Bubna
>+ * @version $Id: VelArrayMethod.java 440740 2006-09-06 15:37:44Z nbubna $
>+ */
>+public class VelArrayMethod implements VelMethod
>+{
>+    public static String SIZE = "size";
>+    public static String IS_EMPTY = "isEmpty";
>+    public static String GET = "get";
>+    public static String SET = "set";
>+
>+    public static boolean supports(String methodName, Object[] params)
>+    {
>+        // quickest way to narrow things down is to switch
>+        // on the number of parameters
>+        switch (params.length)
>+        {
>+            case 0:
>+                // then they must be calling one of these
>+                return SIZE.equals(methodName) || IS_EMPTY.equals(methodName);
>+            case 1:
>+                // must be get() with a numeric param
>+                return GET.equals(methodName) && isNumeric(params[0]);
>+            case 2:
>+                // must be set() with a numeric first param
>+                return SET.equals(methodName) && isNumeric(params[0]);
>+            default:
>+                // it's not a supported method
>+                return false;
>+        }
>+    }
>+
>+    protected static boolean isNumeric(Object param)
>+    {
>+        if (param != null && Number.class.isAssignableFrom(param.getClass()))
>+        {
>+            return true;
>+        }
>+        //TODO? do we need to check for primitive number types?
>+        return false;
>+    }
>+
>+
>+    final Class arrayClass;
>+    final String methodName;
>+    final Object[] params;
>+
>+    public VelArrayMethod(Class arrayClass, String methodName, Object[] 
params)
>+    {
>+        this.methodName = methodName;
>+        this.params = params;
>+        this.arrayClass = arrayClass;
>+    }
>+
>+    protected int toInt(Object param)
>+    {
>+        return ((Number)param).intValue();
>+    }
>+
>+    public Object invoke(Object array, Object[] params) throws Exception
>+    {
>+        // quickest way to narrow things down is to switch
>+        // on the number of parameters
>+        switch (params.length)
>+        {
>+            // 0 params is either size() or isEmpty() (maybe iterator() 
someday)
>+            case 0:
>+                int length = Array.getLength(array);
>+                if (SIZE.equals(methodName))
>+                {
>+                    return new Integer(length);
>+                }
>+                if (IS_EMPTY.equals(methodName))
>+                {
>+                    return Boolean.valueOf(length == 0);
>+                }
>+
>+            // 1 param currently only could mean get() with a numeric param
>+            // it could mean contains(), indexOf(), etc someday
>+            case 1:
>+                try
>+                {
>+                    return Array.get(array, toInt(params[0]));
>+                }
>+                catch (RuntimeException re)
>+                {
>+                    throw new InvocationTargetException(re);
>+                }
>+
>+            // 2 params currently means set() with a numeric first param
>+            // it could later mean subList(int,int) too
>+            case 2:
>+                try
>+                {
>+                    int index = toInt(params[0]);
>+                    // get the old value to return it (like List does)
>+                    Object old = Array.get(array, index);
>+                    Array.set(array, index, params[1]);
>+                    return old;
>+                }
>+                catch (RuntimeException re)
>+                {
>+                    throw new InvocationTargetException(re);
>+                }
>+
>+            default:
>+                // if supports() was checked before creating this instance
>+                // then it should not be possible to get here
>+                throw new UnsupportedOperationException('\'' + methodName +
>+                                                        "' with " + 
params.length +
>+                                                        " parameters is not a 
supported array method");
>+        }
>+    }
>+
>+    public boolean isCacheable()
>+    {
>+        return true;
>+    }
>+
>+    public String getMethodName()
>+    {
>+        return methodName;
>+    }
>+
>+    public Class getReturnType()
>+    {
>+        if (SIZE.equals(methodName))
>+        {
>+            return int.class;
>+        }
>+        if (GET.equals(methodName) || SET.equals(methodName))
>+        {
>+            // should this be Object.class instead?
>+            return arrayClass.getComponentType();
>+        }
>+        if (IS_EMPTY.equals(methodName))
>+        {
>+            return boolean.class;
>+        }
>+        // not sure what else to do here
>+        return Object.class;
>+    }
>+
>+}

>Propchange: 
velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/VelArrayMethod.java
>------------------------------------------------------------------------------
>    svn:eol-style = native

>Propchange: 
velocity/engine/trunk/src/java/org/apache/velocity/util/introspection/VelArrayMethod.java
>------------------------------------------------------------------------------
>    svn:keywords = Revision

>Added: 
velocity/engine/trunk/src/test/org/apache/velocity/test/ArrayMethodsTestCase.java
>URL: 
http://svn.apache.org/viewvc/velocity/engine/trunk/src/test/org/apache/velocity/test/ArrayMethodsTestCase.java?view=auto&rev=525698
>==============================================================================
>--- 
velocity/engine/trunk/src/test/org/apache/velocity/test/ArrayMethodsTestCase.java 
(added)
>+++ 
velocity/engine/trunk/src/test/org/apache/velocity/test/ArrayMethodsTestCase.java 
Wed Apr  4 22:03:07 2007
>@@ -0,0 +1,231 @@
>+package org.apache.velocity.test;
>+
>+/*
>+ * 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
>+ *
>+ * 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.
>+ */
>+
>+import java.io.StringWriter;
>+import java.lang.reflect.Array;
>+import java.util.Arrays;
>+import java.util.ArrayList;
>+import java.util.List;
>+import junit.framework.Test;
>+import junit.framework.TestCase;
>+import junit.framework.TestSuite;
>+import org.apache.velocity.VelocityContext;
>+import org.apache.velocity.app.VelocityEngine;
>+import org.apache.velocity.runtime.RuntimeConstants;
>+import org.apache.velocity.runtime.log.SystemLogChute;
>+
>+/**
>+ * Used to check that method calls on Array references work properly
>+ * and that they produce the same results as the same methods would on
>+ * a fixed-size [EMAIL PROTECTED] List}.
>+ */
>+public class ArrayMethodsTestCase extends TestCase
>+{
>+    private VelocityEngine engine;
>+    private VelocityContext context;
>+
>+    private final static boolean PRINT_RESULTS = true;
>+
>+    public ArrayMethodsTestCase(final String name)
>+    {
>+        super(name);
>+    }
>+
>+    public void setUp() throws Exception
>+    {
>+        engine = new VelocityEngine();
>+
>+        // make the engine's log output go to the test-report
>+        SystemLogChute log = new SystemLogChute();
>+        log.setEnabledLevel(SystemLogChute.INFO_ID);
>+        log.setSystemErrLevel(SystemLogChute.WARN_ID);
>+        engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, log);
>+
>+        context = new VelocityContext();
>+    }
>+
>+    public void tearDown()
>+    {
>+        engine = null;
>+        context = null;
>+    }
>+
>+    public static Test suite ()
>+    {
>+        return new TestSuite(ArrayMethodsTestCase.class);
>+    }
>+
>+    /**
>+     * Runs the test.
>+     */
>+    public void testArrayMethods() throws Exception
>+    {
>+        // test an array of string objects
>+        Object array = new String[] { "foo", "bar", "baz" };
>+        checkResults(array, "woogie", true);
>+
>+        // test an array of primitive ints
>+        array = new int[] { 1, 3, 7 };
>+        checkResults(array, new Integer(11), false);
>+
>+        // test an array of mixed objects, including null
>+        array = new Object[] { new Double(2.2), null };
>+        checkResults(array, "whatever", true);
>+        // then set all the values to null
>+        checkResults(array, null, true);
>+
>+        // then try an empty array
>+        array = new Object[] {};
>+        checkResults(array, null, true);
>+
>+        // while we have an empty array and list in the context,
>+        // make sure $array.get(0) and $list.get(0) throw
>+        // the same type of exception (MethodInvocationException)
>+        Throwable lt = null;
>+        Throwable at = null;
>+        try
>+        {
>+            evaluate("$list.get(0)");
>+        }
>+        catch (Throwable t)
>+        {
>+            lt = t;
>+        }
>+        try
>+        {
>+            evaluate("$array.get(0)");
>+        }
>+        catch (Throwable t)
>+        {
>+            at = t;
>+        }
>+        assertEquals(lt.getClass(), at.getClass());
>+    }
>+
>+    private void checkResults(Object array, Object setme,
>+                              boolean compareToList) throws Exception
>+    {
>+        context.put("array", array);
>+        if (compareToList)
>+        {
>+            // create a list to match...
>+            context.put("list", new 
ArrayList(Arrays.asList((Object[])array)));
>+        }
>+
>+        // if the object to be set is null, then remove instead of put
>+        if (setme != null)
>+        {
>+            context.put("setme", setme);
>+        }
>+        else
>+        {
>+            context.remove("setme");
>+        }
>+
>+        if (PRINT_RESULTS)
>+        {
>+            System.out.println("Changing to an array of: " + 
array.getClass().getComponentType());
>+            System.out.println("Changing setme to: " + setme);
>+        }
>+
>+        int size = Array.getLength(array);
>+        checkResult("size()", String.valueOf(size), compareToList);
>+
>+        boolean isEmpty = (size == 0);
>+        checkResult("isEmpty()", String.valueOf(isEmpty), compareToList);
>+
>+        for (int i=0; i < size; i++)
>+        {
>+            // put the index in the context, so we can try
>+            // both an explicit index and a reference index
>+            context.put("index", new Integer(i));
>+
>+            Object value = Array.get(array, i);
>+            String get = "get($index)";
>+            String set = "set("+i+", $setme)";
>+            if (value == null)
>+            {
>+                checkEmptyResult(get, compareToList);
>+                // set should return null
>+                checkEmptyResult(set, compareToList);
>+            }
>+            else
>+            {
>+                checkResult(get, value.toString(), compareToList);
>+                // set should return the old get value
>+                checkResult(set, value.toString(), compareToList);
>+            }
>+
>+            // check that set() actually changed the value
>+            assertEquals(setme, Array.get(array, i));
>+
>+            // and check that get() now returns setme
>+            if (setme == null)
>+            {
>+                checkEmptyResult(get, compareToList);
>+            }
>+            else
>+            {
>+                checkResult(get, setme.toString(), compareToList);
>+            }
>+        }
>+    }
>+
>+    private void checkEmptyResult(String method, boolean compareToList)
>+        throws Exception
>+    {
>+        checkResult(method, "", compareToList);
>+    }
>+
>+    private void checkResult(String method, String expected,
>+                             boolean compareToList) throws Exception
>+    {
>+        String result = evaluate("$!array."+method);
>+        assertEquals(expected, result);
>+
>+        String listResult = null;
>+        if (compareToList)
>+        {
>+            listResult = evaluate("$!list."+method);
>+            assertEquals(result, listResult);
>+        }
>+
>+        if (PRINT_RESULTS)
>+        {
>+            System.out.println("    <$!array."+method+"> resolved to 
<"+result+">");
>+            if (compareToList)
>+            {
>+                System.out.println("    <$!list."+method+"> resolved to 
"+listResult+">");
>+            }
>+        }
>+    }
>+
>+    private String evaluate(String template) throws Exception
>+    {
>+        StringWriter writer = new StringWriter();
>+        // use template as its own name, since our templates are short
>+        engine.evaluate(context, writer, template, template);
>+        return writer.toString();
>+    }
>+
>+}
>+
>+

>Propchange: 
velocity/engine/trunk/src/test/org/apache/velocity/test/ArrayMethodsTestCase.java
>------------------------------------------------------------------------------
>    svn:eol-style = native

>Propchange: 
velocity/engine/trunk/src/test/org/apache/velocity/test/ArrayMethodsTestCase.java
>------------------------------------------------------------------------------
>    svn:keywords = Revision


--
Henning P. Schmiedehausen  -- [EMAIL PROTECTED] | J2EE, Linux,               
|gls
91054 Buckenhof, Germany   -- +49 9131 506540  | Apache person              |eau
Open Source Consulting, Development, Design    | Velocity - Turbine guy     |rwc
                                                                            |m k
INTERMETA - Gesellschaft fuer Mehrwertdienste mbH - RG Fuerth, HRB 7350     |a s
Sitz der Gesellschaft: Buckenhof. Geschaeftsfuehrer: Henning Schmiedehausen |n

               "Save the cheerleader. Save the world."

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to