Migrating to JSF 2.3, Problems with MyFaces Initialization

倾然丶 夕夏残阳落幕 提交于 2020-01-06 05:44:07

问题


I'm upgrading an application comprised of two projects, "common" and "myapp". I'm now upgrading it to JSF 2.3 (MyFaces) and Primefaces 7, and I can't figure out how to get past a failure in initialization.

I should note that there've been a lot of other changes as well. Both projects had been successfully upgraded to OpenJDK 11, Tomcat 9, and to using Maven. And with the change to JSF 2.3, managed beans are no longer supported in favor of JAVA's CDI API, which inconveniently is longer supported by default in JAVA 11. So I've pulled in OpenWebBeans 2.0 and DeltaSpike 1.9.1. Despite all these moving parts, the application was working up to the point of updating JSF, so I believe the issue is located there.

At this point I have two possible configurations, both failing. With one configuration I get this error:

[main] ERROR [Catalina].[localhost].[/myapp] - StandardWrapper.Throwable
No Factories configured for this Application. This happens if the faces-initialization 
does not work at all - make sure that you properly include all configuration settings
necessary for a basic faces application and that all the necessary libs are included. Also 
check the logging output of your web application and your container for any exceptions!
If you did that and find nothing, the mistake might be due to the fact that you use some
special web-containers which do not support registering context-listeners via TLD files 
and a context listener is not setup in your web.xml.
A typical config looks like this;
<listener>
  <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
</listener>

So, obvious solution was to add the listener, but then I get this:

[main] ERROR myfaces.config.FacesConfigurator - No ManagedBeanDestroyerListener instance
found, thus @PreDestroy methods won't get called in every case. This instance needs to be
published before configuration is started.

This seems like a sequencing issue where the StartupServletContextListener isn't publishing the ManagedBeanDestroyerListener before the Faces configuration begins. However, in my research I read that the StartupServletContextListener should not be required as it is automatically loaded from a TLD in the JSF jars.

Anyone understand what's going on here? How can I get past this?

Here are abridged versions of my pom's and web.xml's:

common/pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.company</groupId>
    <artifactId>common</artifactId>
    <version>2.1.8</version>

    <properties>
       <dependency.locations.enabled>false</dependency.locations.enabled>   
       <owb.version>2.0.12</owb.version>
       <deltaspike.version>1.9.1</deltaspike.version>      
    </properties>

    <repositories>
        <repository>
            <id>local_repository</id>
            <url>https://server.company.com/repository</url>
        </repository>
    </repositories>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.deltaspike.distribution</groupId>
                <artifactId>distributions-bom</artifactId>
                <version>${deltaspike.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.apache.myfaces.core</groupId>
            <artifactId>myfaces-api</artifactId>
            <version>2.3.5</version>
        </dependency>

        <dependency>
            <groupId>org.apache.myfaces.core</groupId>
            <artifactId>myfaces-impl</artifactId>
            <version>2.3.5</version>
        </dependency>

        <dependency>
            <groupId>org.apache.myfaces.core.internal</groupId>
            <artifactId>myfaces-impl-shared-public</artifactId>
            <version>2.3.5</version>
        </dependency>

        <!-- Stored in local maven repository -->
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>7.0</version>
        </dependency>

        <!-- Stored in local maven repository -->
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>all-themes</artifactId>
            <version>1.0.10</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>4.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-core</artifactId>
            <version>2.2.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.0.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>3.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>catalina</artifactId>
            <version>6.0.53</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-util</artifactId>
            <version>9.0.12</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.3</version>
        </dependency>
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.taglibs</groupId>
            <artifactId>taglibs-standard-impl</artifactId>
            <version>1.2.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.taglibs</groupId>
            <artifactId>taglibs-standard-spec</artifactId>
            <version>1.2.5</version>
        </dependency>

        <dependency>
            <groupId>org.apache.myfaces.core</groupId>
            <artifactId>myfaces-bundle</artifactId>
            <version>2.3.5</version>
        </dependency>


        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <version>2.0.SP1</version>
        </dependency>

        <!-- OpenWebBeans - implements CDI Container -->
        <dependency>
            <groupId>org.apache.openwebbeans</groupId>
            <artifactId>openwebbeans-spi</artifactId>
            <version>${owb.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.openwebbeans</groupId>
            <artifactId>openwebbeans-impl</artifactId>
            <version>${owb.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.openwebbeans</groupId>
            <artifactId>openwebbeans-web</artifactId>
            <version>${owb.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.openwebbeans</groupId>
            <artifactId>openwebbeans-jsf</artifactId>
            <version>${owb.version}</version>
        </dependency>

        <!-- DeltaSpike - manages CDI container -->
        <dependency>
            <groupId>org.apache.deltaspike.core</groupId>
            <artifactId>deltaspike-core-api</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.deltaspike.modules</groupId>
            <artifactId>deltaspike-jsf-module-api</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.deltaspike.core</groupId>
            <artifactId>deltaspike-core-impl</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.deltaspike.modules</groupId>
            <artifactId>deltaspike-jsf-module-impl</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--  CDI Control API -->
        <dependency>
            <groupId>org.apache.deltaspike.cdictrl</groupId>
            <artifactId>deltaspike-cdictrl-api</artifactId>
            <scope>compile</scope>
        </dependency>       

        <!--  CDI Control for OpenWebBeans -->
        <dependency>
            <groupId>org.apache.deltaspike.cdictrl</groupId>
            <artifactId>deltaspike-cdictrl-owb</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.deltaspike.modules</groupId>
            <artifactId>deltaspike-servlet-module-api</artifactId>
            <version>${deltaspike.version}</version>
            <scope>compile</scope>
        </dependency>       
        <dependency>
            <groupId>org.apache.deltaspike.modules</groupId>
            <artifactId>deltaspike-servlet-module-impl</artifactId>
            <version>${deltaspike.version}</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>src</sourceDirectory>
        <testSourceDirectory>test</testSourceDirectory>
        <resources>
            ...
        </resources>

        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                    <debug>${debugBuild}</debug>
                    <debuglevel>lines,vars,source</debuglevel> 
                </configuration>
            </plugin>

            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.1.0</version>
                ...
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.0</version>
                ...
            </plugin>

        </plugins>
    </build>    
</project>

myapp/pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.company</groupId>
  <artifactId>myapp</artifactId>
  <version>0.1.0</version>
  <packaging>war</packaging>

  <properties>
       <commonVersion>2.1.8</commonVersion>
       <dependency.locations.enabled>false</dependency.locations.enabled>
  </properties>

  <dependencies>
    <dependency>
        <groupId>com.company</groupId>
        <artifactId>common</artifactId>
        <version>${commonVersion}</version>
    </dependency>
  </dependencies>

  <build>
    <sourceDirectory>src</sourceDirectory>
    <testSourceDirectory>test</testSourceDirectory>
    <resources>
      <resource>
        <directory>resources</directory>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.1</version>
        <configuration>
          <warSourceDirectory>WebContent</warSourceDirectory>
        </configuration>
      </plugin>

      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
          <source>11</source>
          <target>11</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

common/META-INF/web-fragment.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-fragment metadata-complete="true" version="3.0"
              xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd">

    <name>common</name>

    <filter>
        <filter-name>ResourceFilter</filter-name>
        <filter-class>com.company.common.web.ResourceFilter</filter-class>
        <async-supported>true</async-supported>
    </filter>
    <filter-mapping>
        <filter-name>ResourceFilter</filter-name>
        <url-pattern>/javax.faces.resource/*</url-pattern>
        <url-pattern>/resources/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>PrimeFaces FileUpload Filter</filter-name>
        <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
        <init-param>
            <param-name>thresholdSize</param-name>
            <param-value>100000000</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>PrimeFaces FileUpload Filter</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
    </filter-mapping>


    <listener>
        <display-name>httpSessionListener</display-name>
        <listener-class>com.company.common.usersession.UserSessionListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
      <param-name>org.apache.myfaces.annotation.USE_CDI_FOR_ANNOTATION_SCANNING</param-name>
      <param-value>true</param-value>
    </context-param>   
    <context-param>
        <param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
        <param-value>65535</param-value>
    </context-param>
    <context-param>
        <param-name>primefaces.THEME</param-name>
        <param-value>mytheme</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</param-name>
        <param-value>20</param-value>
    </context-param>
    <context-param>
        <param-name>org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION</param-name>
        <param-value>2</param-value>
    </context-param>
    <context-param>
        <param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
        <param-value>false</param-value>
    </context-param>
    <context-param>
        <param-name>org.apache.myfaces.RESOURCE_MAX_TIME_EXPIRES</param-name>
        <param-value>31536000000</param-value> <!-- 1 year -->
    </context-param>
    <context-param>
        <param-name>primefaces.UPLOADER</param-name>
        <param-value>commons</param-value>
    </context-param>
</web-fragment>

myapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:web="http://java.sun.com/xml/ns/javaee"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
   version="3.0">

  <absolute-ordering>
    <name>common</name> <!-- Get the common web fragment -->
  </absolute-ordering>

    <!-- 
        AppApplicationContextListenerhas to happen before WebBeansConfigurationListener
        so that the application context (e.g. app name, db connections) is set before
        web beans are scanned  
    -->
    <listener>
        <listener-class>com.company.application.app.AppApplicationContextListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.apache.webbeans.servlet.WebBeansConfigurationListener</listener-class>
    </listener>

<!-- INCLUDE ??? -->
    <listener>
      <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
    </listener>

  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>



  <!-- Faces Servlet can't be moved into common's web-fragment.xml due to a bug in Apache's MyFaces -->
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
<!-- or possibly:                         -->
<!--     <url-pattern>*.jsf</url-pattern> -->
  </servlet-mapping>

</web-app>

回答1:


[Update 3-Jan-2020: I'm updating this entry to remove some bad advice. Specifically, renaming faces-config.xml to standard-faces-config.xml prevented MyFaces from initializing properly.]

I've resolved most of my issues. There were several components interfering with my project.


Maven:

Being new to Maven with Eclipse, it was a painful lesson to learn I really had to make sure I was re-running the Maven builds and cleaning out my deployment folders so that I was actually executing my changes. After that, here are the essentials of what I found and fixed.

  • Apparently, when dealing with a second referenced project, m2e doesn't handle test jars correctly. So a <dependency> block using <classifier>tests</classifier> or <type>test-jar</type> won't work, but the following will copy the test sources over to the dependent project for compilation. (be sure to edit the <source> value as appropriate, and enable the m2e profile in the Maven run in Eclipse)
    <profiles>
      <profile>
        <id>m2e</id>
        <activation>
          <property>
            <name>m2e.version</name>
          </property>
        </activation>
        <build>
          <plugins>
            <plugin>
              <groupId>org.codehaus.mojo</groupId>
              <artifactId>build-helper-maven-plugin</artifactId>
              <version>3.0.0</version>
              <executions>
                <execution>
                  <id>include-test-source-eclipse</id>
                  <phase>generate-test-sources</phase>
                  <goals>
                    <goal>add-test-source</goal>
                  </goals>
                  <configuration>
                    <sources>
                      <source>../common/test/java</source>
                    </sources>
                  </configuration>
                </execution>
              </executions>
            </plugin>
          </plugins>
        </build>
      </profile>
    </profiles>
  • org.apache.myfaces.core:myfaces-bundle is just org.apache.myfaces.core:myfaces-api and org.apache.myfaces.core:myfaces-impl combined into one package. Include either/or but not both. (The recommendation I received was to use the separate packages, not the bundle.)

  • Despite what I'd read at Apache, DeltaSpike does not make startup CDI (OpenWebBeans) any easier, so I removed it. It seems that registering the OpenWebBeans startup listener was sufficient (see below).

  • JDK 11 is not supported by cobertura (org.codehaus.mojo:cobertura-maven-plugin). People recommended JaCoCo #67 in its place.


web.xml

In switching from managed beans to CDI, the following lines are necessary in web.xml. Managed beans, while deprecated, still defaults to being enabled.

<context-param>
    <param-name>org.apache.myfaces.SUPPORT_MANAGED_BEANS</param-name>
    <param-value>false</param-value>
</context-param>
<context-param>
    <param-name>org.apache.myfaces.annotation.USE_CDI_FOR_ANNOTATION_SCANNING</param-name>
    <param-value>true</param-value>
</context-param> 

And the following are the listeners (and their order) that I'm currently using:

<listener>
    <listener-class>com.company.application.app.MyApplicationContextListener</listener-class>
</listener>

<listener>
    <listener-class>org.apache.webbeans.servlet.WebBeansConfigurationListener</listener-class>
</listener>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<listener>
  <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
</listener>


faces-config.xml:

Don't do what I did. Don't create a standard-faces-config.xml file. This prevents Faces from initializing properly. [The common project's faces-config.xml file wasn't being found, and renaming it seemed to fix the problem. Bad idea.] This mistake resulted in MyFaces failing to create <action-listener>org.primefaces.application.DialogActionListener</action-listener>, and this as well.


So, in summary...

  • It seems that the MyFaces StartupServletContextListener was indeed necessary to include in web.xml.
  • The strange "Bean Destroyer not published" error seemed to be due to switching to CDI but not disabling MyFaces' Managed Bean support.
  • Multiple start-up issues due to my standard-faces-config.xml file blocking proper initialization.


[@tandraschko: Thanks so much for your help and attention as I struggled through this!]



来源:https://stackoverflow.com/questions/59383725/migrating-to-jsf-2-3-problems-with-myfaces-initialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!