Author: byron
Date: Fri Jan 2 06:55:14 2009
New Revision: 730745
URL: http://svn.apache.org/viewvc?rev=730745&view=rev
Log:
VELOCITY-406 Add handling negative values in index values , to access from the
end of the foo
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTIndex.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SimpleNode.java
velocity/engine/trunk/src/java/org/apache/velocity/util/ClassUtils.java
velocity/engine/trunk/src/test/org/apache/velocity/test/IndexTestCase.java
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTIndex.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTIndex.java?rev=730745&r1=730744&r2=730745&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTIndex.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTIndex.java
Fri Jan 2 06:55:14 2009
@@ -64,15 +64,78 @@
return data;
}
+
+
+ private final static Object[] noParams = {};
+ private final static Class[] noTypes = {};
+ /**
+ * If argument is an Integer and negative, then return (o.size() -
argument).
+ * Otherwise return the original argument. We use this to calculate the
true
+ * index of a negative index e.g., $foo[-1]. If no size() method is found
on the
+ * 'o' object, then we throw an VelocityException.
+ * @param context Used to access the method cache.
+ * @param node ASTNode used for error reporting.
+ */
+ public static Object adjMinusIndexArg(Object argument, Object o,
+ InternalContextAdapter context, SimpleNode node)
+ {
+ if (argument instanceof Integer && ((Integer)argument).intValue() < 0)
+ {
+ // The index value is a negative number, $foo[-1], so we want to
actually
+ // Index [size - value], so try and call the size method.
+ VelMethod method = ClassUtils.getMethod("size", noParams, noTypes,
+ o, context, node, false);
+ if (method == null)
+ {
+ // The object doesn't have a size method, so there is no notion
of "at the end"
+ throw new VelocityException(
+ "A 'size()' method required for negative value "
+ + ((Integer)argument).intValue() + " does not exist for class
'"
+ + o.getClass().getName() + "' at " +
Log.formatFileString(node));
+ }
+
+ Object size = null;
+ try
+ {
+ size = method.invoke(o, noParams);
+ }
+ catch (Exception e)
+ {
+ throw new VelocityException("Error trying to calls the 'size()'
method on '"
+ + o.getClass().getName() + "' at " +
Log.formatFileString(node), e);
+ }
+
+ int sizeint = 0;
+ try
+ {
+ sizeint = ((Integer)size).intValue();
+ }
+ catch (ClassCastException e)
+ {
+ // If size() doesn't return an Integer we want to report a
pretty error
+ throw new VelocityException("Method 'size()' on class '"
+ + o.getClass().getName() + "' returned '" +
size.getClass().getName()
+ + "' when Integer was expected at " +
Log.formatFileString(node));
+ }
+
+ argument = new Integer(sizeint + ((Integer)argument).intValue());
+ }
+
+ // Nothing to do, return the original argument
+ return argument;
+ }
+
public Object execute(Object o, InternalContextAdapter context)
throws MethodInvocationException
{
Object argument = jjtGetChild(0).value(context);
+ // If negative, turn -1 into size - 1
+ argument = adjMinusIndexArg(argument, o, context, this);
Object [] params = {argument};
Class[] paramClasses = {argument == null ? null : argument.getClass()};
VelMethod method = ClassUtils.getMethod(methodName, params,
paramClasses,
- o, context, this, rsvc,
strictRef);
+ o, context, this, strictRef);
if (method == null) return null;
@@ -109,7 +172,7 @@
{
String msg = "Error invoking method 'get("
+ (argument == null ? "null" : argument.getClass().getName())
- + ")' in " + o.getClass()
+ + ")' in " + o.getClass().getName()
+ " at " + Log.formatFileString(this);
log.error(msg, e);
throw new VelocityException(msg, e);
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java?rev=730745&r1=730744&r2=730745&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
Fri Jan 2 06:55:14 2009
@@ -156,7 +156,7 @@
}
VelMethod method = ClassUtils.getMethod(methodName, params,
paramClasses,
- o, context, this, rsvc, strictRef);
+ o, context, this, strictRef);
if (method == null) return null;
try
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java?rev=730745&r1=730744&r2=730745&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
Fri Jan 2 06:55:14 2009
@@ -570,7 +570,10 @@
// the first parameter is the index value and the second is the
LHS of the set.
String methodName = "put";
- Object [] params = {astIndex.jjtGetChild(0).value(context), value};
+ Object argument = astIndex.jjtGetChild(0).value(context);
+ // If negative, turn -1 into (size - 1)
+ argument = ASTIndex.adjMinusIndexArg(argument, result, context,
astIndex);
+ Object [] params = {argument, value};
Class[] paramClasses = {params[0] == null ? null :
params[0].getClass(),
params[1] == null ? null :
params[1].getClass()};
if (params[0] instanceof Integer)
@@ -582,7 +585,7 @@
}
VelMethod method = ClassUtils.getMethod(methodName, params,
paramClasses,
- result, context, astIndex, rsvc, strictRef);
+ result, context, astIndex, strictRef);
if (method == null) return false;
try
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SimpleNode.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SimpleNode.java?rev=730745&r1=730744&r2=730745&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SimpleNode.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/SimpleNode.java
Fri Jan 2 06:55:14 2009
@@ -76,6 +76,12 @@
protected String templateName;
+
+ public RuntimeServices getRuntimeServices()
+ {
+ return rsvc;
+ }
+
/**
* @param i
*/
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/util/ClassUtils.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/util/ClassUtils.java?rev=730745&r1=730744&r2=730745&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/util/ClassUtils.java
(original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/util/ClassUtils.java Fri
Jan 2 06:55:14 2009
@@ -167,16 +167,14 @@
* @param o Object to introspect for the given method.
* @param context Context from which the method cache is aquirred
* @param node ASTNode, used for error reporting.
- * @param rsvc RuntimeServices used to retrieve the current Uberspector.
* @param strictRef If no method is found, throw an exception, never return
null in this case
* @return VelMethod object if the object is found, null if not matching
method is found
*/
public static VelMethod getMethod(String methodName, Object[] params,
Class[] paramClasses, Object o,
InternalContextAdapter context,
- SimpleNode node, RuntimeServices rsvc,
boolean strictRef)
+ SimpleNode node, boolean strictRef)
{
VelMethod method = null;
-
try
{
/*
@@ -202,7 +200,7 @@
/*
* otherwise, do the introspection, and then cache it
*/
- method = rsvc.getUberspect().getMethod(o, methodName, params,
+ method = node.getRuntimeServices().getUberspect().getMethod(o,
methodName, params,
new Info(node.getTemplateName(), node.getLine(), node.getColumn()));
if ((method != null) && (o != null))
Modified:
velocity/engine/trunk/src/test/org/apache/velocity/test/IndexTestCase.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/test/org/apache/velocity/test/IndexTestCase.java?rev=730745&r1=730744&r2=730745&view=diff
==============================================================================
--- velocity/engine/trunk/src/test/org/apache/velocity/test/IndexTestCase.java
(original)
+++ velocity/engine/trunk/src/test/org/apache/velocity/test/IndexTestCase.java
Fri Jan 2 06:55:14 2009
@@ -87,6 +87,8 @@
assertEvalEquals("BIG TRUE BIG FALSE", "$foo[true] $foo[false]");
assertEvalEquals("junk foobar ", "$foo[\"junk\"]");
assertEvalEquals("GOT NULL", "#set($i=$NULL)$boo[$i]");
+
+ assertEvalEquals("3", "$a[-1]");
}
public void testIndexSetting()
@@ -97,6 +99,7 @@
assertEvalEquals("orange","#set($blaa =
{\"apple\":\"grape\"})#set($blaa[\"apple\"] = \"orange\")$blaa[\"apple\"]");
assertEvalEquals("null","#set($str[0] = $NULL)#if($str[0] ==
$NULL)null#end");
assertEvalEquals("null","#set($blaa =
{\"apple\":\"grape\"})#set($blaa[\"apple\"] = $NULL)#if($blaa[\"apple\"] ==
$NULL)null#end");
+ assertEvalEquals("2112", "#set($a[-1] = 2112)$a[2]");
}
@@ -107,6 +110,7 @@
// Need to fix parse error reporting
// assertEvalExceptionAt("$boo[blaa]", 1, 6);
assertEvalExceptionAt("#set($foo[1] = 3)", 1, 10);
+ assertEvalExceptionAt("$a[500]", 1, 3);
}