3 Replies Latest reply on Oct 27, 2014 8:57 AM by jaikiran

    Difficulty with ImportHandler#importClass()

    pgarner

      The following bean seems to load fine upon startup and when facelets are loaded, as evidenced by the log:

       

      @ManagedBean(eager=true)
      @ApplicationScoped
      public class EnumConfig {
      
          @PostConstruct
          public void init() {
      
              System.out.println("Testing 123...");
              FacesContext.getCurrentInstance().getApplication().addELContextListener (
                  new ELContextListener() {
               
                      @Override
                      public void contextCreated(ELContextEvent event) {
                   
                          System.out.println("Testing 456...");
                          ImportHandler importHandler = event.getELContext().getImportHandler();
                          importHandler.importClass("foo.bar.business.model.enumeration.YesOrNo");
                          Class<?> clazz = importHandler.resolveClass("YesOrNo");
                          System.out.println("class = " + clazz);
                      }
                  }
              );
          }
      }
      
      
      
      
      
      
      
      

       

      
      21:26:48,703 INFO [stdout] (MSC service thread 1-4) Testing 123...
      21:39:11,976 INFO [stdout] (default task-9) Testing 456...
      21:39:11,976 INFO [stdout] (default task-18) class = null
      
      
      
      
      
      
      
      

      YesOrNo is not imported because clazz == null in EnumConfig code snippet. This is a problem.  And as expected the value expression can't resolve YesOrNo#values(). The select list is rendered empty, with no YesOrNo values.

       

      <f:selectItems
          value="#{YesOrNo.values()}"
          var="yesOrNo"
          itemValue="#{yesOrNo}"
          itemLabel="#{yesOrNo.name()}"/>
      
      
      
      

       

      I set a breakpoint after ImportHandler#importClass and I can see that classNameMap is properly populated:

      importHandler = {javax.el.ImportHandler@17821}

          classNameMap = {java.util.HashMap@17822} size = 1

              [0] = {java.util.HashMap$Node@17830}"YesOrNo" -> "foo.bar.business.model.enumeration.YesOrNo"

          classMap = {java.util.HashMap@17823} size = 0

          staticNameMap = {java.util.HashMap@17824} size = 0

          notAClass = {java.util.HashSet@17825} size = 0

          packages = {java.util.ArrayList@17826} size = 1

              [0] = {java.lang.String@17286}"java.lang"

                  value = {char[9]@17287}

                  hash = -888658374

       

       

      So, classNameMap is populated correctly but the import handler cannot resolve the class.  The JavaDoc for ImportHandler#resolveClass() indicates I am using it correctly (without package name).  Why is import handler unable to resolve the class?

       

      FYI, using <o:importConstants> of OmniFaces works just fine.

       

      <o:importConstants type="foo.bar.business.model.enumeration.YesOrNo"/>
      
      
      
      
      

       

      What can I do to further troubleshoot this problem?

        • 1. Re: Difficulty with ImportHandler#importClass()
          jaikiran

          Looks like a classloader issue. Here's what the implementation looks like jboss-el-api_spec/ImportHandler.java at master · jboss/jboss-el-api_spec · GitHub  which means that the only way your application's class (the YesOrNo class in this instance) can be loaded is if it is visible to the classloader which loaded the javax.el.ImportHandler class. That's not going to happen because the javax.el.ImportHandler is loaded by the module classloader of javax.el module which doesn't have visibility to your application's classes.


          I don't have an idea how that ImportHandler is supposed to work. Someone from the web dev team might know more.

           

          • 2. Re: Re: Difficulty with ImportHandler#importClass()
            pgarner

            jaikiran pai wrote:

             

            Looks like a classloader issue. Here's what the implementation looks like jboss-el-api_spec/ImportHandler.java at master · jboss/jboss-el-api_spec · GitHub  which means that the only way your application's class (the YesOrNo class in this instance) can be loaded is if it is visible to the classloader which loaded the javax.el.ImportHandler class. That's not going to happen because the javax.el.ImportHandler is loaded by the module classloader of javax.el module which doesn't have visibility to your application's classes.


            I don't have an idea how that ImportHandler is supposed to work. Someone from the web dev team might know more.

             

             

            I took a look at the EL 3.0 spec:

             

            1.22.2 Imports of Packages, Classes, and Static Fields

            Either a class or a package can be explicitly imported into the EL evaluation

            environment. Importing a package imports all the classes in the package. The classes

            that can be imported are restricted to the classes that can be loaded by the current

            class loader.

             

            By default, the following packages are imported by the EL environment.

             

            java.lang.*

             

            A static field can also be imported statically. A statically imported static field can be

            referenced by the field name, without the classname.

             

            The imports of packages, classes, and static fields are handled by the

            ImportHandler in the ELContext.

             

             

            and, yep, it does say that the classes that can be imported are restricted to the classes that can be loaded by the current class loader.  But shouldn't the current class loader be able to load classes in WEB-INF/classes?  How can I get in touch with somebody from web dev team to weigh in on this?

            • 3. Re: Re: Difficulty with ImportHandler#importClass()
              jaikiran

              Patrick Garner wrote:

               

              jaikiran pai wrote:

               

              Looks like a classloader issue. Here's what the implementation looks like jboss-el-api_spec/ImportHandler.java at master · jboss/jboss-el-api_spec · GitHub  which means that the only way your application's class (the YesOrNo class in this instance) can be loaded is if it is visible to the classloader which loaded the javax.el.ImportHandler class. That's not going to happen because the javax.el.ImportHandler is loaded by the module classloader of javax.el module which doesn't have visibility to your application's classes.


              I don't have an idea how that ImportHandler is supposed to work. Someone from the web dev team might know more.

               

               

              I took a look at the EL 3.0 spec:

               

              1.22.2 Imports of Packages, Classes, and Static Fields

              Either a class or a package can be explicitly imported into the EL evaluation

              environment. Importing a package imports all the classes in the package. The classes

              that can be imported are restricted to the classes that can be loaded by the current

              class loader.

               

              By default, the following packages are imported by the EL environment.

               

              java.lang.*

               

              A static field can also be imported statically. A statically imported static field can be

              referenced by the field name, without the classname.

               

              The imports of packages, classes, and static fields are handled by the

              ImportHandler in the ELContext.

               

               

              and, yep, it does say that the classes that can be imported are restricted to the classes that can be loaded by the current class loader.  But shouldn't the current class loader be able to load classes in WEB-INF/classes? 

              I haven't looked at that spec, but if current classloader means the thread context classloader associated with the current thread, then yes, it should have used that classloader.

               

              Patrick Garner wrote:

              How can I get in touch with somebody from web dev team to weigh in on this?

              (Subscribe first) and start a discussion in the wildfly-dev mailing list wildfly-dev Info Page