I have read Injecting Jaxb2Marshaller in Spring MVC controller and Difference between applicationContext.xml and spring-servlet.xml in Spring Framework etc but feeling confused on why my case is not working.
Here is what I have in my app contexts and web.xml (trimmed down to show only related parts):
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app .... >
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/app-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
....
<servlet>
<servlet-name>spring-rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-rest</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
...
</web-app>
spring-rest-servlet.xml
<beans ....>
<!-- Only scan for Controllers in Servlet context -->
<context:component-scan base-package="com.fil.ims" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<mvc:annotation-driven />
<context:annotation-config />
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
....
</bean>
</beans>
I have a controller something like this:
@Controller
public class FooControllerImpl implements FooController {
@Inject
@Named("jaxb2Marshaller")
Jaxb2Marshaller jaxb2Marshaller;
public void setJaxb2Marshaller(Jaxb2Marshaller jaxb2Marshaller) {
this.jaxb2Marshaller = jaxb2Marshaller;
}
//.....
}
I found that I cannot inject the jaxb2Marshaller in the servlet context (NoSuchBeanDefinitionException
is thrown). However if I have the jaxb2Marshaller
put in the main app-context (app-context.xml
), it can be injected normally.
I am confused why it happens. From my understanding, if I have ContextLoaderListener
in web.xml
, the provided context config (app-context.xml) will be used to create a top-level app context, and then the dispatcher servlet context (spring-rest-servlet.xml
in my example) will be created as a child context under the top-level app context.
What I don't understand is, both the controller and the bean to be injected (jaxb2Marshaller) is all created under the dispatcher servlet context, why I cannot inject jaxb2Marshaller
into my FooController
? (I understand it will not work if the bean to be injected is located in child app context, but in this case it seems not.)
Can someone explain why?
Update:
I have done another experiment (which makes me even more confusing), by implementing ApplicationContextAware
in my controller, and from the controller, I do applicationContext.getBean("jaxb2Marshaller", Jaxb2Marshaller.class)
. A valid bean is returned (which is aligned with my understanding). It seems only injection through annotation is not working. Any clues?