You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2013/07/15 12:01:00 UTC

svn commit: r1503158 - in /tomcat/trunk/java: javax/el/ org/apache/el/lang/ org/apache/el/parser/

Author: markt
Date: Mon Jul 15 10:00:59 2013
New Revision: 1503158

URL: http://svn.apache.org/r1503158
Log:
More lambda expression implementation. Handle the case of an expression assigned to a variable.

Modified:
    tomcat/trunk/java/javax/el/LambdaExpression.java
    tomcat/trunk/java/javax/el/LocalStrings.properties
    tomcat/trunk/java/org/apache/el/lang/EvaluationContext.java
    tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java
    tomcat/trunk/java/org/apache/el/parser/AstFunction.java
    tomcat/trunk/java/org/apache/el/parser/AstLambdaExpression.java
    tomcat/trunk/java/org/apache/el/parser/AstLambdaExpressionOrInvocation.java

Modified: tomcat/trunk/java/javax/el/LambdaExpression.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/javax/el/LambdaExpression.java?rev=1503158&r1=1503157&r2=1503158&view=diff
==============================================================================
--- tomcat/trunk/java/javax/el/LambdaExpression.java (original)
+++ tomcat/trunk/java/javax/el/LambdaExpression.java Mon Jul 15 10:00:59 2013
@@ -16,7 +16,9 @@
  */
 package javax.el;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class LambdaExpression {
 
@@ -34,15 +36,44 @@ public class LambdaExpression {
         this.context = context;
     }
 
-    public Object invoke(ELContext context , Object... args)
+    @SuppressWarnings("null") // args[i] can't be null due to earlier checks
+    public Object invoke(ELContext context, Object... args)
             throws ELException {
 
         if (context == null) {
             throw new NullPointerException();
         }
 
-        // TODO
-        return null;
+        int formalParamCount = 0;
+        if (formalParameters != null) {
+            formalParamCount = formalParameters.size();
+        }
+
+        int argCount = 0;
+        if (args != null) {
+            argCount = args.length;
+        }
+
+        if (formalParamCount > argCount) {
+            throw new ELException(Util.message(context,
+                    "error.lambda.args.tooFew",
+                    Integer.valueOf(argCount),
+                    Integer.valueOf(formalParamCount)));
+        }
+
+        // Build the argument map
+        Map<String,Object> lambdaArguments = new HashMap<>();
+        for (int i = 0; i < formalParamCount; i++) {
+            lambdaArguments.put(formalParameters.get(i), args[i]);
+        }
+
+        context.enterLambdaScope(lambdaArguments);
+
+        try {
+            return expression.getValue(context);
+        } finally {
+            context.exitLambdaScope();
+        }
     }
 
     public java.lang.Object invoke(Object... args) {

Modified: tomcat/trunk/java/javax/el/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/javax/el/LocalStrings.properties?rev=1503158&r1=1503157&r2=1503158&view=diff
==============================================================================
--- tomcat/trunk/java/javax/el/LocalStrings.properties (original)
+++ tomcat/trunk/java/javax/el/LocalStrings.properties Mon Jul 15 10:00:59 2013
@@ -41,6 +41,8 @@ importHandler.invalidPackage=The package
 importHandler.invalidStaticName=Name of static method or field to import [{0}] must include a class
 importHandler.staticNotFound=The static import [{0}] could not be found in class [{1}] for import [{2}]
 
+lambdaExpression.tooFewArgs=Only [{0}] arguments were provided for a lambda expression that requires at least [{1}]
+
 staticFieldELResolver.methodNotFound=No matching public static method named [{0}] found on class [{1}]
 staticFieldELResolver.notFound=No public static field named [{0}] was found on class [{1}]
 staticFieldELResolver.notWriteable=Writing to static fields (in this case field [{0}] on class [{1}]) is not permitted
\ No newline at end of file

Modified: tomcat/trunk/java/org/apache/el/lang/EvaluationContext.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/el/lang/EvaluationContext.java?rev=1503158&r1=1503157&r2=1503158&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/el/lang/EvaluationContext.java (original)
+++ tomcat/trunk/java/org/apache/el/lang/EvaluationContext.java Mon Jul 15 10:00:59 2013
@@ -17,11 +17,15 @@
 
 package org.apache.el.lang;
 
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
 import javax.el.ELContext;
 import javax.el.ELResolver;
+import javax.el.EvaluationListener;
 import javax.el.FunctionMapper;
+import javax.el.ImportHandler;
 import javax.el.VariableMapper;
 
 public final class EvaluationContext extends ELContext {
@@ -40,53 +44,113 @@ public final class EvaluationContext ext
     }
 
     public ELContext getELContext() {
-        return this.elContext;
+        return elContext;
     }
 
     @Override
     public FunctionMapper getFunctionMapper() {
-        return this.fnMapper;
+        return fnMapper;
     }
 
     @Override
     public VariableMapper getVariableMapper() {
-        return this.varMapper;
+        return varMapper;
     }
 
     @Override
     // Can't use Class<?> because API needs to match specification in superclass
     public Object getContext(Class key) {
-        return this.elContext.getContext(key);
+        return elContext.getContext(key);
     }
 
     @Override
     public ELResolver getELResolver() {
-        return this.elContext.getELResolver();
+        return elContext.getELResolver();
     }
 
     @Override
     public boolean isPropertyResolved() {
-        return this.elContext.isPropertyResolved();
+        return elContext.isPropertyResolved();
     }
 
     @Override
     // Can't use Class<?> because API needs to match specification in superclass
     public void putContext(Class key, Object contextObject) {
-        this.elContext.putContext(key, contextObject);
+        elContext.putContext(key, contextObject);
     }
 
     @Override
     public void setPropertyResolved(boolean resolved) {
-        this.elContext.setPropertyResolved(resolved);
+        elContext.setPropertyResolved(resolved);
     }
 
     @Override
     public Locale getLocale() {
-        return this.elContext.getLocale();
+        return elContext.getLocale();
         }
 
     @Override
     public void setLocale(Locale locale) {
-        this.elContext.setLocale(locale);
+        elContext.setLocale(locale);
+    }
+
+    @Override
+    public void setPropertyResolved(Object base, Object property) {
+        elContext.setPropertyResolved(base, property);
+    }
+
+    @Override
+    public ImportHandler getImportHandler() {
+        return elContext.getImportHandler();
+    }
+
+    @Override
+    public void addEvaluationListener(EvaluationListener listener) {
+        elContext.addEvaluationListener(listener);
+    }
+
+    @Override
+    public List<EvaluationListener> getEvaluationListeners() {
+        return elContext.getEvaluationListeners();
+    }
+
+    @Override
+    public void notifyBeforeEvaluation(String expression) {
+        elContext.notifyBeforeEvaluation(expression);
+    }
+
+    @Override
+    public void notifyAfterEvaluation(String expression) {
+        elContext.notifyAfterEvaluation(expression);
+    }
+
+    @Override
+    public void notifyPropertyResolved(Object base, Object property) {
+        elContext.notifyPropertyResolved(base, property);
+    }
+
+    @Override
+    public boolean isLambdaArgument(String name) {
+        return elContext.isLambdaArgument(name);
+    }
+
+    @Override
+    public Object getLambdaArgument(String name) {
+        return elContext.getLambdaArgument(name);
+    }
+
+    @Override
+    public void enterLambdaScope(Map<String, Object> arguments) {
+        elContext.enterLambdaScope(arguments);
+    }
+
+    @Override
+    public void exitLambdaScope() {
+        elContext.exitLambdaScope();
+    }
+
+    @Override
+    public Object convertToType(Object obj, Class<?> type) {
+        return elContext.convertToType(obj, type);
     }
 }

Modified: tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java?rev=1503158&r1=1503157&r2=1503158&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java (original)
+++ tomcat/trunk/java/org/apache/el/lang/ExpressionBuilder.java Mon Jul 15 10:00:59 2013
@@ -80,9 +80,6 @@ public final class ExpressionBuilder imp
 
     private final String expression;
 
-    /**
-     *
-     */
     public ExpressionBuilder(String expression, ELContext ctx)
             throws ELException {
         this.expression = expression;
@@ -189,15 +186,31 @@ public final class ExpressionBuilder imp
 
             AstFunction funcNode = (AstFunction) node;
 
+            Method m = null;
+
+            if (this.fnMapper != null) {
+                m = fnMapper.resolveFunction(funcNode.getPrefix(), funcNode
+                        .getLocalName());
+            }
+
+            // References to variables that refer to lambda expressions will be
+            // parsed as functions. This is handled at runtime but at this point
+            // need to treat it as a variable rather than a function.
+            if (m == null && this.varMapper != null &&
+                    funcNode.getPrefix().length() == 0) {
+                this.varMapper.resolveVariable(funcNode.getLocalName());
+                return;
+            }
+
             if (this.fnMapper == null) {
                 throw new ELException(MessageFactory.get("error.fnMapper.null"));
             }
-            Method m = fnMapper.resolveFunction(funcNode.getPrefix(), funcNode
-                    .getLocalName());
+
             if (m == null) {
                 throw new ELException(MessageFactory.get(
                         "error.fnMapper.method", funcNode.getOutputName()));
             }
+
             int pcnt = m.getParameterTypes().length;
             if (node.jjtGetNumChildren() != pcnt) {
                 throw new ELException(MessageFactory.get(

Modified: tomcat/trunk/java/org/apache/el/parser/AstFunction.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/el/parser/AstFunction.java?rev=1503158&r1=1503157&r2=1503158&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/el/parser/AstFunction.java (original)
+++ tomcat/trunk/java/org/apache/el/parser/AstFunction.java Mon Jul 15 10:00:59 2013
@@ -23,6 +23,7 @@ import java.lang.reflect.Method;
 
 import javax.el.ELException;
 import javax.el.FunctionMapper;
+import javax.el.LambdaExpression;
 
 import org.apache.el.lang.EvaluationContext;
 import org.apache.el.util.MessageFactory;
@@ -87,6 +88,24 @@ public final class AstFunction extends S
             throw new ELException(MessageFactory.get("error.fnMapper.null"));
         }
         Method m = fnMapper.resolveFunction(this.prefix, this.localName);
+
+        if (m == null && this.prefix.length() == 0) {
+            // Handle case of lambda expression being set to an EL variable for
+            // later use
+            Object obj =
+                    ctx.getELResolver().getValue(ctx, null, this.localName);
+            if (obj instanceof LambdaExpression) {
+                LambdaExpression le = (LambdaExpression) obj;
+                // Build arguments
+                int numArgs = this.jjtGetNumChildren();
+                Object[] args = new Object[numArgs];
+                for (int i = 0; i < numArgs; i++) {
+                    args[i] = children[i].getValue(ctx);
+                }
+                return le.invoke(ctx, args);
+            }
+        }
+
         if (m == null) {
             throw new ELException(MessageFactory.get("error.fnMapper.method",
                     this.getOutputName()));

Modified: tomcat/trunk/java/org/apache/el/parser/AstLambdaExpression.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/el/parser/AstLambdaExpression.java?rev=1503158&r1=1503157&r2=1503158&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/el/parser/AstLambdaExpression.java (original)
+++ tomcat/trunk/java/org/apache/el/parser/AstLambdaExpression.java Mon Jul 15 10:00:59 2013
@@ -17,11 +17,15 @@
 /* Generated By:JJTree: Do not edit this line. AstLambdaExpression.java Version 4.3 */
 package org.apache.el.parser;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.el.ELException;
+import javax.el.LambdaExpression;
 
+import org.apache.el.ValueExpressionImpl;
 import org.apache.el.lang.EvaluationContext;
 import org.apache.el.util.MessageFactory;
 
@@ -31,6 +35,34 @@ public class AstLambdaExpression extends
         super(id);
     }
 
+    @Override
+    public Object getValue(EvaluationContext ctx) throws ELException {
+
+        // Two children - the formal parameters and the expression
+        AstLambdaParameters formalParametersNode =
+                (AstLambdaParameters) children[0];
+        Node[] formalParamNodes = formalParametersNode.children;
+
+        if (formalParamNodes == null || formalParamNodes.length == 0) {
+            // No formal parameters - should be able to simply invoke this
+            return invoke(ctx, null, null);
+        } else {
+            // Has parameters but they aren't provided so build a
+            // LambdaExpression
+            List<String> formalParameters =
+                    new ArrayList<>(formalParamNodes.length);
+            for (Node formalParamNode : formalParamNodes) {
+                formalParameters.add(formalParamNode.getImage());
+            }
+
+            ValueExpressionImpl ve = new ValueExpressionImpl("", children[1],
+                    ctx.getFunctionMapper(), ctx.getVariableMapper(), null);
+            LambdaExpression le = new LambdaExpression(formalParameters, ve);
+
+            return le;
+        }
+    }
+
     @SuppressWarnings("null") // paramValues[i] can't be null due to checks
     @Override
     public Object invoke(EvaluationContext ctx, Class<?>[] paramTypes,

Modified: tomcat/trunk/java/org/apache/el/parser/AstLambdaExpressionOrInvocation.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/el/parser/AstLambdaExpressionOrInvocation.java?rev=1503158&r1=1503157&r2=1503158&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/el/parser/AstLambdaExpressionOrInvocation.java (original)
+++ tomcat/trunk/java/org/apache/el/parser/AstLambdaExpressionOrInvocation.java Mon Jul 15 10:00:59 2013
@@ -27,7 +27,6 @@ public class AstLambdaExpressionOrInvoca
         super(id);
     }
 
-
     @Override
     public Object getValue(EvaluationContext ctx) throws ELException {
 
@@ -38,8 +37,9 @@ public class AstLambdaExpressionOrInvoca
         if (children.length == 2) {
             args = ((AstMethodParameters) children[1]).getParameters(ctx);
         } else {
-            // No parameters - just the expression
-            args = null;
+            // No parameters. AstLambdaExpression contains the logic to handle
+            // this in getValue()
+            return lambdaExpression.getValue(ctx);
         }
         return lambdaExpression.invoke(ctx, null, args);
     }



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