rewrite: UnsupportedOperationException for request scoped bean with parameter
Versions:
- Spring boot 2.7.6
- Joinfaces 4.7.4
- Rewrite 3.5.1.Final
- JSF 2.3
On initializing RewriteFilter for request scoped bean ‘MyController’ (see below) during spring boot application start-up the following exception occurs.
Exception starting filter [OCPsoft Rewrite Filter]
java.lang.UnsupportedOperationException: null
at java.base/java.util.AbstractMap.put(AbstractMap.java:209)
at org.springframework.web.context.request.FacesRequestAttributes.setAttribute(FacesRequestAttributes.java:112)
at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:46)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:371)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:673)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:661)
at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1300)
at org.joinfaces.autoconfigure.rewrite.SpringBootBeanNameResolver.resolveBeanNames(SpringBootBeanNameResolver.java:80)
at org.joinfaces.autoconfigure.rewrite.SpringBootBeanNameResolver.getBeanName(SpringBootBeanNameResolver.java:49)
at org.ocpsoft.rewrite.el.TypeBasedExpression.lookupBeanName(TypeBasedExpression.java:72)
at org.ocpsoft.rewrite.el.TypeBasedExpression.getExpression(TypeBasedExpression.java:55)
at org.ocpsoft.rewrite.el.TypeBasedExpression.toString(TypeBasedExpression.java:108)
at java.base/java.lang.String.valueOf(String.java:2951)
at java.base/java.lang.StringBuilder.append(StringBuilder.java:168)
at org.ocpsoft.rewrite.el.El$ElProperty.toString(El.java:335)
at org.ocpsoft.rewrite.param.ParameterBuilder.addOrReplaceBinding(ParameterBuilder.java:83)
at org.ocpsoft.rewrite.param.ParameterBuilder.bindsTo(ParameterBuilder.java:69)
at org.ocpsoft.rewrite.param.ParameterBuilder.bindsTo(ParameterBuilder.java:29)
at org.ocpsoft.rewrite.config.ConfigurationLoader$1.call(ConfigurationLoader.java:196)
at org.ocpsoft.rewrite.config.ParameterizedConditionVisitor.visit(ParameterizedConditionVisitor.java:40)
at org.ocpsoft.rewrite.config.ParameterizedConditionVisitor.visit(ParameterizedConditionVisitor.java:27)
at org.ocpsoft.rewrite.config.ConditionVisit.visit(ConditionVisit.java:53)
at org.ocpsoft.rewrite.config.ConditionVisit.accept(ConditionVisit.java:44)
at org.ocpsoft.rewrite.config.ConfigurationLoader.build(ConfigurationLoader.java:204)
at org.ocpsoft.rewrite.config.ConfigurationLoader.buildCached(ConfigurationLoader.java:118)
at org.ocpsoft.rewrite.config.ConfigurationLoader.loadConfiguration(ConfigurationLoader.java:81)
at org.ocpsoft.rewrite.servlet.impl.DefaultHttpRewriteProvider.init(DefaultHttpRewriteProvider.java:81)
at org.ocpsoft.rewrite.servlet.impl.DefaultHttpRewriteProvider.init(DefaultHttpRewriteProvider.java:55)
at org.ocpsoft.rewrite.servlet.RewriteFilter.init(RewriteFilter.java:142)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:272)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:106)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4609)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5248)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1383)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:916)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:835)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1383)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:916)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:265)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:430)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.startup.Tomcat.start(Tomcat.java:486)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:123)
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:104)
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:479)
at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:211)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:184)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:162)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:577)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292)
@Join(path = "/mypath", to = "/pages/myPage.jsf")
public class MyController {
@Parameter("someParam")
@Setter
@Getter
private String someParam;
}
@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public MyController myController() {
return new MyController();
}
About this issue
- Original URL
- State: open
- Created 2 years ago
- Comments: 29 (22 by maintainers)
The “problem” is that
org.ocpsoft.rewrite.spring.SpringServiceEnricherdoes not have access to the current ServletContext, so it can’t access the ServletContext attributeorg.springframework.web.context.WebApplicationContext.ROOTin which the WebApplicationContext could be found.See also
org.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContextInstead it relies on
org.springframework.web.context.ContextLoader#getCurrentWebApplicationContextwhich is null for Spring Boot Applications, because they aren’t loaded by the ContextLoaders. (The only exception might be WAR-based Spring-Boot Application, deployed to an existing servlet container)I tested the changes successfully with
4.0.0-SNAPSHOTas JAR and WAR. Thank you @lincolnthree and @larsgrefer. I’m looking forward to the new release. 😃Additionally. I have improved the expression language bean name resolution so that it tries providers until either it finds one that works, or they all fail.
BAM. It works. This is MUCH cleaner. Thanks @larsgrefer.
processInjectionBasedOnServletContextalso usesorg.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContextinternally.The interesting SPI is
ServiceEnricheronce this works correctly, the other Spring SPI Implementations can get their ApplicationContext reference from the enriched by just implementing ApplicationContextAwareProof it works 😃
Hey @larsgrefer! Thanks for the info and for pointing me toward
getRequiredWebApplicationContextgThe issue here is that the JoinFaces BeanNameResolver is still usingApplicationContext.getBeansOfType. So it’s going to fail when Rewrite attempts to configure Bean names and parameters (which is what’s happening to @TobiasBerndt) and the Context isn’t found.I think the better solution here would be to make the Rewrite
SpringBeanNameResolveraware of the ServletContext so that it can properly attempt to access theWebApplicationContextin Spring Boot applications using the method you recommended. Then you’d be able to remove your JoinFaces SPI implementation. Or you can make yours implementContextListenerand fix it that way too.Here’s what I propose, regardless of where the fix goes:
I am working on a new release/snapshot that should resolve this, regardless 😃 Let’s see if we can get it taken care of!
Ok, so from what I can tell, it appears that Spring Boot is misconfigured or incompatible somehow. The Spring
WebApplicationContextis not available during Servlet Filter startup, and it needs to be. I am not an expert in Spring Boot and its startup lifecycle, so I’m not sure how much I will be able to help, here. Know anyone with Spring Boot expertise?Generally, when configuring Spring Manually, you’d ensure this happens by ordering Spring’s
WebContextListenerto run before Rewrite’s.I’ve tried all the solutions proposed here: https://stackoverflow.com/questions/33486219/spring-boot-no-webapplicationcontext-found, but I suspect something is interfering with or overriding the boot order. I might suggest checking with the JoinFaces folks and see what they are doing in this regard, and if there is any way to override their defined start order (if they’ve set one, which I presume they have.)
[Edit. You are correct – This doesn’t fix the issue. I think it just changed the order of classloading and a different issue came up first.] Please ignore.
I thought
SpringBootServletInitializeris only needed if you want to run the application as WAR. My sample application is running as JAR with an embedded tomcat. Javadoc ofSpringBootServletInitializer:Nevertheless I tried it with
SpringBootServletInitializerbut exceptions during startup are still thrown.Okay, so I think I know why this is happening. First, the startup error is caused because you need to extend
SpringBootServletInitializerin your RewriteConfiguration to tell Spring Boot that this Configuration uses the WebApplicationContext (which changes initialization order.)This resolves the startup error:
Next, regarding the PrettyFaces error when loading the
Parameterconfig, I am still working on that. But it’s being caused because the request-scoped bean is being looked up during application startup for some reason. It shouldn’t be. The EL container should be able to return metadata about the bean without instantiating the bean. I’m still researching.