'Springboot with JSF and SOAP interceptors not working properly
I am currently migrating lot of old code to springboot applications. We have JSF and SOAP web service which migrated successfully. I am facing issue related to WsConfigurerAdapter
. If we enable EndpointInterceptor
then FacesServlet does not initialize properly and throws below error.
15:28:41.045 [http-nio-8080-exec-1] ERROR j.faces - Unable to obtain InjectionProvider from init time FacesContext. Does this container implement the Mojarra Injection SPI?
15:28:41.046 [http-nio-8080-exec-1] ERROR j.faces - Application was not properly initialized at startup, could not find Factory: javax.faces.context.FacesContextFactory. Attempting to find backup.
15:28:41.047 [http-nio-8080-exec-1] ERROR o.a.c.c.C.[.[.[/KSF] - Servlet.init() for servlet [FacesServlet] threw exception
java.lang.IllegalStateException: Could not find backup for factory javax.faces.context.FacesContextFactory.
at javax.faces.FactoryFinderInstance.getFactory(FactoryFinderInstance.java:541) ~[javax.faces-2.3.9.jar!/:2.3.9]
at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:292) ~[javax.faces-2.3.9.jar!/:2.3.9]
at javax.faces.webapp.FacesServlet.init(FacesServlet.java:374) ~[javax.faces-2.3.9.jar!/:2.3.9]
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1164) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:804) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:128) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.56.jar!/:?]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_222-4-redhat]
15:28:41.055 [http-nio-8080-exec-1] ERROR o.a.c.c.C.[.[.[.[FacesServlet] - Allocate exception for servlet [FacesServlet]
java.lang.IllegalStateException: Could not find backup for factory javax.faces.context.FacesContextFactory.
at javax.faces.FactoryFinderInstance.getFactory(FactoryFinderInstance.java:541) ~[javax.faces-2.3.9.jar!/:2.3.9]
at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:292) ~[javax.faces-2.3.9.jar!/:2.3.9]
at javax.faces.webapp.FacesServlet.init(FacesServlet.java:374) ~[javax.faces-2.3.9.jar!/:2.3.9]
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1164) ~[tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:804) ~[tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:128) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.56.jar!/:?]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.56.jar!/:?]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_222-4-redhat]
Web service configuration code
@EnableWs
@Configuration
public class MyWebServiceConfig {
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
ServletRegistrationBean<MessageDispatcherServlet> servletRegistrationBean = new ServletRegistrationBean<>(servlet, "/Services/*");
servletRegistrationBean.setName("MessageDispatcherServlet");
return servletRegistrationBean;
}
@Bean // this is causing JSF deployment issue
public WsConfigurerAdapter csfWsConfigurerAdapter() {
return new WsConfigurerAdapter() {
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
if (interceptors == null) {
interceptors = new ArrayList<>();
}
MyPayloadValidatingInterceptor validatingInterceptor = new MyPayloadValidatingInterceptor();
validatingInterceptor.setValidateRequest(true);
validatingInterceptor.setValidateResponse(false);
validatingInterceptor.setSchemas(getSchemas());
try {
validatingInterceptor.afterPropertiesSet();
} catch (Exception e) {}
interceptors.add(validatingInterceptor);
}
};
}
}
I am using prime faces with JSF so important dependency are listed below
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<main.basedir>${project.basedir}/..</main.basedir>
<spring.boot.version>2.6.3</spring.boot.version>
<primefaces.version>5.3</primefaces.version>
<faces.version>2.3.9</faces.version>
</properties>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>${primefaces.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>${faces.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
version="2.2">
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
</faces-config>
Faces/JSF Configuration
@Configuration
public class MyJSFConfig implements ServletContextAware, WebMvcConfigurer {
@Bean
public ServletRegistrationBean<FacesServlet> servletRegistrationBean() {
ServletRegistrationBean<FacesServlet> servletRegistrationBean = new ServletRegistrationBean<>(
new FacesServlet(), "*.jsf", "*.xhtml");
servletRegistrationBean.setName("FacesServlet");
servletRegistrationBean.setLoadOnStartup(1);
return servletRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() {
return new ServletListenerRegistrationBean<ConfigureListener>(new ConfigureListener());
}
@Override
public void setServletContext(ServletContext servletContext) {
// spring boot only works if this is set
// Iniciar el contexto de JSF
// http://stackoverflow.com/a/25509937/1199132
servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());
servletContext.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", Boolean.TRUE.toString());
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/my").setViewName("forward:/my/index.jsf");
}
I am thinking this is classloading issue for springboot. WsConfigurerAdapter is used DelegatingWsConfiguration and configured conditional on missing bean in WebServicesAutoConfiguration. We are on latest springboot release
Solution 1:[1]
It is more related to how spring post bean processing works. After careful debugging found out ServletContextAware method was not called due to that servletcontext was not initialized and Faces Context was not initialized properly.
@Override
public void setServletContext(ServletContext servletContext) {
// spring boot only works if this is set
// Iniciar el contexto de JSF
// http://stackoverflow.com/a/25509937/1199132
servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());
servletContext.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", Boolean.TRUE.toString());
}
I changed to ServletContextInitializer which gets called on startup and initialize required values properly.
Below question answer was helpful in identifying. setServletContext not activating inside @Configuration file
Full working sample project as below location https://github.com/gaurangparmar/my-springboot-jsf
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Gaurang Parmar |