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]