You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by nb...@apache.org on 2010/12/29 07:11:07 UTC
svn commit: r1053541 - in /velocity/engine/trunk/velocity-engine-core/src:
main/java/org/apache/velocity/runtime/directive/
main/java/org/apache/velocity/runtime/parser/node/
main/java/org/apache/velocity/util/ test/java/org/apache/velocity/test/
Author: nbubna
Date: Wed Dec 29 06:11:06 2010
New Revision: 1053541
URL: http://svn.apache.org/viewvc?rev=1053541&view=rev
Log:
Add better duck-typing support, make #if() false for 'empty' objects (VELOCITY-692), and refactor comparison nodes to remove gross amounts of duplicate code
Added:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java (with props)
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/DuckType.java (with props)
velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java (with props)
velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java (with props)
Modified:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Block.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTAddNode.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTEQNode.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTGENode.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTGTNode.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTLENode.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTLTNode.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMathNode.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNENode.java
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java
velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfNullTestCase.java
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Block.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Block.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Block.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Block.java Wed Dec 29 06:11:06 2010
@@ -163,6 +163,14 @@ public abstract class Block extends Dire
}
}
+ /**
+ * Makes #if( $blockRef ) true without rendering, so long as we aren't beyond max depth.
+ */
+ public boolean getAsBoolean()
+ {
+ return depth <= parent.maxDepth;
+ }
+
public String toString()
{
Writer writer = new StringWriter();
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTAddNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTAddNode.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTAddNode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTAddNode.java Wed Dec 29 06:11:06 2010
@@ -21,6 +21,7 @@ package org.apache.velocity.runtime.pars
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.runtime.parser.Parser;
+import org.apache.velocity.util.DuckType;
/**
* Handles number addition of nodes.<br><br>
@@ -53,23 +54,23 @@ public class ASTAddNode extends ASTMathN
super(p, id);
}
- //@Override
+ @Override
protected Object handleSpecial(Object left, Object right, InternalContextAdapter context)
{
- /*
- * shall we try for strings?
- */
- if (left instanceof String || right instanceof String)
+ // check for strings, but don't coerce
+ String lstr = DuckType.asString(left, false);
+ String rstr = DuckType.asString(right, false);
+ if (lstr != null || rstr != null)
{
- if (left == null)
+ if (lstr == null)
{
- left = jjtGetChild(0).literal();
+ lstr = left != null ? left.toString() : jjtGetChild(0).literal();
}
- else if (right == null)
+ else if (rstr == null)
{
- right = jjtGetChild(1).literal();
+ rstr = right != null ? right.toString() : jjtGetChild(1).literal();
}
- return left.toString().concat(right.toString());
+ return lstr.concat(rstr);
}
return null;
}
Added: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java?rev=1053541&view=auto
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java (added)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java Wed Dec 29 06:11:06 2010
@@ -0,0 +1,154 @@
+package org.apache.velocity.runtime.parser.node;
+
+/*
+ * 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 org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.log.Log;
+import org.apache.velocity.runtime.parser.Parser;
+import org.apache.velocity.util.DuckType;
+
+/**
+ * Numeric comparison support<br><br>
+ *
+ * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
+ * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
+ * @author Nathan Bubna
+ */
+public abstract class ASTComparisonNode extends SimpleNode
+{
+ /**
+ * @param id
+ */
+ public ASTComparisonNode(int id)
+ {
+ super(id);
+ }
+
+ /**
+ * @param p
+ * @param id
+ */
+ public ASTComparisonNode(Parser p, int id)
+ {
+ super(p, id);
+ }
+
+
+ /**
+ * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
+ */
+ public Object jjtAccept(ParserVisitor visitor, Object data)
+ {
+ return visitor.visit(this, data);
+ }
+
+ /**
+ * @see org.apache.velocity.runtime.parser.node.SimpleNode#evaluate(org.apache.velocity.context.InternalContextAdapter)
+ */
+ public boolean evaluate(InternalContextAdapter context) throws MethodInvocationException
+ {
+ Object left = jjtGetChild(0).value(context);
+ Object right = jjtGetChild(1).value(context);
+
+ if (left == null || right == null)
+ {
+ return compareNull(left, right);
+ }
+ Boolean result = compareNumbers(left, right);
+ if (result == null)
+ {
+ result = compareNonNumber(left, right);
+ }
+ return result;
+ }
+
+ /**
+ * Always false by default, != and == subclasses must override this.
+ */
+ public boolean compareNull(Object left, Object right)
+ {
+ // if either side is null, log and bail
+ String msg = (left == null ? "Left" : "Right")
+ + " side ("
+ + jjtGetChild( (left == null? 0 : 1) ).literal()
+ + ") of comparison operation has null value at "
+ + Log.formatFileString(this);
+ if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
+ {
+ throw new VelocityException(msg);
+ }
+ log.error(msg);
+ return false;
+ }
+
+ public Boolean compareNumbers(Object left, Object right)
+ {
+ try
+ {
+ left = DuckType.asNumber(left);
+ }
+ catch (NumberFormatException nfe) {}
+ try
+ {
+ right = DuckType.asNumber(right);
+ }
+ catch (NumberFormatException nfe) {}
+
+ // only compare Numbers
+ if (left instanceof Number && right instanceof Number)
+ {
+ return numberTest(MathUtils.compare((Number)left, (Number)right));
+ }
+ return null;
+ }
+
+ public abstract boolean numberTest(int compareResult);
+
+ public boolean compareNonNumber(Object left, Object right)
+ {
+ // by default, log and bail
+ String msg = (right instanceof Number ? "Left" : "Right")
+ + " side of comparison operation is not a number at "
+ + Log.formatFileString(this);
+ if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
+ {
+ throw new VelocityException(msg);
+ }
+ log.error(msg);
+ return false;
+ }
+
+ private String getLiteral(boolean left)
+ {
+ return jjtGetChild(left ? 0 : 1).literal();
+ }
+
+ /**
+ * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
+ */
+ public Object value(InternalContextAdapter context) throws MethodInvocationException
+ {
+ return Boolean.valueOf(evaluate(context));
+ }
+
+}
Propchange: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java
------------------------------------------------------------------------------
svn:keywords = Revision
Propchange: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTEQNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTEQNode.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTEQNode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTEQNode.java Wed Dec 29 06:11:06 2010
@@ -19,130 +19,65 @@ package org.apache.velocity.runtime.pars
* under the License.
*/
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.runtime.parser.Parser;
-import org.apache.velocity.util.TemplateNumber;
+import org.apache.velocity.util.DuckType;
/**
- * Handles <code>arg1 == arg2</code>
+ * Handles <code>arg1 == arg2</code>
*
* This operator requires that the LHS and RHS are both of the
- * same Class OR both are subclasses of java.lang.Number
+ * same Class, both numbers or both coerce-able to strings.
*
* @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
* @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
- * @version $Id$
+ * @author Nathan Bubna
*/
-public class ASTEQNode extends SimpleNode
+public class ASTEQNode extends ASTComparisonNode
{
- /**
- * @param id
- */
public ASTEQNode(int id)
{
super(id);
}
- /**
- * @param p
- * @param id
- */
public ASTEQNode(Parser p, int id)
{
super(p, id);
}
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
- */
- public Object jjtAccept(ParserVisitor visitor, Object data)
+ @Override
+ public boolean compareNull(Object left, Object right)
{
- return visitor.visit(this, data);
+ // at least one is null, see if other is null or acts as a null
+ return left == right || DuckType.asNull(left == null ? right : left);
}
- /**
- * Calculates the value of the logical expression
- *
- * arg1 == arg2
- *
- * All class types are supported. Uses equals() to
- * determine equivalence. This should work as we represent
- * with the types we already support, and anything else that
- * implements equals() to mean more than identical references.
- *
- *
- * @param context internal context used to evaluate the LHS and RHS
- * @return true if equivalent, false if not equivalent,
- * false if not compatible arguments, or false
- * if either LHS or RHS is null
- * @throws MethodInvocationException
- */
- public boolean evaluate(InternalContextAdapter context)
- throws MethodInvocationException
+ public boolean numberTest(int compareResult)
{
- Object left = jjtGetChild(0).value(context);
- Object right = jjtGetChild(1).value(context);
-
- /*
- * convert to Number if applicable
- */
- if (left instanceof TemplateNumber)
- {
- left = ( (TemplateNumber) left).getAsNumber();
- }
- if (right instanceof TemplateNumber)
- {
- right = ( (TemplateNumber) right).getAsNumber();
- }
-
- /*
- * If comparing Numbers we do not care about the Class.
- */
- if (left instanceof Number && right instanceof Number)
- {
- return MathUtils.compare( (Number)left, (Number)right) == 0;
- }
+ return compareResult == 0;
+ }
+ @Override
+ public boolean compareNonNumber(Object left, Object right)
+ {
/**
* if both are not null, then assume that if one class
* is a subclass of the other that we should use the equals operator
*/
- if (left != null && right != null &&
- (left.getClass().isAssignableFrom(right.getClass()) ||
- right.getClass().isAssignableFrom(left.getClass())))
+ if (left.getClass().isAssignableFrom(right.getClass()) ||
+ right.getClass().isAssignableFrom(left.getClass()))
{
- return left.equals( right );
+ return left.equals(right);
}
- /*
- * Ok, time to compare string values
- */
- left = (left == null) ? null : left.toString();
- right = (right == null) ? null: right.toString();
-
- if (left == null && right == null)
+ // coerce to string, remember getAsString() methods may return null
+ left = DuckType.asString(left);
+ right = DuckType.asString(right);
+ if (left == right)
{
- if (log.isDebugEnabled())
- {
- log.debug("Both right (" + getLiteral(false) + " and left "
- + getLiteral(true) + " sides of '==' operation returned null."
- + "If references, they may not be in the context."
- + getLocation(context));
- }
return true;
}
else if (left == null || right == null)
{
- if (log.isDebugEnabled())
- {
- log.debug((left == null ? "Left" : "Right")
- + " side (" + getLiteral(left == null)
- + ") of '==' operation has null value. If it is a "
- + "reference, it may not be in the context or its "
- + "toString() returned null. " + getLocation(context));
-
- }
return false;
}
else
@@ -151,17 +86,4 @@ public class ASTEQNode extends SimpleNod
}
}
- private String getLiteral(boolean left)
- {
- return jjtGetChild(left ? 0 : 1).literal();
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
- */
- public Object value(InternalContextAdapter context)
- throws MethodInvocationException
- {
- return evaluate(context) ? Boolean.TRUE : Boolean.FALSE;
- }
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTGENode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTGENode.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTGENode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTGENode.java Wed Dec 29 06:11:06 2010
@@ -19,133 +19,26 @@ package org.apache.velocity.runtime.pars
* under the License.
*/
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.MethodInvocationException;
-import org.apache.velocity.exception.VelocityException;
-import org.apache.velocity.runtime.RuntimeConstants;
-import org.apache.velocity.runtime.log.Log;
import org.apache.velocity.runtime.parser.Parser;
-import org.apache.velocity.util.TemplateNumber;
-
/**
* Handles arg1 >= arg2<br><br>
- *
- * Only subclasses of Number can be compared.<br><br>
- *
- * Please look at the Parser.jjt file which is
- * what controls the generation of this class.
- *
- * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
- * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
*/
-public class ASTGENode extends SimpleNode
+public class ASTGENode extends ASTComparisonNode
{
- /**
- * @param id
- */
public ASTGENode(int id)
{
super(id);
}
- /**
- * @param p
- * @param id
- */
public ASTGENode(Parser p, int id)
{
super(p, id);
}
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
- */
- public Object jjtAccept(ParserVisitor visitor, Object data)
- {
- return visitor.visit(this, data);
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#evaluate(org.apache.velocity.context.InternalContextAdapter)
- */
- public boolean evaluate( InternalContextAdapter context)
- throws MethodInvocationException
+ public boolean numberTest(int compareResult)
{
- /*
- * get the two args
- */
-
- Object left = jjtGetChild(0).value( context );
- Object right = jjtGetChild(1).value( context );
-
- /*
- * if either is null, lets log and bail
- */
-
- if (left == null || right == null)
- {
- String msg = (left == null ? "Left" : "Right")
- + " side ("
- + jjtGetChild( (left == null? 0 : 1) ).literal()
- + ") of '>=' operation has null value at "
- + Log.formatFileString(this);
-
- if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
- {
- throw new VelocityException(msg);
- }
-
- log.error(msg);
- return false;
- }
-
-
- /*
- * convert to Number if applicable
- */
- if (left instanceof TemplateNumber)
- {
- left = ( (TemplateNumber) left).getAsNumber();
- }
- if (right instanceof TemplateNumber)
- {
- right = ( (TemplateNumber) right).getAsNumber();
- }
-
- /*
- * Only compare Numbers
- */
-
- if ( !( left instanceof Number ) || !( right instanceof Number ))
- {
- String msg = (!(left instanceof Number) ? "Left" : "Right")
- + " side of '>=' operation is not a Number at "
- + Log.formatFileString(this);
-
- if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
- {
- throw new VelocityException(msg);
- }
-
- log.error(msg);
- return false;
- }
-
- return MathUtils.compare ( (Number)left,(Number)right) >= 0;
-
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
- */
- public Object value(InternalContextAdapter context)
- throws MethodInvocationException
- {
- boolean val = evaluate(context);
-
- return val ? Boolean.TRUE : Boolean.FALSE;
+ return compareResult >= 0;
}
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTGTNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTGTNode.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTGTNode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTGTNode.java Wed Dec 29 06:11:06 2010
@@ -19,132 +19,26 @@ package org.apache.velocity.runtime.pars
* under the License.
*/
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.MethodInvocationException;
-import org.apache.velocity.exception.VelocityException;
-import org.apache.velocity.runtime.RuntimeConstants;
-import org.apache.velocity.runtime.log.Log;
import org.apache.velocity.runtime.parser.Parser;
-import org.apache.velocity.util.TemplateNumber;
/**
* Handles arg1 > arg2<br><br>
- *
- * Only subclasses of Number can be compared.<br><br>
- *
- * Please look at the Parser.jjt file which is
- * what controls the generation of this class.
- *
- * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
- * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
*/
-
-public class ASTGTNode extends SimpleNode
+public class ASTGTNode extends ASTComparisonNode
{
- /**
- * @param id
- */
public ASTGTNode(int id)
{
super(id);
}
- /**
- * @param p
- * @param id
- */
public ASTGTNode(Parser p, int id)
{
super(p, id);
}
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
- */
- public Object jjtAccept(ParserVisitor visitor, Object data)
- {
- return visitor.visit(this, data);
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#evaluate(org.apache.velocity.context.InternalContextAdapter)
- */
- public boolean evaluate(InternalContextAdapter context)
- throws MethodInvocationException
- {
- /*
- * get the two args
- */
-
- Object left = jjtGetChild(0).value( context );
- Object right = jjtGetChild(1).value( context );
-
- /*
- * if either is null, lets log and bail
- */
-
- if (left == null || right == null)
- {
- String msg = (left == null ? "Left" : "Right")
- + " side ("
- + jjtGetChild( (left == null? 0 : 1) ).literal()
- + ") of '>' operation has null value at "
- + Log.formatFileString(this);
-
- if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
- {
- throw new VelocityException(msg);
- }
-
- log.error(msg);
- return false;
- }
-
- /*
- * convert to Number if applicable
- */
- if (left instanceof TemplateNumber)
- {
- left = ( (TemplateNumber) left).getAsNumber();
- }
- if (right instanceof TemplateNumber)
- {
- right = ( (TemplateNumber) right).getAsNumber();
- }
-
- /*
- * Only compare Numbers
- */
-
- if ( !( left instanceof Number ) || !( right instanceof Number ))
- {
- String msg = (!(left instanceof Number) ? "Left" : "Right")
- + " side of '>=' operation is not a Number at "
- + Log.formatFileString(this);
-
- if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
- {
- throw new VelocityException(msg);
- }
-
- log.error(msg);
- return false;
- }
-
- return MathUtils.compare ( (Number)left,(Number)right) == 1;
-
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
- */
- public Object value(InternalContextAdapter context)
- throws MethodInvocationException
+ public boolean numberTest(int compareResult)
{
- boolean val = evaluate(context);
-
- return val ? Boolean.TRUE : Boolean.FALSE;
+ return compareResult == 1;
}
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTLENode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTLENode.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTLENode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTLENode.java Wed Dec 29 06:11:06 2010
@@ -19,131 +19,26 @@ package org.apache.velocity.runtime.pars
* under the License.
*/
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.MethodInvocationException;
-import org.apache.velocity.exception.VelocityException;
-import org.apache.velocity.runtime.RuntimeConstants;
-import org.apache.velocity.runtime.log.Log;
import org.apache.velocity.runtime.parser.Parser;
-import org.apache.velocity.util.TemplateNumber;
/**
* Handles arg1 <= arg2<br><br>
- *
- * Only subclasses of Number can be compared.<br><br>
- *
- * Please look at the Parser.jjt file which is
- * what controls the generation of this class.
- *
- * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
- * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
*/
-
-public class ASTLENode extends SimpleNode
+public class ASTLENode extends ASTComparisonNode
{
- /**
- * @param id
- */
public ASTLENode(int id)
{
super(id);
}
- /**
- * @param p
- * @param id
- */
public ASTLENode(Parser p, int id)
{
super(p, id);
}
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
- */
- public Object jjtAccept(ParserVisitor visitor, Object data)
- {
- return visitor.visit(this, data);
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#evaluate(org.apache.velocity.context.InternalContextAdapter)
- */
- public boolean evaluate( InternalContextAdapter context)
- throws MethodInvocationException
- {
- /*
- * get the two args
- */
-
- Object left = jjtGetChild(0).value( context );
- Object right = jjtGetChild(1).value( context );
-
- /*
- * if either is null, lets log and bail
- */
-
- if (left == null || right == null)
- {
- String msg = (left == null ? "Left" : "Right")
- + " side ("
- + jjtGetChild( (left == null? 0 : 1) ).literal()
- + ") of '<=' operation has null value at "
- + Log.formatFileString(this);
-
- if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
- {
- throw new VelocityException(msg);
- }
-
- log.error(msg);
- return false;
- }
-
- /*
- * convert to Number if applicable
- */
- if (left instanceof TemplateNumber)
- {
- left = ( (TemplateNumber) left).getAsNumber();
- }
- if (right instanceof TemplateNumber)
- {
- right = ( (TemplateNumber) right).getAsNumber();
- }
-
- /*
- * Only compare Numbers
- */
- if ( !( left instanceof Number ) || !( right instanceof Number ))
- {
- String msg = (!(left instanceof Number) ? "Left" : "Right")
- + " side of '>=' operation is not a Number at "
- + Log.formatFileString(this);
-
- if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
- {
- throw new VelocityException(msg);
- }
-
- log.error(msg);
- return false;
- }
-
- return MathUtils.compare ( (Number)left,(Number)right) <= 0;
-
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
- */
- public Object value(InternalContextAdapter context)
- throws MethodInvocationException
+ public boolean numberTest(int compareResult)
{
- boolean val = evaluate(context);
-
- return val ? Boolean.TRUE : Boolean.FALSE;
+ return compareResult <= 0;
}
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTLTNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTLTNode.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTLTNode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTLTNode.java Wed Dec 29 06:11:06 2010
@@ -19,132 +19,26 @@ package org.apache.velocity.runtime.pars
* under the License.
*/
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.MethodInvocationException;
-import org.apache.velocity.exception.VelocityException;
-import org.apache.velocity.runtime.RuntimeConstants;
-import org.apache.velocity.runtime.log.Log;
import org.apache.velocity.runtime.parser.Parser;
-import org.apache.velocity.util.TemplateNumber;
/**
* Handles arg1 < arg2<br><br>
- *
- * Only subclasses of Number can be compared.<br><br>
- *
- * Please look at the Parser.jjt file which is
- * what controls the generation of this class.
- *
- * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
- * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
*/
-
-public class ASTLTNode extends SimpleNode
+public class ASTLTNode extends ASTComparisonNode
{
- /**
- * @param id
- */
public ASTLTNode(int id)
{
super(id);
}
- /**
- * @param p
- * @param id
- */
public ASTLTNode(Parser p, int id)
{
super(p, id);
}
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
- */
- public Object jjtAccept(ParserVisitor visitor, Object data)
- {
- return visitor.visit(this, data);
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#evaluate(org.apache.velocity.context.InternalContextAdapter)
- */
- public boolean evaluate(InternalContextAdapter context)
- throws MethodInvocationException
+ public boolean numberTest(int compareResult)
{
- /*
- * get the two args
- */
-
- Object left = jjtGetChild(0).value( context );
- Object right = jjtGetChild(1).value( context );
-
- /*
- * if either is null, lets log and bail
- */
-
- if (left == null || right == null)
- {
- String msg = (left == null ? "Left" : "Right")
- + " side ("
- + jjtGetChild( (left == null? 0 : 1) ).literal()
- + ") of '<' operation has null value at "
- + Log.formatFileString(this);
-
- if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
- {
- throw new VelocityException(msg);
- }
-
- log.error(msg);
- return false;
- }
-
- /*
- * convert to Number if applicable
- */
- if (left instanceof TemplateNumber)
- {
- left = ( (TemplateNumber) left).getAsNumber();
- }
- if (right instanceof TemplateNumber)
- {
- right = ( (TemplateNumber) right).getAsNumber();
- }
-
- /*
- * Only compare Numbers
- */
-
- if ( !( left instanceof Number ) || !( right instanceof Number ))
- {
- String msg = (!(left instanceof Number) ? "Left" : "Right")
- + " side of '>=' operation is not a valid Number at "
- + Log.formatFileString(this);
-
- if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
- {
- throw new VelocityException(msg);
- }
-
- log.error(msg);
- return false;
- }
-
- return MathUtils.compare ( (Number)left,(Number)right) == -1;
-
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
- */
- public Object value(InternalContextAdapter context)
- throws MethodInvocationException
- {
- boolean val = evaluate(context);
-
- return val ? Boolean.TRUE : Boolean.FALSE;
+ return compareResult == -1;
}
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMathNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMathNode.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMathNode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMathNode.java Wed Dec 29 06:11:06 2010
@@ -25,7 +25,7 @@ import org.apache.velocity.exception.Met
import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.parser.Parser;
-import org.apache.velocity.util.TemplateNumber;
+import org.apache.velocity.util.DuckType;
/**
* Helps handle math<br><br>
@@ -93,17 +93,17 @@ public abstract class ASTMathNode extend
return special;
}
- /*
- * convert to Number if applicable
- */
- if (left instanceof TemplateNumber)
+ // coerce to Number type, if possible
+ try
{
- left = ((TemplateNumber)left).getAsNumber();
+ left = DuckType.asNumber(left);
}
- if (right instanceof TemplateNumber)
+ catch (NumberFormatException nfe) {}
+ try
{
- right = ((TemplateNumber)right).getAsNumber();
+ right = DuckType.asNumber(right);
}
+ catch (NumberFormatException nfe) {}
/*
* if not a Number, not much we can do
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNENode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNENode.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNENode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNENode.java Wed Dec 29 06:11:06 2010
@@ -22,134 +22,29 @@ package org.apache.velocity.runtime.pars
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.runtime.parser.Parser;
-import org.apache.velocity.util.TemplateNumber;
/**
- * Handles <code>arg1 != arg2</code>
- *
- * This operator requires that the LHS and RHS are both of the
- * same Class OR both are subclasses of java.lang.Number
- *
- * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
- * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
+ * Handles <code>arg1 != arg2</code> by negating evaluation of ASTEQNode
*/
-public class ASTNENode extends SimpleNode
+public class ASTNENode extends ASTEQNode
{
- /**
- * @param id
- */
public ASTNENode(int id)
{
super(id);
}
- /**
- * @param p
- * @param id
- */
public ASTNENode(Parser p, int id)
{
super(p, id);
}
/**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
- */
- public Object jjtAccept(ParserVisitor visitor, Object data)
- {
- return visitor.visit(this, data);
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#evaluate(org.apache.velocity.context.InternalContextAdapter)
- */
- public boolean evaluate( InternalContextAdapter context)
- throws MethodInvocationException
- {
- Object left = jjtGetChild(0).value( context );
- Object right = jjtGetChild(1).value( context );
-
- /*
- * convert to Number if applicable
- */
- if (left instanceof TemplateNumber)
- {
- left = ( (TemplateNumber) left).getAsNumber();
- }
- if (right instanceof TemplateNumber)
- {
- right = ( (TemplateNumber) right).getAsNumber();
- }
-
- /*
- * If comparing Numbers we do not care about the Class.
- */
- if (left instanceof Number && right instanceof Number)
- {
- return MathUtils.compare ( (Number)left,(Number)right) != 0;
- }
-
- /**
- * if both are not null, then assume that if one class
- * is a subclass of the other that we should use the equals operator
- */
- if (left != null && right != null &&
- (left.getClass().isAssignableFrom(right.getClass()) ||
- right.getClass().isAssignableFrom(left.getClass())))
- {
- return !left.equals( right );
- }
-
- /*
- * Ok, time to compare string values
- */
- left = (left == null) ? null : left.toString();
- right = (right == null) ? null: right.toString();
-
- if (left == null && right == null)
- {
- if (log.isDebugEnabled())
- {
- log.debug("Both right (" + getLiteral(false) + " and left "
- + getLiteral(true) + " sides of '!=' operation returned null."
- + "If references, they may not be in the context."
- + getLocation(context));
- }
- return false;
- }
- else if (left == null || right == null)
- {
- if (log.isDebugEnabled())
- {
- log.debug((left == null ? "Left" : "Right")
- + " side (" + getLiteral(left == null)
- + ") of '!=' operation has null value. If it is a "
- + "reference, it may not be in the context or its "
- + "toString() returned null. " + getLocation(context));
-
- }
- return true;
- }
- else
- {
- return !left.equals(right);
- }
- }
-
- private String getLiteral(boolean left)
- {
- return jjtGetChild(left ? 0 : 1).literal();
- }
-
- /**
- * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
+ * {@inheritDoc}
*/
- public Object value(InternalContextAdapter context)
- throws MethodInvocationException
+ @Override
+ public boolean evaluate(InternalContextAdapter context) throws MethodInvocationException
{
- boolean val = evaluate(context);
-
- return val ? Boolean.TRUE : Boolean.FALSE;
+ return !super.evaluate(context);
}
}
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java Wed Dec 29 06:11:06 2010
@@ -37,6 +37,7 @@ import org.apache.velocity.runtime.log.L
import org.apache.velocity.runtime.parser.Parser;
import org.apache.velocity.runtime.parser.Token;
import org.apache.velocity.util.ClassUtils;
+import org.apache.velocity.util.DuckType;
import org.apache.velocity.util.introspection.Info;
import org.apache.velocity.util.introspection.VelMethod;
import org.apache.velocity.util.introspection.VelPropertySet;
@@ -51,7 +52,7 @@ import org.apache.velocity.util.introspe
* @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @author <a href="mailto:Christoph.Reck@dlr.de">Christoph Reck</a>
- * @author <a href="mailto:kjohnson@transparent.com>Kent Johnson</a>
+ * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a>
* @version $Id$
*/
public class ASTReference extends SimpleNode
@@ -418,7 +419,7 @@ public class ASTReference extends Simple
}
}
- toString = value.toString();
+ toString = DuckType.asString(value);
}
if (value == null || toString == null)
@@ -526,29 +527,18 @@ public class ASTReference extends Simple
throws MethodInvocationException
{
Object value = execute(null, context);
-
if (value == null)
{
return false;
}
- else if (value instanceof Boolean)
+ try
{
- if (((Boolean) value).booleanValue())
- return true;
- else
- return false;
- }
- else
+ return DuckType.asBoolean(value);
+ }
+ catch(Exception e)
{
- try
- {
- return value.toString() != null;
- }
- catch(Exception e)
- {
- throw new VelocityException("Reference evaluation threw an exception at "
- + Log.formatFileString(this), e);
- }
+ throw new VelocityException("Reference evaluation threw an exception at "
+ + Log.formatFileString(this), e);
}
}
Added: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/DuckType.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/DuckType.java?rev=1053541&view=auto
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/DuckType.java (added)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/DuckType.java Wed Dec 29 06:11:06 2010
@@ -0,0 +1,289 @@
+package org.apache.velocity.util;
+
+/*
+ * 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.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Support for getAs<Type>() convention for rendering (String), evaluating (Boolean)
+ * or doing math with (Number) references.
+ *
+ * @author Nathan Bubna
+ * @since 2.0
+ */
+public class DuckType
+{
+ protected enum Types
+ {
+ STRING("getAsString"),
+ NUMBER("getAsNumber"),
+ BOOLEAN("getAsBoolean"),
+ EMPTY("isEmpty");
+
+ final String name;
+ final Map<Class,Object> cache = new HashMap();
+
+ Types(String name)
+ {
+ this.name = name;
+ }
+
+ void set(Class c, Object o)
+ {
+ cache.put(c, o);
+ }
+
+ Object get(Class c)
+ {
+ return cache.get(c);
+ }
+ }
+
+ protected static final Object NO_METHOD = new Object();
+
+ public static String asString(Object value)
+ {
+ return asString(value, true);
+ }
+
+ public static String asString(Object value, boolean coerceType)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+ if (value instanceof String)
+ {
+ return (String)value;
+ }
+ Object got = get(value, Types.STRING);
+ if (got == NO_METHOD)
+ {
+ return coerceType ? value.toString() : null;
+ }
+ return (String)got;
+ }
+
+ public static boolean asNull(Object value)
+ {
+ if (value == null ||
+ get(value, Types.STRING) == null ||
+ get(value, Types.NUMBER) == null)
+ {
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean asBoolean(Object value)
+ {
+ return asBoolean(value, true);
+ }
+
+ public static boolean asBoolean(Object value, boolean coerceType)
+ {
+ if (value == null)
+ {
+ return false;
+ }
+ if (value instanceof Boolean)
+ {
+ return ((Boolean)value).booleanValue();
+ }
+ Object got = get(value, Types.BOOLEAN);
+ if (got != NO_METHOD)
+ {
+ return ((Boolean)got).booleanValue();
+ }
+ if (coerceType)
+ {
+ return !asEmpty(value);
+ }
+ return true;
+ }
+
+ // see VELOCITY-692 for discussion about empty values
+ public static boolean asEmpty(Object value)
+ {
+ // empty variable
+ if (value == null)
+ {
+ return true;
+ }
+
+ // empty string
+ if (value instanceof CharSequence)
+ {
+ return ((CharSequence)value).length() == 0;
+ }
+
+ // isEmpty() object
+ Object isEmpty = get(value, Types.EMPTY);
+ if (isEmpty != NO_METHOD)
+ {
+ return (Boolean)isEmpty;
+ }
+
+ // empty array
+ if (value.getClass().isArray())
+ {
+ return Array.getLength(value) == 0;// [] is false
+ }
+
+ // null getAsString()
+ Object asString = get(value, Types.STRING);
+ if (asString == null)
+ {
+ return true;// duck null
+ }
+ // empty getAsString()
+ else if (asString != NO_METHOD)
+ {
+ return ((String)asString).length() == 0;
+ }
+
+ // null getAsNumber()
+ Object asNumber = get(value, Types.NUMBER);
+ if (asNumber == null)
+ {
+ return true;
+ }
+
+ // empty toString()
+ String string = value.toString();
+ return string == null || string.length() == 0;
+ }
+
+ public static Number asNumber(Object value)
+ {
+ return asNumber(value, true);
+ }
+
+ public static Number asNumber(Object value, boolean coerceType)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+ if (value instanceof Number)
+ {
+ return (Number)value;
+ }
+ Object got = get(value, Types.NUMBER);
+ if (got != NO_METHOD)
+ {
+ return (Number)got;
+ }
+ if (coerceType)
+ {
+ String string = asString(value);// coerce to string
+ if (string != null)
+ {
+ return new BigDecimal(string);
+ }
+ }
+ return null;
+ }
+
+ protected static Object get(Object value, Types type)
+ {
+ try
+ {
+ // check cache
+ Class c = value.getClass();
+ Object cached = type.get(c);
+ if (cached == NO_METHOD)
+ {
+ return cached;
+ }
+ if (cached != null)
+ {
+ return ((Method)cached).invoke(value);
+ }
+ // ok, search the class
+ Method method = findMethod(c, type);
+ if (method == null)
+ {
+ type.set(c, NO_METHOD);
+ return NO_METHOD;
+ }
+ type.set(c, method);
+ return method.invoke(value);
+ }
+ catch (RuntimeException re)
+ {
+ throw re;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);// no checked exceptions, please
+ }
+ }
+
+ protected static Method findMethod(Class c, Types type)
+ {
+ if (c == null || c == Object.class)
+ {
+ return null;
+ }
+ Method m = getMethod(c, type.name);
+ if (m != null)
+ {
+ return m;
+ }
+ for (Class i : c.getInterfaces())
+ {
+ m = findMethod(i, type);
+ if (m != null)
+ {
+ return m;
+ }
+ }
+ m = findMethod(c.getSuperclass(), type);
+ if (m != null)
+ {
+ return m;
+ }
+ return null;
+ }
+
+ private static Method getMethod(Class c, String name)
+ {
+ if (Modifier.isPublic(c.getModifiers()))
+ {
+ try
+ {
+ Method m = c.getDeclaredMethod(name);
+ if (Modifier.isPublic(m.getModifiers()))
+ {
+ return m;
+ }
+ }
+ catch (NoSuchMethodException nsme) {}
+ }
+ return null;
+ }
+
+}
Propchange: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/DuckType.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/DuckType.java
------------------------------------------------------------------------------
svn:keywords = Revision
Propchange: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/DuckType.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java?rev=1053541&view=auto
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java (added)
+++ velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java Wed Dec 29 06:11:06 2010
@@ -0,0 +1,147 @@
+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 org.apache.velocity.util.TemplateString;
+import org.apache.velocity.util.TemplateBoolean;
+import org.apache.velocity.util.TemplateNumber;
+
+/**
+ * Test objects with getAs<Type>() methods.
+ */
+public class GetAsTestCase extends BaseTestCase
+{
+ public GetAsTestCase(final String name)
+ {
+ super(name);
+ }
+
+ public void testCustomString()
+ {
+ // render
+ context.put("foo", new CustomString("getAsString"));
+ assertEvalEquals("getAsString", "$foo");
+ // aborted value
+ context.put("bar", new CustomString(null));
+ assertEvalEquals("", "$!bar");
+ // concatenation
+ context.put("half", new CustomString("half"));
+ assertEvalEquals("1half", "#set( $out = 1 + $half )$out");
+ }
+
+ public void testCustomBoolean()
+ {
+ context.put("foo", new CustomBoolean(false));
+ assertEvalEquals("right", "#if( !$foo )right#end");
+ }
+
+ public void testCustomNumber()
+ {
+ context.put("foo", new CustomNumber(7));
+ assertEvalEquals("14", "#set( $bar = $foo * 2 )$bar");
+ }
+
+
+ public void testTemplateString()
+ {
+ context.put("foo", new CustomTemplateString("getAsString"));
+ assertEvalEquals("getAsString", "$foo");
+ }
+
+ public void testTemplateBoolean()
+ {
+ context.put("foo", new CustomTemplateBoolean(false));
+ assertEvalEquals("right", "#if( !$foo )right#end");
+ }
+
+ public void testTemplateNumber()
+ {
+ context.put("foo", new CustomTemplateNumber(5));
+ assertEvalEquals("25", "#set( $foo = $foo * $foo )$foo");
+ }
+
+
+
+ public static class CustomString
+ {
+ String string;
+ public CustomString(String string)
+ {
+ this.string = string;
+ }
+ public String getAsString()
+ {
+ return string;
+ }
+ }
+
+ public static class CustomBoolean
+ {
+ boolean bool;
+ public CustomBoolean(boolean bool)
+ {
+ this.bool = bool;
+ }
+ public boolean getAsBoolean()
+ {
+ return bool;
+ }
+ }
+
+ public static class CustomNumber
+ {
+ Number num;
+ public CustomNumber(Number num)
+ {
+ this.num = num;
+ }
+ public Number getAsNumber()
+ {
+ return num;
+ }
+ }
+
+ public static class CustomTemplateString extends CustomString implements TemplateString
+ {
+ public CustomTemplateString(String string)
+ {
+ super(string);
+ }
+ }
+
+ public static class CustomTemplateBoolean extends CustomBoolean implements TemplateBoolean
+ {
+ public CustomTemplateBoolean(Boolean bool)
+ {
+ super(bool);
+ }
+ }
+
+ public static class CustomTemplateNumber extends CustomNumber implements TemplateNumber
+ {
+ public CustomTemplateNumber(Number num)
+ {
+ super(num);
+ }
+ }
+
+}
+
+
Propchange: velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java
------------------------------------------------------------------------------
svn:keywords = Revision
Propchange: velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java?rev=1053541&view=auto
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java (added)
+++ velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java Wed Dec 29 06:11:06 2010
@@ -0,0 +1,95 @@
+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.util.Collections;
+
+/**
+ * Used to check that empty values are properly handled in #if statements
+ */
+public class IfEmptyTestCase extends BaseTestCase
+{
+ public IfEmptyTestCase(final String name)
+ {
+ super(name);
+ }
+
+ protected void assertEmpty(Object obj)
+ {
+ context.put("obj", obj);
+ assertEvalEquals("", "#if( $obj )fail#end");
+ }
+
+ public void testNull()
+ {
+ assertEmpty(null);
+ assertEmpty(new NullAsString());
+ assertEmpty(new NullAsNumber());
+ }
+
+ public void testDataStructures()
+ {
+ assertEmpty(Collections.emptyMap());
+ assertEmpty(Collections.emptyList());
+ assertEmpty(new Object[]{});
+ }
+
+ public void testString()
+ {
+ assertEmpty("");
+ assertEmpty(new EmptyAsString());
+ assertEmpty(new EmptyToString());
+ }
+
+ public static class NullAsString
+ {
+ public String getAsString()
+ {
+ return null;
+ }
+ }
+
+ public static class EmptyAsString
+ {
+ public String getAsString()
+ {
+ return "";
+ }
+ }
+
+ public static class NullAsNumber
+ {
+ public String getAsNumber()
+ {
+ return null;
+ }
+ }
+
+ public static class EmptyToString
+ {
+ public String toString()
+ {
+ return "";
+ }
+ }
+
+}
+
+
Propchange: velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java
------------------------------------------------------------------------------
svn:keywords = Revision
Propchange: velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfNullTestCase.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfNullTestCase.java?rev=1053541&r1=1053540&r2=1053541&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfNullTestCase.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfNullTestCase.java Wed Dec 29 06:11:06 2010
@@ -91,7 +91,7 @@ public class IfNullTestCase extends Base
public static class NullToString
{
- public String toString()
+ public String getAsString()
{
return null;
}