You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by cb...@apache.org on 2017/02/20 10:58:58 UTC
svn commit: r1783739 - in /velocity/engine/trunk/velocity-engine-core/src:
main/java/org/apache/velocity/runtime/
main/java/org/apache/velocity/runtime/parser/node/
main/java/org/apache/velocity/util/
main/resources/org/apache/velocity/runtime/defaults...
Author: cbrisson
Date: Mon Feb 20 10:58:58 2017
New Revision: 1783739
URL: http://svn.apache.org/viewvc?rev=1783739&view=rev
Log:
[engine] implements new strategy for reference boolean evaluation
1) return false for a null object
2) return its value for a Boolean object, or the result of the getAsBoolean() method if it exists.
3) If directive.if.emptycheck = false (true by default), stop here and return true.
4) check for emptiness:
- return whether an array is empty.
- return whether isEmpty() is false (covers String and all Collection classes).
- return whether length() is zero (covers CharSequence classes other than String).
- returns whether size() is zero.
- return whether a Number *strictly* equals zero.
5) check for emptiness after explicit conversion methods:
- return whether the result of getAsString() is empty (and false for a null result) if it exists.
- return whether the result of getAsNumber() *strictly* equals zero (and false for a null result) if it exists.
Modified:
velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.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/main/java/org/apache/velocity/util/DuckType.java
velocity/engine/trunk/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties
velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java?rev=1783739&r1=1783738&r2=1783739&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java Mon Feb 20 10:58:58 2017
@@ -76,6 +76,12 @@ public interface RuntimeConstants
String SKIP_INVALID_ITERATOR = "directive.foreach.skip.invalid";
/**
+ * An empty object (string, collection) or zero number is false.
+ * @since 2.0
+ */
+ String CHECK_EMPTY_OBJECTS = "directive.if.emptycheck";
+
+ /**
* Starting tag for error messages triggered by passing a parameter not allowed in the #include directive. Only string literals,
* and references are allowed.
*/
@@ -98,7 +104,7 @@ public interface RuntimeConstants
* @since 1.7
*/
String PROVIDE_SCOPE_CONTROL = "provide.scope.control";
-
+
/*
* ----------------------------------------------------------------------
* R E S O U R C E M A N A G E R C O N F I G U R A T I O N
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=1783739&r1=1783738&r2=1783739&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 Mon Feb 20 10:58:58 2017
@@ -579,7 +579,7 @@ public class ASTReference extends Simple
}
try
{
- return DuckType.asBoolean(value);
+ return DuckType.asBoolean(value, rsvc.getBoolean(RuntimeConstants.CHECK_EMPTY_OBJECTS, true));
}
catch(Exception e)
{
Modified: 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=1783739&r1=1783738&r2=1783739&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/DuckType.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/DuckType.java Mon Feb 20 10:58:58 2017
@@ -23,9 +23,12 @@ import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
+import static org.apache.velocity.runtime.parser.node.MathUtils.isZero;
+
/**
* Support for getAs<Type>() convention for rendering (String), evaluating (Boolean)
* or doing math with (Number) references.
@@ -40,7 +43,9 @@ public class DuckType
STRING("getAsString"),
NUMBER("getAsNumber"),
BOOLEAN("getAsBoolean"),
- EMPTY("isEmpty");
+ EMPTY("isEmpty"),
+ LENGTH("length"),
+ SIZE("size");
final String name;
final Map<Class,Object> cache = new HashMap();
@@ -93,11 +98,6 @@ public class DuckType
get(value, Types.NUMBER) == null;
}
- public static boolean asBoolean(Object value)
- {
- return asBoolean(value, true);
- }
-
public static boolean asBoolean(Object value, boolean coerceType)
{
if (value == null)
@@ -129,23 +129,37 @@ public class DuckType
return true;
}
- // empty string
- if (value instanceof CharSequence)
+ // empty array
+ if (value.getClass().isArray())
{
- return ((CharSequence)value).length() == 0;
+ return Array.getLength(value) == 0;// [] is false
}
- // isEmpty() object
+ // isEmpty() for object / string
Object isEmpty = get(value, Types.EMPTY);
if (isEmpty != NO_METHOD)
{
return (Boolean)isEmpty;
}
- // empty array
- if (value.getClass().isArray())
+ // isEmpty() for object / other char sequences
+ Object length = get(value, Types.LENGTH);
+ if (length != NO_METHOD && length instanceof Number)
{
- return Array.getLength(value) == 0;// [] is false
+ return isZero((Number)length);
+ }
+
+ // size() object / collection
+ Object size = get(value, Types.SIZE);
+ if (size != NO_METHOD && size instanceof Number)
+ {
+ return isZero((Number)size);
+ }
+
+ // zero numbers are false
+ if (value instanceof Number)
+ {
+ return isZero((Number)value);
}
// null getAsString()
@@ -166,10 +180,13 @@ public class DuckType
{
return true;
}
+ // zero numbers are false
+ else if (asNumber != NO_METHOD && asNumber instanceof Number)
+ {
+ return isZero((Number)asNumber);
+ }
- // empty toString()
- String string = value.toString();
- return string == null || string.length() == 0;
+ return false;
}
public static Number asNumber(Object value)
Modified: velocity/engine/trunk/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties?rev=1783739&r1=1783738&r2=1783739&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties Mon Feb 20 10:58:58 2017
@@ -44,6 +44,15 @@ runtime.string.interning = true
directive.foreach.maxloops = -1
# ----------------------------------------------------------------------------
+# I F P R O P E R T I E S
+# ----------------------------------------------------------------------------
+# This property controls whether empty strings and collections,
+# as long as zero numbers, do evaluate to false.
+# ----------------------------------------------------------------------------
+
+directive.if.emptycheck = true
+
+# ----------------------------------------------------------------------------
# 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: 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=1783739&r1=1783738&r2=1783739&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java Mon Feb 20 10:58:58 2017
@@ -19,7 +19,13 @@ package org.apache.velocity.test;
* under the License.
*/
+import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.Collections;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
/**
* Used to check that empty values are properly handled in #if statements
@@ -37,6 +43,12 @@ public class IfEmptyTestCase extends Bas
assertEvalEquals("", "#if( $obj )fail#end");
}
+ protected void assertNotEmpty(Object obj)
+ {
+ context.put("obj", obj);
+ assertEvalEquals("", "#if( !$obj )fail#end");
+ }
+
public void testNull()
{
assertEmpty(null);
@@ -49,13 +61,43 @@ public class IfEmptyTestCase extends Bas
assertEmpty(Collections.emptyMap());
assertEmpty(Collections.emptyList());
assertEmpty(new Object[]{});
+ List list = new ArrayList();
+ list.add(1);
+ assertNotEmpty(list);
+ Map map = new TreeMap();
+ map.put("foo", 1);
+ assertNotEmpty(map);
}
public void testString()
{
assertEmpty("");
assertEmpty(new EmptyAsString());
- assertEmpty(new EmptyToString());
+ assertNotEmpty("hello");
+ }
+
+ public void testNumber()
+ {
+ assertEmpty(0);
+ assertEmpty(0L);
+ assertEmpty(0.0f);
+ assertEmpty(0.0);
+ assertEmpty(BigInteger.ZERO);
+ assertEmpty(BigDecimal.ZERO);
+ assertNotEmpty(1);
+ assertNotEmpty(1L);
+ assertNotEmpty(1.0f);
+ assertNotEmpty(1.0);
+ assertNotEmpty(BigInteger.ONE);
+ assertNotEmpty(BigDecimal.ONE);
+ }
+
+ public void testStringBuilder()
+ {
+ StringBuilder builder = new StringBuilder();
+ assertEmpty(builder);
+ builder.append("yo");
+ assertNotEmpty(builder);
}
public static class NullAsString
@@ -82,12 +124,4 @@ public class IfEmptyTestCase extends Bas
}
}
- public static class EmptyToString
- {
- public String toString()
- {
- return "";
- }
- }
-
}