Spring Boot - Embedded Tomcat - #WebListener, scanned by #ServletComponentScan, adds a filter and gets java.lang.UnsupportedOperationException - spring

Supposedly we can use #ServletComponentScan to add standard servlet components annotated with #WebListener, #WebFilter and so on.
In my case I have a #WebListener that adds dynamically a filter:
#WebListener
public class FilterConfigurerListener implements ServletContextListener{
#Override
public void contextInitialized(ServletContextEvent sce) {
try{
...
ServletContext sc = sce.getServletContext();
Dynamic rcf = sc.addFilter("myFilter", MyFilter.class);
The addFilter() call throws the following exception:
java.lang.UnsupportedOperationException: Section 4.4 of the Servlet 3.0 specification does not permit this method to be called from a ServletContextListener that was not defined in web.xml, a web-fragment.xml file nor annotated with #WebListener
at org.apache.catalina.core.StandardContext$NoPluggabilityServletContext.addFilter(StandardContext.java:6639)
at com.whatever.FilterConfigurerListener.contextInitialized(FilterConfigurerListener.java:44)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4743)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5207)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
My Spring Boot App is annotated as said in the docs:
#ServletComponentScan(basePackageClasses=FilterConfigurerListener.class)
#SpringBootApplication
public class MySpringBootApplication {
Having a look at org.apache.catalina.core.StandardContext I can see that this implementation doesn't allow adding a filter:
#Override
public javax.servlet.FilterRegistration.Dynamic addFilter(
String filterName, Class<? extends Filter> filterClass) {
throw new UnsupportedOperationException(
sm.getString("noPluggabilityServletContext.notAllowed"));
}
How can we achieve this then?

Related

Spring server doesn't start with actuator dependency

If I add spring boot actuator dependency my server doesn't start. I get the following error:
SEVERE [main] org.apache.catalina.startup.HostConfig.deployDescriptor Error deploying deployment descriptor [tomcat path\conf\Catalina\localhost\test.xml]
java.lang.IllegalStateException: Error starting child
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:720)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:690)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:692)
...
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/agromarket]]
at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:440)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:198)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:717)
... 37 more
Caused by: java.lang.ClassCastException: org.apache.logging.slf4j.SLF4JLoggerContext cannot be cast to org.apache.logging.log4j.core.LoggerContext
at rs.navigator.alexandar.sync.WebAppInitializer.onStartup(WebAppInitializer.java:34)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:174)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5161)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
Dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Any ideas why? From my knowledge even if the versions aren't compatible the server should still be able to start.
Edit:
My WebAppInitializer:
public class WebAppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println(("------------------ Sync context initialized and application started ------------------"));
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
// ctx.register(ServletContextListener.class);
// ctx.register(SecurityConfiguration.class);
// ctx.register(SpringFoxConfig.class);
// ctx.register(WebMvcConfigure.class);
// ctx.register(JPAConfiguration.class);
// ctx.setServletContext(servletContext);
// Reconfigure log4j
// ServletContext sctx = ctx.getServletContext();
System.setProperty("logFilename", servletContext.getContextPath().substring(1));
org.apache.logging.log4j.core.LoggerContext sctxLog =
(org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
sctxLog.reconfigure();
//Dispatcher servlet
ServletRegistration.Dynamic servlet = servletContext.addServlet("mvc-dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
ctx.close();
}
}
Error stack after adding #EnableAutoConfiguration
If you want benefit from the automatic features of Spring Boot, your #Configuration class must be annotated with #EnableAutoConfiguration.
Since the auto-configuration already creates a DispatcherServlet bound to /, you can safely change your WebAppInitializer class to:
#SpringBootApplication
public class WebAppInitializer extends SpringBootServletInitializer {
}

java.lang.IllegalArgumentException: Failed to register servlet with name 'dispatcher'.Check if there is another servlet registered under the same name

My initializer class
public class HomeServlet extends
AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{SpringContextConfig1.class};
}
#Override
protected String[] getServletMappings() {
return new String[] {"/home"};
}
}
Configuration Class
#ComponentScan(basePackages={"spittr.controllers"})
#Configuration
#EnableWebMvc
public class SpringContextConfig1 extends WebMvcConfigurerAdapter{
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver ivr=new InternalResourceViewResolver();
ivr.setPrefix("/WEB-INF/jsp/");
ivr.setSuffix(".jsp");
ivr.setExposeContextBeansAsAttributes(true);
return ivr;
}
}
Controller
#Controller
public class HomeController {
#RequestMapping(value="/home",method=RequestMethod.GET)
public String home(){
return "home";
}
}
This is a very simple program, I wrote to test the JavaConfig of Spring MVC.I exactly followed all the steps from "Spring in Action" book.
When I run this code, I'm getting this error
09:41:37,854 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 72) MSC000001: Failed to start service jboss.undertow.deployment.default-server.default-host./spittr: org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./spittr: java.lang.RuntimeException: java.lang.IllegalArgumentException: Failed to register servlet with name 'dispatcher'.Check if there is another servlet registered under the same name.
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:85)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at org.jboss.threads.JBossThread.run(JBossThread.java:320)
Caused by: java.lang.RuntimeException: java.lang.IllegalArgumentException: Failed to register servlet with name 'dispatcher'.Check if there is another servlet registered under the same name.
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:236)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:100)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:82)
... 6 more
Caused by: java.lang.IllegalArgumentException: Failed to register servlet with name 'dispatcher'.Check if there is another servlet registered under the same name.
at org.springframework.util.Assert.notNull(Assert.java:115)
at org.springframework.web.servlet.support.AbstractDispatcherServletInitializer.registerDispatcherServlet(AbstractDispatcherServletInitializer.java:98)
at org.springframework.web.servlet.support.AbstractDispatcherServletInitializer.onStartup(AbstractDispatcherServletInitializer.java:71)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:169)
at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:186)
at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:171)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.api.LegacyThreadSetupActionWrapper$1.call(LegacyThreadSetupActionWrapper.java:44)
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:234)
The hightlight of the error is that " Failed to register servlet with name 'dispatcher'.Check if there is another servlet registered under the same name. at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:85) "
Please help me to solve this problem. I using WildFly-10 on eclipse.
use the configuration class as follows:
#ComponentScan(basePackages={"spittr.controllers"})
#Configuration
#EnableWebMvc
public class SpringContextConfig1 extends WebMvcConfigurerAdapter{
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver ivr=new InternalResourceViewResolver();
ivr.setPrefix("/WEB-INF/jsp/");
ivr.setSuffix(".jsp");
ivr.setExposeContextBeansAsAttributes(true);
registry.viewResolver(ivr);
}
}
Basically you're extending WebMvcConfigurerAdapter without inheriting any of its methods (in my 4.3.3 Spring version al least).
since you have a single DispatcherServlet here, you can add the SpringContextConfig1 class to the root context and leave the servlet context empty: switch the body of the method getServletConfigClasses() under the getRootConfigClasses() and vice versa - see A Bit on ApplicationContext Hierarchies.
Moreover, the DispatcherServlet mapping is more likely / instead of /home:
protected String[] getServletMappings() {
return new String[] {"/"};
}
My friend encountered the same problem.
The problem was that the correct package name was not set for the class.
AAAAnd clean the project before packaging!!!
Here is the code on GitHub

spring-boot with tomcat and cxf-servlet

I'm trying to stand up an embedded Tomcat with spring-boot. I want to use CXF for a set of web services in the app but I can not figure out how to stand up the CXF servlet.
My Main class looks like this...
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackages={"com.connecture.services.documentservice.webservice"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(new Class[] { Application.class, CfxInitializer.class }, args);
}
#Bean
public EmbeddedServletContainerFactory embeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory("", 8080);
return factory;
}
}
And my CfxInitializer like this...
public class CfxInitializer implements ServletContextInitializer
{
#Override
public void onStartup(ServletContext servletContext) throws ServletException
{
XmlWebApplicationContext rootContext = new XmlWebApplicationContext();
rootContext.setConfigLocations(new String[] { "classpath*:applicationContext.xml" });
servletContext.addListener(new ContextLoaderListener(rootContext));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("CXFServlet", CXFServlet.class);
dispatcher.addMapping("/api/*");
}
}
When I try to build and start the jar with the typical command ./gradlew build && java -jar build/libs/gs-spring-boot-0.1.0.jar
I get an Exception for multiple Contexts.
Java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:277)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4971)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Here is a more complete pastebin - http://pastebin.com/bcJ2ULhM
----------------------------------------------------------------------------------
Similarly to Dave's answer I was able to fix it by removing the ServletContextInitializer and adding a bean to the Application Class.
#Bean
public ServletRegistrationBean servletRegistrationBean(){
return new ServletRegistrationBean(new CXFServlet(),"/api/*");
}
The Spring Boot embedded servlet features are designed to work with Servlet and ServletRegistration #Beans, and not with the ContextLoaderListener (which looks like it is trying to steal the ServletContext attribute for the root context). Try adding a ServletRegistration for your servlet instead; if it is Spring aware, assuming it has an interface that lets you change the application context or the context location, then you should be able to configure it in the registration.
I found the following project on github which helped me get started
https://github.com/ungerts/spring-boot-jaxrs-sample
Worked for me with:
spring-boot 1.2.3
cxf-rt-frontend-jaxrs:3.1.0
jackson-jaxrs-json-provider:2.5.3
Samples are now part of the CXF wiki: http://cxf.apache.org/docs/jaxrs-services-configuration.html#JAXRSServicesConfiguration-SpringBoot

Tomcat 7.0.50 fails to inialize due to websocket deployment exception

I am trying to deploy WebSockets on tomcat 7.0.50. following is my code
#ServerEndpoint(value="/ws/fileuploadtracker/")
public class FileUploadTrackerEndPoint{
#OnOpen
public void onOpen(Session session) {
.....
}
#OnMessage
public void onMessage(Session session, String msg) {
try {
session.getBasicRemote().sendText(msg);
} catch (IOException e) {
logger.error(e.getMessage());
}
}
}
I picked above code from oracles' notes on javaee's websocket example from the link:
http://docs.oracle.com/javaee/7/tutorial/doc/websocket004.htm
My tomcat fails to start with following exception :
SEVERE: Error during ServletContainerInitializer processing
javax.servlet.ServletException: javax.websocket.DeploymentException: A parameter of type [interface javax.websocket.Session] was found on method[onOpen] of class [java.lang.reflect.Method] that did not have a #PathParam annotation
at org.apache.tomcat.websocket.server.WsSci.onStartup(WsSci.java:146)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5444)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caused by: javax.websocket.DeploymentException: A parameter of type [interface javax.websocket.Session] was found on method[onOpen] of class [java.lang.reflect.Method] that did not have a #PathParam annotation
at org.apache.tomcat.websocket.pojo.PojoMethodMapping.getPathParams(PojoMethodMapping.java:233)
at org.apache.tomcat.websocket.pojo.PojoMethodMapping.<init>(PojoMethodMapping.java:122)
at org.apache.tomcat.websocket.server.WsServerContainer.addEndpoint(WsServerContainer.java:239)
at org.apache.tomcat.websocket.server.WsSci.onStartup(WsSci.java:143)
... 8 more
1) How am I supposed to configure server end points as annotated class on tomcat 7.
2) IS there any tomcat specific way to write annotated server endpoints?
3)if tomcat implements JSR356 why does not it support above config?
I tried hard to find a suitable example but couldn't. I also tried putting #pathparam annotation but it only acepts strings and throws classcastexception.
It's also possible you used the wrong #PathParam, make sure you use:
import javax.websocket.server.PathParam;
and not:
import javax.ws.rs.PathParam;
I was using 1.b09 api. changed it to 1.0.
lesson learnt : always go for stable versions and not beta ones

Proxy Exception while injecting spring bean into JSF bean

I'm trying to inject spring bean into JSF bean, I'm using Spring 3.1 and JSF 2 (Mojarra 2.1.7)
Without a lot of talking my configuration and code and exception listed in the following:
StudentService.java:
#Scope(proxyMode=ScopedProxyMode.TARGET_CLASS)
public class StudentsService extends AbstractMaqraaService {
#Override
public Set<Class<?>> getTypes() {
// TODO Auto-generated method stub
return null;
}
public Student registerStudent(Student student) {
return this.store(student);
}
}
StudentRegistrationMBean.java:
#ManagedBean(name="studentRegistrationMBean")
#SessionScoped
public class StudentRegistrationMBean extends AbstractMBean {
private Student student;
#ManagedProperty (value="#{studentsService}")
private StudentsService studentsService;
public StudentRegistrationMBean() {
this.student = new Student();
}
/*Setters and getters omitted here only*/
public String register() {
studentsService.registerStudent(student);
return "manageStudents";
}
}
Spring bean in module context xml file:
<bean id="abstractMaqraaService" class="org.tts.maqraa.service.AbstractMaqraaService" abstract="true"/>
<bean id="studentsService" class="org.tts.maqraa.service.StudentsService" lazy-init="default" parent="abstractMaqraaService"/>
faces-config.xml:
...
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
...
Eception:
TRACE [http-bio-8080-exec-3] (SpringBeanELResolver.java:53) - Successfully resolved variable 'studentsService' in Spring BeanFactory
DEBUG [http-bio-8080-exec-3] (AbstractBeanFactory.java:245) - Returning cached instance of singleton bean 'studentsService'
نوار 13, 2012 11:10:45 ص com.sun.faces.application.view.FaceletViewHandlingStrategy handleRenderException
SEVERE: Error Rendering View[/teacher/registerNewStudent.xhtml]
com.sun.faces.mgbean.ManagedBeanCreationException: Unable to set property studentsService for managed bean studentRegistrationMBean
at com.sun.faces.mgbean.ManagedBeanBuilder$BakedBeanProperty.set(ManagedBeanBuilder.java:615)
at com.sun.faces.mgbean.ManagedBeanBuilder.buildBean(ManagedBeanBuilder.java:133)
...
at java.lang.Thread.run(Unknown Source)
Caused by: javax.el.ELException: Cannot convert org.tts.maqraa.service.StudentsService#8f65bc0 of type class $Proxy10 to class org.tts.maqraa.service.StudentsService
at org.apache.el.lang.ELSupport.coerceToType(ELSupport.java:420)
at org.apache.el.ExpressionFactoryImpl.coerceToType(ExpressionFactoryImpl.java:47)
at com.sun.faces.el.ELUtils.coerce(ELUtils.java:536)
at com.sun.faces.mgbean.BeanBuilder$Expression.evaluate(BeanBuilder.java:592)
at com.sun.faces.mgbean.ManagedBeanBuilder$BakedBeanProperty.set(ManagedBeanBuilder.java:606)
... 47 more
ERROR [http-bio-8080-exec-3] (MaqraaExceptionHandler.java:83) - Exception
javax.el.ELException: Cannot convert org.tts.maqraa.service.StudentsService#8f65bc0 of type class $Proxy10 to class org.tts.maqraa.service.StudentsService
at org.apache.el.lang.ELSupport.coerceToType(ELSupport.java:420)
...
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
I made a lot of search in Google and found a lot of questions here had issues like mine but nothing helped me, I hope I'll find my solution for my special case !!
use <aop:aspectj-autoproxy proxy-target-class="true"/> to enforce use of JDK proxy rather than CGLIB
if you inject your Spring service like this don't forget to create the setter for your Service:
#ManagedProperty (value="#{studentsService}")
private StudentsService studentsService;
public void setStudentsService (StudentsService studentsService)
{
this.studentsService = studentsService;
}
With the #Autowired annotation there was no need to do this.
Take a look at this answer It's about not using an interface for using your proxy.

Resources