Author: cbrisson Date: Wed Jun 5 23:46:02 2019 New Revision: 1860691 URL: http://svn.apache.org/viewvc?rev=1860691&view=rev Log: [engine][VELOCITY-915] Add new backward compatibility flags to mimic 1.7 behavior for invalid references event handlers
Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java 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/test/java/org/apache/velocity/test/BuiltInEventHandlerTestCase.java Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java?rev=1860691&r1=1860690&r2=1860691&view=diff ============================================================================== --- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java (original) +++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/app/event/implement/ReportInvalidReferences.java Wed Jun 5 23:46:02 2019 @@ -25,6 +25,7 @@ import org.apache.velocity.exception.Par import org.apache.velocity.runtime.RuntimeServices; import org.apache.velocity.util.RuntimeServicesAware; import org.apache.velocity.util.introspection.Info; +import org.slf4j.Logger; import java.util.ArrayList; import java.util.List; @@ -39,7 +40,7 @@ import java.util.List; * Note that InvalidReferenceHandler can be used * in two modes. If the Velocity properties file contains the following: * <pre> - * eventhandler.invalidreference.exception = true + * event_handler.invalid_references.exception = true * </pre> * then the event handler will throw a ParseErrorRuntimeException upon * hitting the first invalid reference. This stops processing and is @@ -61,8 +62,10 @@ import java.util.List; public class ReportInvalidReferences implements InvalidReferenceEventHandler, RuntimeServicesAware { + public static final String EVENTHANDLER_INVALIDREFERENCE_EXCEPTION = "event_handler.invalid_references.exception"; - public static final String EVENTHANDLER_INVALIDREFERENCE_EXCEPTION = "eventhandler.invalidreference.exception"; + @Deprecated + public static final String OLD_EVENTHANDLER_INVALIDREFERENCE_EXCEPTION = "eventhandler.invalidreference.exception"; /** * List of InvalidReferenceInfo objects @@ -172,9 +175,16 @@ public class ReportInvalidReferences imp */ public void setRuntimeServices(RuntimeServices rs) { - stopOnFirstInvalidReference = rs.getConfiguration().getBoolean( - EVENTHANDLER_INVALIDREFERENCE_EXCEPTION, - false); + Boolean b = rs.getConfiguration().getBoolean(OLD_EVENTHANDLER_INVALIDREFERENCE_EXCEPTION, null); + if (b == null) + { + b = rs.getConfiguration().getBoolean(EVENTHANDLER_INVALIDREFERENCE_EXCEPTION, false); + } + else + { + rs.getLog().warn("configuration key '{}' has been deprecated in favor of '{}'", OLD_EVENTHANDLER_INVALIDREFERENCE_EXCEPTION, EVENTHANDLER_INVALIDREFERENCE_EXCEPTION); + } + stopOnFirstInvalidReference = b.booleanValue(); } } 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=1860691&r1=1860690&r2=1860691&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 Wed Jun 5 23:46:02 2019 @@ -274,6 +274,30 @@ public interface RuntimeConstants extend */ String EVENTHANDLER_INVALIDREFERENCES = "event_handler.invalid_references.class"; + /** + * The <code>event_handler.invalid_references.quiet</code> property specifies if invalid quiet references + * (as in <code>$!foo</code>) trigger events (defaults to false). + * {@link org.apache.velocity.app.event.InvalidReferenceEventHandler} implementations to use. + * @since 2.2 + */ + String EVENTHANDLER_INVALIDREFERENCES_QUIET = "event_handler.invalid_references.quiet"; + + /** + * The <code>event_handler.invalid_references.null</code> property specifies if invalid null references + * (aka the value is present in the context or parent object but is null or a method returned null) + * trigger invalid reference events (defaults to false). + * {@link org.apache.velocity.app.event.InvalidReferenceEventHandler} implementations to use. + * @since 2.2 + */ + String EVENTHANDLER_INVALIDREFERENCES_NULL = "event_handler.invalid_references.null"; + + /** + * The <code>event_handler.invalid_references.tested</code> property specifies if invalid tested references + * (as in <code>#if($foo)</code> ) trigger invalid reference events (defaults to false). + * {@link org.apache.velocity.app.event.InvalidReferenceEventHandler} implementations to use. + * @since 2.2 + */ + String EVENTHANDLER_INVALIDREFERENCES_TESTED = "event_handler.invalid_references.tested"; /* * ---------------------------------------------------------------------- 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=1860691&r1=1860690&r2=1860691&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 Wed Jun 5 23:46:02 2019 @@ -102,6 +102,25 @@ public class ASTReference extends Simple private int numChildren = 0; + /** + * Whether to trigger an event for invalid quiet references + * @since 2.2 + */ + private boolean warnInvalidQuietReferences = false; + + /** + * Whether to trigger an event for invalid null references, that is when a value + * is present in the context or parent object but is null + * @since 2.2 + */ + private boolean warnInvalidNullReferences = false; + + /** + * Whether to trigger an event for invalid tested references - as in #if($foo) + * @since 2.2 + */ + private boolean warnInvalidTestedReferences = false; + protected Info uberInfo; /** @@ -196,6 +215,16 @@ public class ASTReference extends Simple checkEmpty = rsvc.getBoolean(RuntimeConstants.CHECK_EMPTY_OBJECTS, true); + /* invalid references special cases */ + + warnInvalidQuietReferences = + rsvc.getBoolean(RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES_QUIET, false); + warnInvalidNullReferences = + rsvc.getBoolean(RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES_NULL, false); + warnInvalidTestedReferences = + rsvc.getBoolean(RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES_TESTED, false); + + /** * In the case we are referencing a variable with #if($foo) or * #if( ! $foo) then we allow variables to be undefined and we @@ -272,23 +301,28 @@ public class ASTReference extends Simple Object result = getRootVariableValue(context); + /* a reference which has been provided an alternate value + * is *knowingly* potentially null and should be accepted + * in strict mode (except if the alternate value is null) + */ + if (astAlternateValue != null && (result == null || !DuckType.asBoolean(result, false))) + { + result = astAlternateValue.value(context); + } + if (result == null && !strictRef) { /* * do not trigger an invalid reference if the reference is present, but with a null value * don't either for a quiet reference or inside an #if/#elseif evaluation context */ - if (referenceType != QUIET_REFERENCE && - (numChildren > 0 || - !context.containsKey(rootString) && !onlyTestingReference)) + if ((referenceType != QUIET_REFERENCE || warnInvalidQuietReferences) && + (numChildren > 0 || + (!context.containsKey(rootString) || warnInvalidNullReferences) && + (!onlyTestingReference || warnInvalidTestedReferences))) { result = EventHandlerUtil.invalidGetMethod(rsvc, context, - "$" + rootString, null, null, uberInfo); - } - - if (result == null && astAlternateValue != null) - { - result = astAlternateValue.value(context); + "$" + rootString, null, null, uberInfo); } return result; @@ -311,6 +345,7 @@ public class ASTReference extends Simple { Object previousResult = result; int failedChild = -1; + for (int i = 0; i < numChildren; i++) { if (strictRef && result == null) @@ -327,6 +362,10 @@ public class ASTReference extends Simple } previousResult = result; result = jjtGetChild(i).execute(result,context); + if (astAlternateValue != null && (result == null || !DuckType.asBoolean(result, checkEmpty))) + { + result = astAlternateValue.value(context); + } if (result == null && !strictRef) // If strict and null then well catch this // next time through the loop { @@ -344,7 +383,9 @@ public class ASTReference extends Simple * don't either for a quiet reference, * or inside an #if/#elseif evaluation context when there's no child */ - if (!context.containsKey(rootString) && referenceType != QUIET_REFERENCE && (!onlyTestingReference || numChildren > 0)) + if ((!context.containsKey(rootString) || warnInvalidNullReferences) && + (referenceType != QUIET_REFERENCE || warnInvalidQuietReferences) && + (!onlyTestingReference || warnInvalidTestedReferences || numChildren > 0)) { result = EventHandlerUtil.invalidGetMethod(rsvc, context, "$" + rootString, previousResult, null, uberInfo); @@ -357,9 +398,9 @@ public class ASTReference extends Simple // (it means the getter has been called and returned null) // do not either for a quiet reference or if the *last* child failed while testing the reference Object getter = context.icacheGet(child); - if (getter == null && - referenceType != QUIET_REFERENCE && - (!onlyTestingReference || failedChild < numChildren - 1)) + if ((getter == null || warnInvalidNullReferences) && + (referenceType != QUIET_REFERENCE || warnInvalidQuietReferences) && + (!onlyTestingReference || warnInvalidTestedReferences || failedChild < numChildren - 1)) { StringBuilder name = new StringBuilder("$").append(rootString); for (int i = 0; i <= failedChild; i++) @@ -391,14 +432,6 @@ public class ASTReference extends Simple } } - /* - * Time to try the alternate value if needed - */ - if (astAlternateValue != null && (result == null || !DuckType.asBoolean(result, checkEmpty))) - { - result = astAlternateValue.value(context); - } - return result; } catch(MethodInvocationException mie) Modified: velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/BuiltInEventHandlerTestCase.java URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/BuiltInEventHandlerTestCase.java?rev=1860691&r1=1860690&r2=1860691&view=diff ============================================================================== --- velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/BuiltInEventHandlerTestCase.java (original) +++ velocity/engine/trunk/velocity-engine-core/src/test/java/org/apache/velocity/test/BuiltInEventHandlerTestCase.java Wed Jun 5 23:46:02 2019 @@ -128,9 +128,10 @@ public class BuiltInEventHandlerTestCase context.put("a1","test"); context.put("b1","test"); + context.put("n1", null); Writer writer = new StringWriter(); - ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar()"); + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar() $!c1 $n1 $!n1 #if($c1) nop #end"); List errors = reporter.getInvalidReferences(); assertEquals(2,errors.size()); @@ -143,7 +144,7 @@ public class BuiltInEventHandlerTestCase public void testReportInvalidReferences2() throws Exception { VelocityEngine ve = new VelocityEngine(); - ve.setProperty("eventhandler.invalidreference.exception","true"); + ve.setProperty("event_handler.invalid_references.exception","true"); ReportInvalidReferences reporter = new ReportInvalidReferences(); ve.init(); @@ -169,6 +170,137 @@ public class BuiltInEventHandlerTestCase } /** + * Test reporting of invalid syntax + * @throws Exception + */ + public void testReportQuietInvalidReferences() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty("event_handler.invalid_references.quiet","true"); + ReportInvalidReferences reporter = new ReportInvalidReferences(); + ve.init(); + + VelocityContext context = new VelocityContext(); + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(reporter); + ec.attachToContext(context); + + context.put("a1","test"); + context.put("b1","test"); + context.put("n1", null); + Writer writer = new StringWriter(); + + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar() $!c1 $n1 $!n1 #if($c1) nop #end"); + + List errors = reporter.getInvalidReferences(); + assertEquals(3,errors.size()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference()); + assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(2)).getInvalidReference()); + + log("Caught invalid references (local configuration)."); + } + + /** + * Test reporting of invalid syntax + * @throws Exception + */ + public void testReportNullInvalidReferences() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty("event_handler.invalid_references.null","true"); + ReportInvalidReferences reporter = new ReportInvalidReferences(); + ve.init(); + + VelocityContext context = new VelocityContext(); + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(reporter); + ec.attachToContext(context); + + context.put("a1","test"); + context.put("b1","test"); + context.put("n1", null); + Writer writer = new StringWriter(); + + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar() $!c1 $n1 $!n1 #if($c1) nop #end"); + + List errors = reporter.getInvalidReferences(); + assertEquals(3,errors.size()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference()); + assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference()); + assertEquals("$n1",((InvalidReferenceInfo) errors.get(2)).getInvalidReference()); + + log("Caught invalid references (local configuration)."); + } + + /** + * Test reporting of invalid syntax + * @throws Exception + */ + public void testReportNullQuietInvalidReferences() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty("event_handler.invalid_references.quiet","true"); + ve.setProperty("event_handler.invalid_references.null","true"); + ReportInvalidReferences reporter = new ReportInvalidReferences(); + ve.init(); + + VelocityContext context = new VelocityContext(); + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(reporter); + ec.attachToContext(context); + + context.put("a1","test"); + context.put("b1","test"); + context.put("n1", null); + Writer writer = new StringWriter(); + + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar() $!c1 $n1 $!n1 #if($c1) nop #end"); + + List errors = reporter.getInvalidReferences(); + assertEquals(5,errors.size()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference()); + assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(2)).getInvalidReference()); + assertEquals("$n1",((InvalidReferenceInfo) errors.get(3)).getInvalidReference()); + assertEquals("$n1",((InvalidReferenceInfo) errors.get(4)).getInvalidReference()); + + log("Caught invalid references (local configuration)."); + } + + /** + * Test reporting of invalid syntax + * @throws Exception + */ + public void testReportTestedInvalidReferences() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty("event_handler.invalid_references.tested","true"); + ReportInvalidReferences reporter = new ReportInvalidReferences(); + ve.init(); + + VelocityContext context = new VelocityContext(); + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(reporter); + ec.attachToContext(context); + + context.put("a1","test"); + context.put("b1","test"); + context.put("n1", null); + Writer writer = new StringWriter(); + + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar() $!c1 $n1 $!n1 #if($c1) nop #end"); + + List errors = reporter.getInvalidReferences(); + assertEquals(3,errors.size()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference()); + assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(2)).getInvalidReference()); + + log("Caught invalid references (local configuration)."); + } + + /** * Test escaping * @throws Exception */