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/01/15 07:53:09 UTC
svn commit: r125251 - in jakarta/velocity/trunk: src/java/org/apache/velocity/runtime/directive src/java/org/apache/velocity/test test/templates test/templates/compare
Author: wglass
Date: Fri Jan 14 22:53:07 2005
New Revision: 125251
URL: http://svn.apache.org/viewcvs?view=rev&rev=125251
Log:
Allow #foreach to handle null values. http://issues.apache.org/bugzilla/show_bug.cgi?id=27741
Added:
jakarta/velocity/trunk/test/templates/compare/foreach-null-list.cmp
jakarta/velocity/trunk/test/templates/foreach-null-list.vm
Modified:
jakarta/velocity/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java
jakarta/velocity/trunk/src/java/org/apache/velocity/test/TemplateTestCase.java
jakarta/velocity/trunk/test/templates/templates.properties
Modified: jakarta/velocity/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java
Url: http://svn.apache.org/viewcvs/jakarta/velocity/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java?view=diff&rev=125251&p1=jakarta/velocity/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java&r1=125250&p2=jakarta/velocity/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java&r2=125251
==============================================================================
--- jakarta/velocity/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java (original)
+++ jakarta/velocity/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java Fri Jan 14 22:53:07 2005
@@ -21,10 +21,15 @@
import java.util.Iterator;
-import org.apache.velocity.runtime.RuntimeServices;
-import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.app.event.EventCartridge;
import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.context.Context;
+
+import org.apache.velocity.runtime.resource.Resource;
+
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.runtime.parser.node.SimpleNode;
@@ -35,6 +40,7 @@
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.util.introspection.Info;
+import org.apache.velocity.util.introspection.IntrospectionCacheData;
/**
* Foreach directive used for moving through arrays,
@@ -42,11 +48,202 @@
*
* @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
- * @version $Id: Foreach.java,v 1.48 2004/03/20 03:35:50 dlr Exp $
+ * @version $Id$
*/
public class Foreach extends Directive
{
/**
+ * A special context to use when the foreach iterator returns a null. This
+ * is required since the standard context may not support nulls.
+ * All puts and gets are passed through, except for the foreach iterator key.
+ */
+ protected class NullHolderContext implements InternalContextAdapter
+ {
+ private InternalContextAdapter innerContext = null;
+ private String loopVariableKey = "";
+ private boolean active = true;
+
+ /**
+ * Create the context as a wrapper to be used within the foreach
+ * @param key the reference used in the foreach
+ * @param context the parent context
+ */
+ private NullHolderContext( String key, InternalContextAdapter context )
+ {
+ innerContext = context;
+ if( key != null )
+ loopVariableKey = key;
+ }
+
+ /**
+ * Get an object from the context, or null if the key is equal to the loop variable
+ * @see org.apache.velocity.context.InternalContextAdapter#get(java.lang.String)
+ */
+ public Object get( String key )
+ {
+ return ( active && loopVariableKey.equals(key) )
+ ? null
+ : innerContext.get(key);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#put(java.lang.String key, java.lang.Object value)
+ */
+ public Object put( String key, Object value )
+ {
+ if( loopVariableKey.equals(key) && (value == null) )
+ {
+ active = true;
+ }
+
+ return innerContext.put( key, value );
+ }
+
+ /**
+ * Does the context contain the key
+ * @see org.apache.velocity.context.InternalContextAdapter#containsKey(java.lang.Object key)
+ */
+ public boolean containsKey( Object key )
+ {
+ return innerContext.containsKey(key);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#getKeys()
+ */
+ public Object[] getKeys()
+ {
+ return innerContext.getKeys();
+ }
+
+ /**
+ * Remove an object from the context
+ * @see org.apache.velocity.context.InternalContextAdapter#remove(java.lang.Object key)
+ */
+ public Object remove(Object key)
+ {
+ if( loopVariableKey.equals(key) )
+ {
+ active = false;
+ }
+ return innerContext.remove(key);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#pushCurrentTemplateName(java.lang.String s)
+ */
+ public void pushCurrentTemplateName(String s)
+ {
+ innerContext.pushCurrentTemplateName(s);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#popCurrentTemplateName()
+ */
+ public void popCurrentTemplateName()
+ {
+ innerContext.popCurrentTemplateName();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#getCurrentTemplateName()
+ */
+ public String getCurrentTemplateName()
+ {
+ return innerContext.getCurrentTemplateName();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#getTemplateNameStack()
+ */
+ public Object[] getTemplateNameStack()
+ {
+ return innerContext.getTemplateNameStack();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#icacheGet(java.lang.Object key)
+ */
+ public IntrospectionCacheData icacheGet(Object key)
+ {
+ return innerContext.icacheGet(key);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#icachePut(java.lang.Object key, org.apache.velocity.util.introspection.IntrospectionCacheData o)
+ */
+ public void icachePut(Object key, IntrospectionCacheData o)
+ {
+ innerContext.icachePut(key,o);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#setCurrentResource(org.apache.velocity.runtime.resource.Resource r)
+ */
+ public void setCurrentResource( Resource r )
+ {
+ innerContext.setCurrentResource(r);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#getCurrentResource()
+ */
+ public Resource getCurrentResource()
+ {
+ return innerContext.getCurrentResource();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#getBaseContext()
+ */
+ public InternalContextAdapter getBaseContext()
+ {
+ return innerContext.getBaseContext();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#getInternalUserContext()
+ */
+ public Context getInternalUserContext()
+ {
+ return innerContext.getInternalUserContext();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#attachEventCartridge(org.apache.velocity.app.event.EventCartridge ec)
+ */
+ public EventCartridge attachEventCartridge(EventCartridge ec)
+ {
+ return innerContext.attachEventCartridge(ec);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#getEventCartridge()
+ */
+ public EventCartridge getEventCartridge()
+ {
+ return innerContext.getEventCartridge();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#getAllowRendering()
+ */
+ public boolean getAllowRendering()
+ {
+ return innerContext.getAllowRendering();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalContextAdapter#setAllowRendering(boolean v)
+ */
+ public void setAllowRendering(boolean v)
+ {
+ innerContext.setAllowRendering(v);
+ }
+
+ }
+
+ /**
* Return name of this directive.
*/
public String getName()
@@ -174,11 +371,35 @@
Object o = context.get(elementKey);
Object ctr = context.get( counterName);
+ /**
+ * Instantiate the null holder context if a null value
+ * is returned by the foreach iterator. Only one instance is
+ * created - it's reused for every null value.
+ */
+ NullHolderContext nullHolderContext = null;
+
while (i.hasNext())
{
context.put( counterName , new Integer(counter));
- context.put(elementKey,i.next());
- node.jjtGetChild(3).render(context, writer);
+ Object value = i.next();
+ context.put(elementKey, value);
+
+ /**
+ * If the value is null, use the special null holder context
+ */
+ if( value == null )
+ {
+ if( nullHolderContext == null )
+ {
+ // lazy instantiation
+ nullHolderContext = new NullHolderContext(elementKey, context);
+ }
+ node.jjtGetChild(3).render(nullHolderContext, writer);
+ }
+ else
+ {
+ node.jjtGetChild(3).render(context, writer);
+ }
counter++;
}
Modified: jakarta/velocity/trunk/src/java/org/apache/velocity/test/TemplateTestCase.java
Url: http://svn.apache.org/viewcvs/jakarta/velocity/trunk/src/java/org/apache/velocity/test/TemplateTestCase.java?view=diff&rev=125251&p1=jakarta/velocity/trunk/src/java/org/apache/velocity/test/TemplateTestCase.java&r1=125250&p2=jakarta/velocity/trunk/src/java/org/apache/velocity/test/TemplateTestCase.java&r2=125251
==============================================================================
--- jakarta/velocity/trunk/src/java/org/apache/velocity/test/TemplateTestCase.java (original)
+++ jakarta/velocity/trunk/src/java/org/apache/velocity/test/TemplateTestCase.java Fri Jan 14 22:53:07 2005
@@ -62,7 +62,7 @@
* @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:jon@latchkey.com">Jon S. Stevens</a>
- * @version $Id: TemplateTestCase.java,v 1.36 2004/03/19 17:13:38 dlr Exp $
+ * @version $Id$
*/
public class TemplateTestCase extends BaseTestCase implements TemplateTestBase
{
@@ -158,6 +158,17 @@
context.put("obarr", oarr );
context.put("enumerator", vec.elements());
context.put("intarr", intarr );
+
+ /**
+ * Test #foreach() with a list containing nulls
+ */
+ ArrayList nullList = new ArrayList();
+ nullList.add("a");
+ nullList.add("b");
+ nullList.add(null);
+ nullList.add("d");
+ context.put("nullList", nullList);
+
}
/**
Added: jakarta/velocity/trunk/test/templates/compare/foreach-null-list.cmp
Url: http://svn.apache.org/viewcvs/jakarta/velocity/trunk/test/templates/compare/foreach-null-list.cmp?view=auto&rev=125251
==============================================================================
--- (empty file)
+++ jakarta/velocity/trunk/test/templates/compare/foreach-null-list.cmp Fri Jan 14 22:53:07 2005
@@ -0,0 +1,12 @@
+
+
+Foreach with a list that contains null.
+
+ This is a.
+ 1
+ This is b.
+ 2
+ This is $element.
+ 3
+ This is d.
+ 4
Added: jakarta/velocity/trunk/test/templates/foreach-null-list.vm
Url: http://svn.apache.org/viewcvs/jakarta/velocity/trunk/test/templates/foreach-null-list.vm?view=auto&rev=125251
==============================================================================
--- (empty file)
+++ jakarta/velocity/trunk/test/templates/foreach-null-list.vm Fri Jan 14 22:53:07 2005
@@ -0,0 +1,17 @@
+#*
+
+@test foreach-null-list.vm
+
+This template is used for Velocity regression testing.
+If you alter this template make sure you change the
+corresponding comparison file so that the regression
+test doesn't fail incorrectly.
+
+*#
+
+Foreach with a list that contains null.
+
+#foreach ($element in $nullList)
+ This is $element.
+ $velocityCount
+#end
Modified: jakarta/velocity/trunk/test/templates/templates.properties
Url: http://svn.apache.org/viewcvs/jakarta/velocity/trunk/test/templates/templates.properties?view=diff&rev=125251&p1=jakarta/velocity/trunk/test/templates/templates.properties&r1=125250&p2=jakarta/velocity/trunk/test/templates/templates.properties&r2=125251
==============================================================================
--- jakarta/velocity/trunk/test/templates/templates.properties (original)
+++ jakarta/velocity/trunk/test/templates/templates.properties Fri Jan 14 22:53:07 2005
@@ -44,3 +44,4 @@
test.template.42 = string
test.template.43 = stop1
test.template.44 = stop2
+test.template.45 = foreach-null-list
---------------------------------------------------------------------
To unsubscribe, e-mail: velocity-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: velocity-dev-help@jakarta.apache.org