Author: byron
Date: Sat Jan 31 04:28:17 2009
New Revision: 739503
URL: http://svn.apache.org/viewvc?rev=739503&view=rev
Log:
VELOCITY-688 In strict mode rendering a reference that evaluates to null will
throw an exception
Modified:
velocity/engine/trunk/src/changes/changes.xml
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictEscapeTestCase.java
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictReferenceTestCase.java
velocity/engine/trunk/xdocs/docs/user-guide.xml
Modified: velocity/engine/trunk/src/changes/changes.xml
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/changes/changes.xml?rev=739503&r1=739502&r2=739503&view=diff
==============================================================================
--- velocity/engine/trunk/src/changes/changes.xml (original)
+++ velocity/engine/trunk/src/changes/changes.xml Sat Jan 31 04:28:17 2009
@@ -27,6 +27,13 @@
<body>
<release version="1.7" date="In Subversion">
+ <action type="add" dev="byron" issue="VELOCITY-688">
+ In strict mode attempts to render references that evaluate to
+ null will throw an exception. In the user wishes to suppress
+ the exception and render nothing then the reference can be
+ proceeded with '$!' as in $!foo.
+ </action>
+
<action type="add" dev="byron" issue="VELOCITY-673">
The non default VelocityEngine construtors now do not initialize the
runtime
system so that properties may be set after constrution. Also fixes an
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=739503&r1=739502&r2=739503&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
Sat Jan 31 04:28:17 2009
@@ -421,7 +421,33 @@
}
if (value == null || toString == null)
- {
+ {
+ if (strictRef)
+ {
+ if (referenceType != QUIET_REFERENCE)
+ {
+ log.error("Prepend the reference with '$!' e.g., $!" +
literal().substring(1)
+ + " if you want Velocity to ignore the reference when it
evaluates to null");
+ if (value == null)
+ {
+ throw new VelocityException("Reference " + literal()
+ + " evaluated to null when attempting to render at "
+ + Log.formatFileString(this));
+ }
+ else // toString == null
+ {
+ // This will probably rarely happen, but when it does we
want to
+ // inform the user that toString == null so they don't
pull there
+ // hair out wondering why Velocity thinks the value is
null.
+ throw new VelocityException("Reference " + literal()
+ + " evaluated to object " + value.getClass().getName()
+ + " whose toString() method returned null at "
+ + Log.formatFileString(this));
+ }
+ }
+ return true;
+ }
+
/*
* write prefix twice, because it's schmoo, so the \ don't escape
each
* other...
Modified:
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictEscapeTestCase.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/test/org/apache/velocity/test/StrictEscapeTestCase.java?rev=739503&r1=739502&r2=739503&view=diff
==============================================================================
---
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictEscapeTestCase.java
(original)
+++
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictEscapeTestCase.java
Sat Jan 31 04:28:17 2009
@@ -38,9 +38,12 @@
super.setUp();
engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE,
Boolean.TRUE);
context.put("pow", "bang");
+ context.put("NULL", null);
+ context.put("animal", new Animal());
+ DEBUG = true;
}
- public void testVarEscape()
+ public void testReferenceEscape()
{
engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT,
Boolean.TRUE);
@@ -60,6 +63,14 @@
assertEvalEquals("\\$pow", "#set($foo = \"\\\\\\$pow\")$foo");
assertEvalEquals("\\$%", "\\$%");
+
+ // This should work but does not... may be related to VELOCITY-679
+ // This is broken from existing escape behavior
+ // assertEvalEquals("\\$bang", "\\$$pow");
+
+ assertEvalEquals("$!foo", "#set($foo = $NULL)\\$!foo");
+ assertEvalEquals("$!animal.null", "\\$!animal.null");
+ assertEvalEquals("$!animal", "\\$!animal");
}
public void testMacroEscape()
@@ -87,7 +98,11 @@
assertEvalEquals("#macro(foo) #end", "\\#macro(foo) \\#end");
assertEvalException("\\\\#end");
- assertEvalException("\\\\#if()");
+ assertEvalException("\\\\#if()");
+
+ // This should work but does not, probably related to VELOCITY-678
+ // this is broken from existing behavior
+ //assertEvalEquals("\\$bar", "\\$#foo()");
}
/**
@@ -101,5 +116,21 @@
assertEvalEquals("\\$bogus", "\\\\$bogus");
assertEvalEquals("\\\\$bogus", "\\\\\\\\$bogus");
assertEvalEquals("\\$bogus", "#set($foo = \"\\\\$bogus\")$foo");
- }
+ }
+
+ /**
+ * Test object for escaping
+ */
+ public static class Animal
+ {
+ public Object getNull()
+ {
+ return null;
+ }
+
+ public String toString()
+ {
+ return null;
+ }
+ }
}
Modified:
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictReferenceTestCase.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/test/org/apache/velocity/test/StrictReferenceTestCase.java?rev=739503&r1=739502&r2=739503&view=diff
==============================================================================
---
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictReferenceTestCase.java
(original)
+++
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictReferenceTestCase.java
Sat Jan 31 04:28:17 2009
@@ -44,7 +44,6 @@
context.put("TRUE", Boolean.TRUE);
}
-
/**
* Test the modified behavior of #if in strict mode. Mainly, that
* single variables references in #if statements use non strict rules
@@ -77,7 +76,7 @@
public void testAllowNullValues()
throws Exception
{
- evaluate("$bar");
+ evaluate("$!bar");
assertEvalEquals("true", "#if($bar == $NULL)true#end");
assertEvalEquals("true", "#set($foobar = $NULL)#if($foobar ==
$NULL)true#end");
assertEvalEquals("13", "#set($list = [1, $NULL, 3])#foreach($item in
$list)#if($item != $NULL)$item#end#end");
@@ -120,7 +119,6 @@
// Mainly want to make sure no exceptions are thrown here
assertEvalEquals("propiness", "$fargo.prop");
- assertEvalEquals("$fargo.nullVal", "$fargo.nullVal");
assertEvalEquals("", "$!fargo.nullVal");
assertEvalEquals("propiness", "$fargo.next.prop");
@@ -154,8 +152,8 @@
assertVelocityEx("#set($fargo.prop = $NULL)$fargo.prop.next");
// make sure no exceptions are thrown here
- evaluate("$fargo.next.next");
- evaluate("$fargo.next.nullVal");
+ evaluate("$!fargo.next.next");
+ evaluate("$!fargo.next.nullVal");
evaluate("#foreach($item in $fargo.nullVal)#end");
}
@@ -177,6 +175,22 @@
}
+ public void testRenderingNull()
+ {
+ Fargo fargo = new Fargo();
+ fargo.next = new Fargo();
+ context.put("fargo", fargo);
+
+ assertVelocityEx("#set($foo = $NULL)$foo");
+ assertEvalEquals("", "#set($foo = $NULL)$!foo");
+ assertVelocityEx("$fargo.nullVal");
+ assertEvalEquals("", "$!fargo.nullVal");
+ assertVelocityEx("$fargo.next.next");
+ assertEvalEquals("", "$!fargo.next.next");
+ assertVelocityEx("$fargo.next.nullVal");
+ assertEvalEquals("", "$!fargo.next.nullVal");
+ }
+
/**
* Assert that we get a MethodInvocationException when calling evaluate
*/
Modified: velocity/engine/trunk/xdocs/docs/user-guide.xml
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/xdocs/docs/user-guide.xml?rev=739503&r1=739502&r2=739503&view=diff
==============================================================================
--- velocity/engine/trunk/xdocs/docs/user-guide.xml (original)
+++ velocity/engine/trunk/xdocs/docs/user-guide.xml Sat Jan 31 04:28:17 2009
@@ -801,6 +801,18 @@
directive.foreach.skip.invalid). Finally, undefined macro
references will also throw an exception in strict mode.
</p>
+ <p>
+ References that Velocity attempts to render but evaluate to null
+ will cause an Exception. To simply render nothing in this case
+ the reference can be preceded by '$!' instead of '$', similar to
+ non strict mode. Keep in mind this is different from the
+ reference not existing in the context which will always throw an
+ exception when attempting to render it in strict mode. For
+ example, below $foo has a value of null in the context
+ </p>
+ <source><![CDATA[this is $foo ## throws an exception because $foo is
null
+this is $!foo ## renders to "this is " without an exception
+this is $!bogus ## bogus is not in the context so throws an
exception]]></source>
</section>
<section name="Case Substitution" href="case_substitution">