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">


Reply via email to