glassfish
  1. glassfish
  2. GLASSFISH-20778

EL 3.0 doesn't behave in Glassfish 4 the same way as in the standalone API

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 4.0
    • Fix Version/s: None
    • Component/s: web_container
    • Labels:
      None
    • Environment:

      windows 7, Dell Inspiron

      Description

      While writing some examples using the new features of Expression Language 3.0 (both in JSP and using the standalone API) I noticed that some of the new stuff are not behaving the same way in both places:

      1- According to item 1.22 of EL spec, "A static field or static method of a Javaclass can be referenced with the syntax classname.field, such as Boolean.TRUE".
      Doing so in the standalone API, it works as expected:

      ELProcessor elp = new ELProcessor();
      Object ret = elp.eval("Boolean.TRUE");
      System.out.println("Output Value: " + ret);

      Resulting: "Output Value: true"

      or...

      ELProcessor elp = new ELProcessor();
      Object ret = elp.eval("(x -> Math.sqrt)(9)");
      System.out.println("Output Value: " + ret);

      prints: 9.0

      However, when doing the same thing in JSP, nothing is printed:

      $

      {Boolean.TRUE}

      $

      {Integer.MAX_VALUE}

      $

      {Boolean.TRUE == true}

      // prints 'false'
      $

      {(x -> Math.sqrt(x))(9)}

      2 - According to item 1.22.3 of EL spec, "A class name reference, followed by arguments in parenthesis, such as Boolean(true) denotes the invocation of the constructor of the class with the supplied arguments."
      Doing so using the standalone API:

      ELProcessor elp = new ELProcessor();
      Object ret = elp.eval("StringBuilder('Java EE rocks')");
      System.out.println("Output Value: " + ret);

      Prints: Output Value: Java EE rocks

      But, in JSP:

      $

      {StringBuilder('Java EE rocks')}

      Results:

      exception
      org.apache.jasper.JasperException: javax.el.ELException: Expression uses
      functions, but no FunctionMapper was provided root cause

      *javax.el.ELException: Expression uses functions, but no FunctionMapper was
      provided*

      These expressions I have mentioned above wouldn't be supposed to work the same way in JSP and in the standalone API?

        Activity

        Hide
        kchung added a comment -

        Hmm... Looks like the java.lang language is properly imported in stand-alone EL, but not in EL used by JSP container. Will take a look.

        Show
        kchung added a comment - Hmm... Looks like the java.lang language is properly imported in stand-alone EL, but not in EL used by JSP container. Will take a look.
        Hide
        kchung added a comment -

        The JSP api was fixed.

        The maven artifact (javax.servlet.jsp: javax.servlet.jsp-api version 2.3.2-b01) to be published and integrated to glassfish v4.

        The fix is also available from the source in svn repo https://svn.java.net/svn/jsp~svn/trunk/api (revision 1459). The jar file can be built with a "mvn install", and the resultant jar file can be integrated with glassfish v4 by copying it to <gf>/modules directory, renaming (and replacing) javax.servlet.jsp-api.jar

        Show
        kchung added a comment - The JSP api was fixed. The maven artifact (javax.servlet.jsp: javax.servlet.jsp-api version 2.3.2-b01) to be published and integrated to glassfish v4. The fix is also available from the source in svn repo https://svn.java.net/svn/jsp~svn/trunk/api (revision 1459). The jar file can be built with a "mvn install", and the resultant jar file can be integrated with glassfish v4 by copying it to <gf>/modules directory, renaming (and replacing) javax.servlet.jsp-api.jar
        Hide
        balusc added a comment - - edited

        Great work.

        Please don't forget to implement this on Facelets as well and to update https://java.net/projects/el-spec/pages/StaticField on the subject. This confused a lot of users about the correct syntax of referencing constants in EL. It was mentioned in EL 3.0 EDR, however it was modified in EL 3.0 FR.

        Show
        balusc added a comment - - edited Great work. Please don't forget to implement this on Facelets as well and to update https://java.net/projects/el-spec/pages/StaticField on the subject. This confused a lot of users about the correct syntax of referencing constants in EL. It was mentioned in EL 3.0 EDR, however it was modified in EL 3.0 FR.
        Hide
        kchung added a comment -

        I've updated JSP source with a simpler fix.

        The call to the constructor of an imported class fail due to a bug in EL. This is also fixed. a new EL jar will be published and integrated into glassfish v4.

        Show
        kchung added a comment - I've updated JSP source with a simpler fix. The call to the constructor of an imported class fail due to a bug in EL. This is also fixed. a new EL jar will be published and integrated into glassfish v4.
        Hide
        kchung added a comment -

        For the benefit of other container using EL 3.0, here's a description of the cause for the problem, and how it is fixed in JSP.

        In a JSP container, the method ScopedAttributeELResolver.getValue(Object base, Object property) always sets the field ELResolver.propertyResolver to true if the base is null. This is a problem for EL, because only checks that a name is actually an imported class if the name is not resolved by a ELResolver. The fix is to check if the name is an imported class in ScopedAttributeELResolver.

        Here's the method in JSP:

        
        package javax.servlet.jsp.el;
        
        public class ScopedAttributeELResolver extends ELResolver {
            ...
            public Object getValue(ELContext context,
                                   Object base,
                                   Object property) {
        
                if (context == null) {
                    throw new NullPointerException();
                }
        
                if (base == null) {
                    context.setPropertyResolved(true);
                    if (property instanceof String) {
                        String attribute = (String) property;
                        PageContext ctxt = (PageContext)
                                               context.getContext(JspContext.class);
                        Object value = ctxt.findAttribute(attribute);
                        // To support reference of static fields for imported class in
                        // EL 3.0, if a scoped attribute returns null, this attribute
                        // is further checked to see if it is the name of an imported
                        // class.  If so, an ELClass instance is returned.
                        // Note: the JSP spec needs to be updated for this behavior. Note
                        // also that this behavior is not backward compatible with JSP 2.2
                        // and a runtime switch may be needed to force backward
                        // compatility.
                        if (value == null) {
                            // check to see if the property is an imported class
                            if (context.getImportHandler() != null) {
                                Class<?> c = context.getImportHandler().resolveClass(attribute);
                                if (c != null) {
                                    value = new ELClass(c);
                                    // A possible optimization is to set the ELClass
                                    // instance in an attribute map.
                                }
                            }
                        }
                        return value;
                    }
                }
                return null;
            }
        ...
        }
        
        
        Show
        kchung added a comment - For the benefit of other container using EL 3.0, here's a description of the cause for the problem, and how it is fixed in JSP. In a JSP container, the method ScopedAttributeELResolver.getValue(Object base, Object property) always sets the field ELResolver.propertyResolver to true if the base is null. This is a problem for EL, because only checks that a name is actually an imported class if the name is not resolved by a ELResolver. The fix is to check if the name is an imported class in ScopedAttributeELResolver. Here's the method in JSP: package javax.servlet.jsp.el; public class ScopedAttributeELResolver extends ELResolver { ... public Object getValue(ELContext context, Object base, Object property) { if (context == null ) { throw new NullPointerException(); } if (base == null ) { context.setPropertyResolved( true ); if (property instanceof String ) { String attribute = ( String ) property; PageContext ctxt = (PageContext) context.getContext(JspContext.class); Object value = ctxt.findAttribute(attribute); // To support reference of static fields for imported class in // EL 3.0, if a scoped attribute returns null , this attribute // is further checked to see if it is the name of an imported // class. If so, an ELClass instance is returned. // Note: the JSP spec needs to be updated for this behavior. Note // also that this behavior is not backward compatible with JSP 2.2 // and a runtime switch may be needed to force backward // compatility. if (value == null ) { // check to see if the property is an imported class if (context.getImportHandler() != null ) { Class <?> c = context.getImportHandler().resolveClass(attribute); if (c != null ) { value = new ELClass(c); // A possible optimization is to set the ELClass // instance in an attribute map. } } } return value; } } return null ; } ... }
        Hide
        marcelocenerine added a comment -

        I've built and installed a new version of javax.servlet.jsp-api-2.3.2-b01-SNAPSHOT.jar (based on revision 1460) as explained by kchung. The issues related to accessing static members have been solved. However, constructor invocation doesn't seem to be working. I got the same error:

         
        <%@page contentType="text/html" pageEncoding="UTF-8"%>
        <!DOCTYPE html>
        <html>
            <head>
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                <title>Expression Language 3.0: Miscelaneous</title>
            </head>
            <body>
                ${Boolean(false)}
            </body>
        </html>
        

        ERROR PAGE:

        type Exception report
        messageInternal Server Error
        descriptionThe server encountered an internal error that prevented it from fulfilling this request.
        exception
        org.apache.jasper.JasperException: javax.el.ELException: Expression uses functions, but no FunctionMapper was provided
        root cause
        javax.el.ELException: Expression uses functions, but no FunctionMapper was provided

        GLASSFISH LOG:

        WARNING: StandardWrapperValve[jsp]: Servlet.service() for servlet jsp threw exception
        javax.el.ELException: Expression uses functions, but no FunctionMapper was provided
        at com.sun.el.parser.AstFunction.getValue(AstFunction.java:161)
        at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226)
        at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50)
        at org.apache.jasper.runtime.PageContextImpl.evaluateExpression(PageContextImpl.java:1016)
        at org.apache.jsp.newFeatures.miscelaneous_jsp._jspService(miscelaneous_jsp.java:56)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:111)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:411)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:473)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:377)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
        at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
        at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
        at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
        at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
        at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
        at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
        at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
        at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
        at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
        at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
        at java.lang.Thread.run(Thread.java:722)

        Should I update/install any other jar?

        Thanks

        Show
        marcelocenerine added a comment - I've built and installed a new version of javax.servlet.jsp-api-2.3.2-b01-SNAPSHOT.jar (based on revision 1460) as explained by kchung. The issues related to accessing static members have been solved. However, constructor invocation doesn't seem to be working. I got the same error: <%@page contentType= "text/html" pageEncoding= "UTF-8" %> <!DOCTYPE html> <html> <head> <meta http-equiv= "Content-Type" content= "text/html; charset=UTF-8" > <title>Expression Language 3.0: Miscelaneous</title> </head> <body> ${ Boolean ( false )} </body> </html> ERROR PAGE: type Exception report messageInternal Server Error descriptionThe server encountered an internal error that prevented it from fulfilling this request. exception org.apache.jasper.JasperException: javax.el.ELException: Expression uses functions, but no FunctionMapper was provided root cause javax.el.ELException: Expression uses functions, but no FunctionMapper was provided GLASSFISH LOG: WARNING: StandardWrapperValve [jsp] : Servlet.service() for servlet jsp threw exception javax.el.ELException: Expression uses functions, but no FunctionMapper was provided at com.sun.el.parser.AstFunction.getValue(AstFunction.java:161) at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226) at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50) at org.apache.jasper.runtime.PageContextImpl.evaluateExpression(PageContextImpl.java:1016) at org.apache.jsp.newFeatures.miscelaneous_jsp._jspService(miscelaneous_jsp.java:56) at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:111) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:411) at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:473) at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:377) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188) at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191) at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168) at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189) at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206) at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136) at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114) at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838) at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544) at java.lang.Thread.run(Thread.java:722) Should I update/install any other jar? Thanks
        Hide
        kchung added a comment -

        The failure to invoke the constructor of an import class was fixed in the EL. You'll need to build it from the repository https://svn.java.net/svn/uel~svn/trunk, copy javax.el-3.0.1-b01-SNAPSHOT.jar to <gf>/modules, and renaming (and replacing) javax.el.jar.

        Show
        kchung added a comment - The failure to invoke the constructor of an import class was fixed in the EL. You'll need to build it from the repository https://svn.java.net/svn/uel~svn/trunk , copy javax.el-3.0.1-b01-SNAPSHOT.jar to <gf>/modules, and renaming (and replacing) javax.el.jar.
        Hide
        sartoris added a comment -

        Hello, I realize this issue has been resolved. I see that the JSP API fix is in the JSP 2.3.2-b01 Beta version. Are there any plans to move this from a Beta version to a normal update version?

        Show
        sartoris added a comment - Hello, I realize this issue has been resolved. I see that the JSP API fix is in the JSP 2.3.2-b01 Beta version. Are there any plans to move this from a Beta version to a normal update version?

          People

          • Assignee:
            kchung
            Reporter:
            marcelocenerine
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: