You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@velocity.apache.org by wg...@apache.org on 2005/11/13 09:10:31 UTC

svn commit: r332946 - in /jakarta/velocity/core/trunk: src/java/org/apache/velocity/runtime/ src/java/org/apache/velocity/runtime/defaults/ src/java/org/apache/velocity/runtime/parser/node/ src/test/org/apache/velocity/test/ test/set/ test/set/compare/...

Author: wglass
Date: Sun Nov 13 00:10:26 2005
New Revision: 332946

URL: http://svn.apache.org/viewcvs?rev=332946&view=rev
Log:
Allow #set to accept nulls as the right hand side argument.  
For backwards compatibility, this feature is turned off
by default.  Set the property "directive.set.null.allowed" to "true"
to permit this.  Thanks to the various contributors of issue
VELOCITY-186, including Thomas Veith who provided the patch 
and numerous others who contributed thoughts and comments.

Added:
    jakarta/velocity/core/trunk/src/test/org/apache/velocity/test/SetTestCase.java   (with props)
    jakarta/velocity/core/trunk/test/set/   (with props)
    jakarta/velocity/core/trunk/test/set/compare/
    jakarta/velocity/core/trunk/test/set/compare/set1.cmp
    jakarta/velocity/core/trunk/test/set/compare/set2.cmp
    jakarta/velocity/core/trunk/test/set/set1.vm
    jakarta/velocity/core/trunk/test/set/set2.vm
Modified:
    jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
    jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties
    jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
    jakarta/velocity/core/trunk/xdocs/docs/developer-guide.xml
    jakarta/velocity/core/trunk/xdocs/docs/user-guide.xml

Modified: jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java?rev=332946&r1=332945&r2=332946&view=diff
==============================================================================
--- jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java (original)
+++ jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java Sun Nov 13 00:10:26 2005
@@ -123,6 +123,11 @@
     public static final String MAX_NUMBER_LOOPS = "directive.foreach.maxloops";
 
     /**
+     * if set to true then allows #set to accept null values in the right hand side.
+     */
+    public static final String SET_NULL_ALLOWED = "directive.set.null.allowed";
+    
+    /**
      * Starting tag for error messages triggered by passing
      * a parameter not allowed in the #include directive. Only
      * string literals, and references are allowed.

Modified: jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties
URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties?rev=332946&r1=332945&r2=332946&view=diff
==============================================================================
--- jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties (original)
+++ jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties Sun Nov 13 00:10:26 2005
@@ -48,6 +48,16 @@
 directive.foreach.maxloops = -1
 
 #----------------------------------------------------------------------------
+# S E T  P R O P E R T I E S
+#----------------------------------------------------------------------------
+# These properties control the behavior of #set.
+# For compatibility, the default behavior is to disallow setting a reference
+# to null.  This default may be changed in a future version. 
+#----------------------------------------------------------------------------
+
+directive.set.null.allowed = false
+
+#----------------------------------------------------------------------------
 # I N C L U D E  P R O P E R T I E S
 #----------------------------------------------------------------------------
 # These are the properties that governed the way #include'd content

Modified: jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java?rev=332946&r1=332945&r2=332946&view=diff
==============================================================================
--- jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java (original)
+++ jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java Sun Nov 13 00:10:26 2005
@@ -88,51 +88,65 @@
         throws IOException, MethodInvocationException
     {
         /*
-         *  get the RHS node, and it's value
+         *  get the RHS node, and its value
          */
 
         Object value = right.value(context);
 
         /*
-         * it's an error if we don't have a value of some sort
+         * it's an error if we don't have a value of some sort AND 
+         * it is not allowed by configuration 
          */
 
-        if ( value  == null)
+        if( !rsvc.getBoolean(RuntimeConstants.SET_NULL_ALLOWED,false) ) 
         {
-            /*
-             *  first, are we supposed to say anything anyway?
-             */
-            if(blather)
+            if ( value == null )
             {
-               
-                boolean doit = EventHandlerUtil.shouldLogOnNullSet( rsvc, context, left.literal(), right.literal() );
-
-                if (doit)
+                /*
+                 *  first, are we supposed to say anything anyway?
+                 */
+                if(blather)
                 {
-                    log.error("RHS of #set statement is null. Context will not be modified. " 
-                                  + context.getCurrentTemplateName() + " [line " + getLine() 
-                                  + ", column " + getColumn() + "]");
+                    boolean doit = EventHandlerUtil.shouldLogOnNullSet( rsvc, context, left.literal(), right.literal() );
+    
+                    if (doit)
+                    {
+                        log.warn("RHS of #set statement is null. Context will not be modified. " 
+                                      + context.getCurrentTemplateName() + " [line " + getLine() 
+                                      + ", column " + getColumn() + "]");
+                    }
                 }
-            }
-
-            return false;
-        }                
+    
+                return false;
+            }                
+        }      
 
-        /*
-         *  if the LHS is simple, just punch the value into the context
-         *  otherwise, use the setValue() method do to it.
-         *  Maybe we should always use setValue()
-         */
-        
-        if (left.jjtGetNumChildren() == 0)
+        if ( value == null )
         {
-            context.put( leftReference, value);
+            /*
+             * if RHS is null it doesn't matter if LHS is simple or complex
+             * because the LHS is removed from context
+             */
+            context.remove( leftReference );
         }
         else
         {
-            left.setValue(context, value);
+            /*
+             *  if the LHS is simple, just punch the value into the context
+             *  otherwise, use the setValue() method do to it.
+             *  Maybe we should always use setValue()
+             */
+            
+            if (left.jjtGetNumChildren() == 0)
+            {
+                context.put( leftReference, value);
+            }
+            else
+            {
+                left.setValue(context, value);
+            }
         }
-    
+        
         return true;
     }
 

Added: jakarta/velocity/core/trunk/src/test/org/apache/velocity/test/SetTestCase.java
URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/src/test/org/apache/velocity/test/SetTestCase.java?rev=332946&view=auto
==============================================================================
--- jakarta/velocity/core/trunk/src/test/org/apache/velocity/test/SetTestCase.java (added)
+++ jakarta/velocity/core/trunk/src/test/org/apache/velocity/test/SetTestCase.java Sun Nov 13 00:10:26 2005
@@ -0,0 +1,155 @@
+package org.apache.velocity.test;
+
+/*
+ * Copyright 2001-2004 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.io.BufferedWriter;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.runtime.RuntimeConstants;
+
+/**
+ * Test that an instance of a ResourceLoader can be successfully passed in.
+ *
+ * @author <a href="mailto:wglass@apache.org">Will Glass-Husain</a>
+ * @version $Id$
+ */
+public class SetTestCase extends BaseTestCase
+{
+    /**
+     * VTL file extension.
+     */
+    private static final String TMPL_FILE_EXT = "vm";
+
+    /**
+     * Comparison file extension.
+     */
+    private static final String CMP_FILE_EXT = "cmp";
+
+    /**
+     * Comparison file extension.
+     */
+    private static final String RESULT_FILE_EXT = "res";
+
+    /**
+     * Path for templates. This property will override the
+     * value in the default velocity properties file.
+     */
+    private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/set";
+
+    /**
+     * Results relative to the build directory.
+     */
+    private static final String RESULTS_DIR = TEST_RESULT_DIR + "/set";
+
+    /**
+     * Results relative to the build directory.
+     */
+    private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/set/compare";
+
+    /**
+     * Default constructor.
+     */
+    public SetTestCase(String name)
+    {
+        super(name);
+    }
+
+    public void setUp()
+            throws Exception
+    {
+        assureResultsDirectoryExists(RESULTS_DIR);
+    }
+
+    public static Test suite ()
+    {
+        return new TestSuite(SetTestCase.class);
+    }
+
+    /**
+     * Runs the test.
+     */
+    public void testSetNull()
+            throws Exception
+    {
+        /**
+         * Check that #set does not accept nulls
+         */
+    
+        VelocityEngine ve = new VelocityEngine();
+        ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH);
+        ve.init();
+    
+        checkTemplate(ve,"set1");
+        
+        /**
+         * Check that setting the property is the same as the default
+         */
+        ve = new VelocityEngine();
+        ve.addProperty(RuntimeConstants.SET_NULL_ALLOWED, "false");
+        ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH);
+        ve.init();
+    
+        checkTemplate(ve,"set1");
+
+        /**
+         * Check that #set can accept nulls
+         */
+        ve = new VelocityEngine();
+        ve.addProperty(RuntimeConstants.SET_NULL_ALLOWED, "true");
+        ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH);
+        ve.init();
+    
+        checkTemplate(ve,"set2");
+    }
+
+    public void checkTemplate(VelocityEngine ve, String templateName)
+    throws Exception
+    {
+        Template template;
+        FileOutputStream fos;
+        Writer fwriter;
+        Context context;
+
+        template = ve.getTemplate( getFileName(null, templateName, TMPL_FILE_EXT) );
+
+        fos = new FileOutputStream (
+                getFileName(RESULTS_DIR, templateName, RESULT_FILE_EXT));
+
+        fwriter = new BufferedWriter( new OutputStreamWriter(fos) );
+
+        context = new VelocityContext();
+        template.merge(context, fwriter);
+        fwriter.flush();
+        fwriter.close();
+
+        if (!isMatch(RESULTS_DIR, COMPARE_DIR, templateName, RESULT_FILE_EXT, CMP_FILE_EXT))
+        {
+            fail("Output incorrect.");
+        }        
+    }
+
+}
+

Propchange: jakarta/velocity/core/trunk/src/test/org/apache/velocity/test/SetTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/velocity/core/trunk/src/test/org/apache/velocity/test/SetTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Id Author Date Revision

Propchange: jakarta/velocity/core/trunk/test/set/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sun Nov 13 00:10:26 2005
@@ -0,0 +1 @@
+results

Added: jakarta/velocity/core/trunk/test/set/compare/set1.cmp
URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/test/set/compare/set1.cmp?rev=332946&view=auto
==============================================================================
--- jakarta/velocity/core/trunk/test/set/compare/set1.cmp (added)
+++ jakarta/velocity/core/trunk/test/set/compare/set1.cmp Sun Nov 13 00:10:26 2005
@@ -0,0 +1,4 @@
+set1
+
+123
+123
\ No newline at end of file

Added: jakarta/velocity/core/trunk/test/set/compare/set2.cmp
URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/test/set/compare/set2.cmp?rev=332946&view=auto
==============================================================================
--- jakarta/velocity/core/trunk/test/set/compare/set2.cmp (added)
+++ jakarta/velocity/core/trunk/test/set/compare/set2.cmp Sun Nov 13 00:10:26 2005
@@ -0,0 +1,4 @@
+set2
+
+123
+$abc
\ No newline at end of file

Added: jakarta/velocity/core/trunk/test/set/set1.vm
URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/test/set/set1.vm?rev=332946&view=auto
==============================================================================
--- jakarta/velocity/core/trunk/test/set/set1.vm (added)
+++ jakarta/velocity/core/trunk/test/set/set1.vm Sun Nov 13 00:10:26 2005
@@ -0,0 +1,8 @@
+## This template is used for the case in which #set with a null
+## is not accepted
+set1
+
+#set($abc = "123")
+$abc
+#set($abc = $boohoo)
+$abc
\ No newline at end of file

Added: jakarta/velocity/core/trunk/test/set/set2.vm
URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/test/set/set2.vm?rev=332946&view=auto
==============================================================================
--- jakarta/velocity/core/trunk/test/set/set2.vm (added)
+++ jakarta/velocity/core/trunk/test/set/set2.vm Sun Nov 13 00:10:26 2005
@@ -0,0 +1,8 @@
+## This template is used for the case in which #set with a null
+## is not accepted
+set2
+
+#set($abc = "123")
+$abc
+#set($abc = $boohoo)
+$abc
\ No newline at end of file

Modified: jakarta/velocity/core/trunk/xdocs/docs/developer-guide.xml
URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/xdocs/docs/developer-guide.xml?rev=332946&r1=332945&r2=332946&view=diff
==============================================================================
--- jakarta/velocity/core/trunk/xdocs/docs/developer-guide.xml (original)
+++ jakarta/velocity/core/trunk/xdocs/docs/developer-guide.xml Sun Nov 13 00:10:26 2005
@@ -1260,7 +1260,8 @@
 <i><code>org.apache.velocity.app.event.NullSetEventHandler</code></i>
 
 <blockquote>
-When a #set() results in a null assignment, this is normally
+When a #set() rejects an assignment due to the right hand side being an invalid
+or null reference, this is normally
 logged.  The <code>NullSetEventHandler</code> allows you to 'veto' the
 logging of this condition.
 <br/>
@@ -1506,6 +1507,17 @@
 <p>
 <code>directive.foreach.maxloops = -1</code><br/>
 Maximum allowed number of loops for a #foreach() statement.
+</p>
+
+<p>
+<strong>#set() Directive</strong>
+</p>
+
+<p>
+<code>directive.set.null.allowed = false</code><br/>
+If true, having a right hand side of a #set() statement with
+an invalid reference or null value will set the left hand side to null.
+If false, the left hand side will stay the same.
 </p>
 
 <p>

Modified: jakarta/velocity/core/trunk/xdocs/docs/user-guide.xml
URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/xdocs/docs/user-guide.xml?rev=332946&r1=332945&r2=332946&view=diff
==============================================================================
--- jakarta/velocity/core/trunk/xdocs/docs/user-guide.xml (original)
+++ jakarta/velocity/core/trunk/xdocs/docs/user-guide.xml Sun Nov 13 00:10:26 2005
@@ -919,9 +919,12 @@
 
  <p>
     If the RHS is a property or method reference that evaluates to
-    <em>null</em>, it will <b>not</b> be assigned to the LHS.  It is
-    not possible to remove an existing reference from the context via
-    this mechanism.  This can be confusing for
+    <em>null</em>, it will <b>not</b> be assigned to the LHS.  
+	Depending on how Velocity is configured, it is usually not
+    possible to remove an existing reference from the context via
+    this mechanism.  
+	(Note that this can be permitted by changing one of the Velocity configuration properties).
+	This can be confusing for
     newcomers to Velocity.  For example:
  </p>
 



---------------------------------------------------------------------
To unsubscribe, e-mail: velocity-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: velocity-dev-help@jakarta.apache.org