commons-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Eric Gravel" <Eric.Gra...@intervalintl.com>
Subject [jexl] RE: Question about checking for undefined properties versus null value properties
Date Tue, 01 May 2012 15:35:48 GMT
Hi Henri,

Your summary is dead on.  I wanted to receive all JexlException that
might be thrown. But the Interpreter doesn't always throw them; there's
cases where they are only thrown when lenient == false.

It's great to hear this is available in v3.x, however, I can't deploy
snapshot libraries to our production environment.  So I guess I'm left
with 2 options: 1) go back to lenient and wait for v3.0 final, or 2)
apply some fixes to 2.1.1 locally (if that's possible).

I've been able to make a change that seems to work but I don't know if
it's the best approach and whether it might have a negative impact or
side-effect on other parts of the Interprerter.  Here's the code changes
I've done, maybe you can take a quick look and let me know what you
think.


I've created a new JexlEngine that extends the library one.  Needed to
do this so that I could provide my own Interpreter; I overwrote the
createInterpreter().

	public class JexlEngine 
		extends org.apache.commons.jexl2.JexlEngine
	{
		public JexlEngine() {
			this(null, null, null, null);
		}

		public JexlEngine(Uberspect anUberspect, JexlArithmetic
anArithmetic, Map<String, Object> theFunctions, Log log) 
		{
			super(anUberspect, anArithmetic, theFunctions,
log);
		}
		
		protected Interpreter createInterpreter(JexlContext
context) {
			return createInterpreter(context, isStrict(),
isSilent());
		}

		protected Interpreter createInterpreter(JexlContext
context, boolean strictFlag, boolean silentFlag) {
			return new
IntervalInternationalJexlInterpreter(this, context == null ?
EMPTY_CONTEXT : context, strictFlag, silentFlag);
		}
	}


The Interpreter that I created simply checks if there was a return
object from uberspect.getPropertyGet() before calling theNode.jjAcept()
for an ASTIdentifier if the result variable wasn't null.  I store the
outcome in a Boolean variable that I check in the if (result == null) at
the end of the method.

	public class IntervalInternationalJexlInterpreter 
		extends org.apache.commons.jexl2.Interpreter 
	{
		
		public IntervalInternationalJexlInterpreter(JexlEngine
jexl, JexlContext aContext, boolean strictFlag, boolean silentFlag) 
		{
			super(jexl, aContext, strictFlag, silentFlag);
		}
		
		protected
IntervalInternationalJexlInterpreter(Interpreter base) 
		{
			super(base);
		}

		public Object visit(ASTReference node, Object data) {
			// could be array access, identifier or map
literal
			// followed by zero or more ("." and array
access, method, size,
			// identifier or integer literal)
			int numChildren = node.jjtGetNumChildren();
			// pass first piece of data in and loop through
children
			Object result = null;
			StringBuilder variableName = null;
			String propertyName = null;
			boolean isVariable = true;
			boolean hasGetterMethod = false;
			int v = 0;
			for (int c = 0; c < numChildren; c++) {
				if (isCancelled()) {
					throw new
JexlException.Cancel(node);
				}
				JexlNode theNode = node.jjtGetChild(c);
				propertyName = theNode.image;
				
				// integer literals may be part of an
antish var name only if no bean was found so far
				if (result == null && theNode instanceof
ASTNumberLiteral && ((ASTNumberLiteral) theNode).isInteger()) {
					isVariable &= v > 0;
				} else {
					isVariable &= (theNode
instanceof ASTIdentifier);
					if (result != null)
					{
						hasGetterMethod =
uberspect.getPropertyGet(result, theNode.image, theNode) != null;
					}
					result = theNode.jjtAccept(this,
result);                
				}
				
				// if we get null back a result, check
for an ant variable
				if (result == null && isVariable) {
					if (v == 0) {
						variableName = new
StringBuilder(node.jjtGetChild(0).image);
						v = 1;
					}
					for (; v <= c; ++v) {
	
variableName.append('.');
	
variableName.append(node.jjtGetChild(v).image);
					}
					result =
context.get(variableName.toString());
					
					if (result == null)
					{
						// break out of loop
since we can't get value of property/variable
						break;
					}

				}
			}
			if (result == null) {
				if (	isVariable &&
					!hasGetterMethod &&
					!isTernaryProtected(node)  && 
	
!(context.has(variableName.toString()) || 
					(numChildren == 1 &&
node.jjtGetChild(0) instanceof ASTIdentifier && ((ASTIdentifier)
node.jjtGetChild(0)).getRegister() >= 0))
				) {
					JexlException xjexl =
propertyName != null
							  ? new
JexlException.Property(node, propertyName)
							  : new
JexlException.Variable(node, variableName.toString());
					return unknownVariable(xjexl);
				}
			}
			return result;
		}
		
		protected boolean isTernaryProtected(JexlNode node) {
			for (JexlNode walk = node.jjtGetParent(); walk
!= null; walk = walk.jjtGetParent()) {
				if (walk instanceof ASTTernaryNode) {
					return true;
				} else if (!(walk instanceof
ASTReference || walk instanceof ASTArrayAccess)) {
					break;
				}
			}
			return false;
		}

	}

Eric A. Gravel
Application Architect - IT Application Services
Interval International
6262 Sunset Drive * Miami, Florida 33143
305.666.1861, ext. 7315 * fax 305.668.3409
eric.gravel@intervalintl.com
IntervalWorld.com * ResortDeveloper.com
Please consider the environment before printing this e-mail.


-----Original Message-----
From: henrib [mailto:henrib@apache.org] 
Sent: Tuesday, May 01, 2012 9:27 AM

Hi Eric,

If I may, your main question might be summarized as: Is there anyway to
have Jexl only throw an exception if a property or variable is undefined
when strict-mode is on?

The answer is "yes" with jexl3 (i.e. the trunk); the JexlArithmetic and
the JexlEngine may be configured with different "strict" modes,
JexlArithmetic dealing with whether "null" is an error as an operand and
the JexlEngine dealing with the "undefined" variable/property/methods.

This (new) test should exert this use case:


Is this is the behavior you expect?

Retrofitting this feature in 2.1.x is however not in the current plan;
I'll push a 3.0 SNAPSHOT out (i.e. maven snapshot) soon for convenience.
Hope this helps,
Regards.
Henrib


_____________________________________________________________________________
Scanned by IBM Email Security Management Services powered by MessageLabs. For more information
please visit http://www.ers.ibm.com
_____________________________________________________________________________

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Mime
View raw message