Spring mvc autowire RequestMappingHandlerMapping - java

I'm trying to autowire org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping in my spring mvc controller in order to get all url mappings and display them on UI, but not successfull. There is error that the bean is missing:
org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping web.controller.WorkController.handlerMapping; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
My web.xml:
<display-name>Spring MVC Application</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
My mvc-dispatcher-servlet.xml:
<context:annotation-config/>
<context:component-scan base-package="web.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
My root-context.xml:
<bean id="helloBean" class="web.beans.HelloBean"/>
The java controller:
package web.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import web.beans.HelloBean;
import java.util.List;
#Controller
public class WorkController {
#Autowired RequestMappingHandlerMapping handlerMapping;
#Autowired private HelloBean helloBean;
#Autowired private ApplicationContext applicationContext;
#RequestMapping(value = "/index")
public String index() {
return "index";
}
}

You should initiate the RequestMappingHandlerMapping bean before autowired it.
It has two way:
In springxml config such as hello bean
<bean name="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<!-- add your properties here property name="..." value="..."></property-->
</bean>
Or using
#Configuration
#Configuration
#ComponentScan("your.package")
#EnableWebMvc
public class AppConfig {
...
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping();
// add properties here
return mapping;
}
...
}

Try to get all request urls, The code below may be useful for you.
ServletContext servletContext = request.getSession().getServletContext();
WebApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
Map<String, HandlerMapping> allRequestMappings = BeanFactoryUtils.beansOfTypeIncludingAncestors(appContext, HandlerMapping.class, true, false);
for (HandlerMapping handlerMapping : allRequestMappings.values()) {
if (handlerMapping instanceof RequestMappingHandlerMapping) {
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) handlerMapping;
Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
for (Map.Entry<RequestMappingInfo, HandlerMethod> requestMappingInfoHandlerMethodEntry : handlerMethods.entrySet()) {
RequestMappingInfo requestMappingInfo = requestMappingInfoHandlerMethodEntry.getKey();
PatternsRequestCondition patternsCondition = requestMappingInfo.getPatternsCondition();
String requestUrl = SetUtils.first(patternsCondition.getPatterns());
System.out.println(requestUrl);
}
}
}
Frankly speaking, java reflect is a key point to get all request urls. if you look into the spring-mvc source deeply, you will find the implementation classes of HandlerMapping interface, such as
AbstractControllerUrlHandlerMapping, AbstractDetectingUrlHandlerMapping,
AbstractHandlerMapping, AbstractHandlerMethodMapping,
AbstractUrlHandlerMapping, BeanNameUrlHandlerMapping,
ControllerBeanNameHandlerMapping, ControllerClassNameHandlerMapping,
DefaultAnnotationHandlerMapping, RequestMappingHandlerMapping,
RequestMappingInfoHandlerMapping, SimpleUrlHandlerMapping

i try to add "#EnableWebFlux" in my Main class and it works(in my
situation).
so i think maybe "EnableWebMvc" works so..
it works fine for me, don`t ↓ me please :)
#EnableWebFlux(for webflux)
#EnableWebMvc(for commvc)
#SpringBootApplication
public class InstoreApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(InstoreApplication.class)......
}
}

You can add these in *.properties file:
# Log restful end points
logging.level.web=TRACE
logging.level.org.springframework.web=TRACE

Related

SpringMVC RestEasy Integration Beans aren't injected to Controller classes

I'm working on a project which has spring mvc 2.5.* .I have integrated RESTeasy to create restful endpoints. I have defined a controller class with #Controler. I have a bean which is supposed to be injected to this controller but it seems it's not getting injected, thus it throws a null pointer exception when the bean variable is used in controller rest methods.
I have added these to the web.xml
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<servlet>
<servlet-name>resteasy-servlet</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.test.package.controller.MyApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>resteasy-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Customized class I extended from resteasy Application class to define application path:
#ApplicationPath("/rest")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>();
// register root resource
classes.add(EmployeeController.class);
return classes;
}
}
I have a servlet.xml which has defined mvc controller beans which works fine:
eg:
<bean name="/testDetail.html" class="com.test.package.controller.TestDetailController" parent="baseController">
<property name="testService" ref="testService"/>
</bean>
My Controller class looks like this:
#Controller
#Path("/employee")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class EmployeeController {
private static final Log LOG = LogFactory.getLog(EmployeeController.class);
private EmployeeService employeeService; // This doesn't get initiated.
#PUT
#Path("/update/{empId}")
public Response updateEmp(#PathParam("empId") Long empId, EmpRequest request) {
Response response = null;
employeeService.update(request); // NULL POINTER THROWN HERE, employeeService is null
return response;
}
public EmployeeService getEmployeeService () {
return employeeService ;
}
public void serEmployeeService (EmployeeService employeeService ) {
this.employeeService = employeeService ;
}
}
Here I added another bean to servlet.xml as,
<bean id="employeeController " class="com.test.package.controller.EmployeeController">
<property name="employeeService " ref="employeeService "/>
</bean>
In a separate xml employeeService bean is defined. It' just that it won't reflect in the employeeController bean. I'm not sure if even employeeController bean is created or not. But I'm able to call the endpoint successfully. bean initiation works fine if put employeeService bean in a MVC controller. eg:
<bean name="/testDetail.html" class="com.test.package.controller.TestDetailController" parent="baseController">
<property name="employeeService " ref="employeeService "/>
</bean>
But not in RestController. Any Idea on this behavior. Am I missing any configuration here.
firstly, you should define the employeeService bean as follows,
<bean id="employeeService" class="com.test.package.service.EmployeeService">
--------
</bean>
load the above config xml file in web.xml,
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/XML_FILE_PATH/XML_FILE_NAME.xml</param-value>
</context-param>
then, you can use employeeService bean
use #PostConstruct annotation for invoke with this method after employeeService bean is initialized
#PUT
#PostConstruct
#Path("/update/{empId}")
public Response updateEmp(#PathParam("empId") Long empId, EmpRequest request) {
Response response = null;
employeeService.update(request); // NULL POINTER THROWN HERE, employeeService is null
return response;
}

How to configure and load spring context in servlet project

I am pretty new to spring. I have dynamic web application project. Inside i have a servlet which is receive request. The request comes with a request no. Based on the no i will create a new object for appropriate request class and serve the request. Now i need to integrate with spring. i applied the below configuration,
WEB.XML (To load spring context)
<servlet>
<servlet-name>spring-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/docspring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
In servlet
package com.receve;
#Controller
#WebServlet("/Recever")
public class Recever extends HttpServlet {
#Autowired
private ClassOne one;
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//request parameters receved and
if(req==1){
one.print();
}
}
public ClassOne getOne() {
return One;
}
public void setOne(ClassOne one) {
this.one = one;
}
}
In ClassOne
package com.operations;
#Component
public Class ClassOne{
public void print(){
//some statement;
}
}
In spring.xml
<context:annotation-config />
<context:component-scan base-package="com" />
But while running the application i am getting NullPointerexception while calling one.print() method. what is the proper way(configuration) to obtain this?
Thanks.
Remove extends HttpServlet and Autowiring is turned off by default, so the default autowiring mode for a bean is 'no'.

spring and vaadin integration

I'm trying to implement an application with several uis - vaadin, jsp and etc.
It was working with simple jsp but then I decided to use vaadin as ui.
I've created vaadin servlet(and spring servlet left too).
My web.xml looks like this
<?xml version="1.0"?>
<web-app 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-app_2_5.xsd"
version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/pmc-web-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>another-pmc-servlet</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<param-name>UI</param-name>
<param-value>com.xxxx.app.pmc.vaadin.PmcUi</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>pmc-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>another-pmc-servlet</servlet-name>
<url-pattern>/VAADIN/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>pmc-servlet</servlet-name>
<url-pattern>/JSP/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>/WEB-INF/jsp/*</url-pattern>
</servlet-mapping>
</web-app>
I've created vaadin table component and adjusted it for my needs. I used autowiring for service.
package com.xxxx.app.pmc.vaadin.components;
import com.xxxx.app.pmc.model.Project;
import com.xxxx.app.pmc.service.project.ProjectService;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.ui.Table;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
#Component("projectTable")
public class ProjectTable extends Table {
private static final String CAPTION = "Projects";
private static final String[] headers = { "Project name", "Project owner", "ID" };
#Autowired
private ProjectService projectService;
public Table createTable() {
this.setContainerDataSource(projectDatasource());
this.setVisibleColumns(headers);
this.setSelectable(true);
this.setImmediate(true);
return this;
}
public IndexedContainer projectDatasource() {
IndexedContainer indexedContainer = new IndexedContainer();
for(String header: headers) {
indexedContainer.addContainerProperty(header, String.class, "");
}
List<Project> projects = projectService.findAllProjects();
for(int i = 0; i < projects.size(); i++) {
Object id = indexedContainer.addItem();
Project item = projects.get(i);
indexedContainer.getContainerProperty(id, headers[0]).setValue(item.getProjectName());
indexedContainer.getContainerProperty(id, headers[1]).setValue(item.getProjectOwner());
indexedContainer.getContainerProperty(id, headers[1]).setValue(item.getProjectId());
}
return indexedContainer;
}
}
ProjectService is a spring bean too.
#Service("projectService")
public class ProjectService {
#Autowired
private ProjectRepository projectRepository;
public void insertProject(Project project) {
projectRepository.store(project);
}
public List<Project> findAllProjects() {
return projectRepository.getAllItems();
}
public Project getProject(String id) {
return projectRepository.get(id);
}
}
ProjectRepository is another spring bean. It uses SqlSessionTemplate bean from MyBatis.
#Repository("projectRepository")
public class ProjectRepository implements IRepository<Project> {
private static final String STORE_PROJECT = "Project.insertProject";
private static final String GET_PROJECT_BY_ID = "Project.getProjectById";
private static final String GET_PROJECT_LIST = "Project.getProjectList";
#Autowired
private SqlSessionTemplate sqlSessionTemplate;
#Override
public void store(Project object) {
sqlSessionTemplate.insert(STORE_PROJECT, object);
}
#Override
public Project get(String id) {
return sqlSessionTemplate.selectOne(GET_PROJECT_BY_ID, id);
}
#Override
public List<Project> getAllItems() {
return sqlSessionTemplate.selectList(GET_PROJECT_LIST);
}
}
When I wrote an application using spring controller(using JSP) - it was working fine.
But when I added vaadin - JSP stopped working and vaadin application throws NullPointerException for ProjectService, ProjectRepository... all the beans I use.
What is the problem?
All my context xml context files are simple.
<import resource="classpath:com/xxxx/app/pmc/pmc-service-context.xml"/>
<context:component-scan base-package="com.xxx.app.pmc"/>
And my pmc-web-context.xml has this lines too.
<mvc:annotation-driven/>
<context:annotation-config/>
It was working fine with JSP so I think the problem is not with spring declarations itself but with integration of spring into vaadin of mine.
How to resolve it?
When I for example created ProjectTable object manually - it throws NullPointerException for ProjectService. When I create ProjectService manually - it throws NullPointerException for ProjectRepository and so on. It seems autowiring simply doesn't work.
P.S forgot to add my UI code
package com.xxxx.app.pmc.vaadin;
import com.xxxx.app.pmc.vaadin.components.ProjectTable;
import com.vaadin.annotations.Title;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import org.springframework.stereotype.Component;
#Title("PMC")
#Component("pmcVaadin")
public class PmcUi extends UI {
#Override
protected void init(VaadinRequest request) {
VerticalLayout mainLayout = new VerticalLayout();
ProjectTable projectTable = new ProjectTable();
mainLayout.addComponent(projectTable.createTable());
mainLayout.setSizeFull();
setContent(mainLayout);
}
}
Like you suspected your Spring beans are created, but in application and Spring's servlet contexts. Your Vaadin servlet has no access to any of those.
For detailed (manual) solution with code either check Vaadin's wiki or search for a proper Vaadin's add ons that will do the job for you (personally I recommend SpringVaadinIntegration).
The typical idea is to programmatically pass Vaadin servlet to one of Spring's utility classes (eg.: WebApplicationContextUtils) and retrieve application context (loaded by ContextLoaderListener). If you need servlet context, then from code examples I have seen, you do the same as above, but additionally manually read context (eg.: using XmlWebApplicationContext) and set application context as it's parent.
Pretty easy option is to use Configurable support. It'll do some aspect magic and all java objects annotated by #Configurable will be automatically integrated into Spring. You can find more details in Spring documentation. Also please note that to represent context information in GUI you will have to use session beans. That causes the problem with session size, and in bigger applications makes it impossible to cluster.

How to configure Spring MVC with pure Java-based configuration?

I have, what I would consider a pretty simple Spring MVC setup. My applicationContext.xml is this:
<mvc:annotation-driven />
<mvc:resources mapping="/css/**" location="/css/" />
<context:property-placeholder location="classpath:controller-test.properties" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/views/" p:suffix=".jsp" />
My web.xml is currently this:
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
I am trying to convert this set up to pure Java-based config. I've searched the web and so far, I've come up with stuff that explains (some what) how to do the Java config but doesn't explain how to register that Java config with the environment, i.e., the web context.
What I have so far in terms of #Configuration is this:
#Configuration
#EnableWebMvc
#PropertySource("classpath:controller.properties")
#ComponentScan("com.project.web")
public class WebSpringConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
}
#Bean
public ViewResolver configureViewResolver() {
InternalResourceViewResolver viewResolve = new InternalResourceViewResolver();
viewResolve.setPrefix("/WEB-INF/views/");
viewResolve.setSuffix(".jsp");
return viewResolve;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
}
How do I register this with the web container? I am using the latest spring (4.02).
Thanks!
You need to make following changes to web.xml in order to support java based configuration. This will tell the the DispatcherServlet to load configuration using the annotation based java configuration AnnotationConfigWebApplicationContext. You only need to pass the location of your java config file to the contextConfigLocation param, as below
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/*path to your WebSpringConfig*/ </param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Update: Doing the same without making changes to web.xml
You can even do this without web.xml as Servlet Specification 3.0 makes the web.xml optional. You only need to implement/configure WebApplicationInitializer interface to configure the ServletContext which will allow you to create, configure, and perform registration of DispatcherServlet programmatically. The good thing is that WebApplicationInitializer is detected automatically.
In summary, one needs to implement WebApplicationInitializer to get rid of web.xml.
public class MyWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(WebSpringConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext =
new AnnotationConfigWebApplicationContext();
dispatcherContext.register(DispatcherConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
Update: from comments
A slightly more convoluted explanation is also included in the official Spring reference Spring 4 Release
Reference:
http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/web/WebApplicationInitializer.html
Java-based configuration without adding any elements to web.xml. WebApplicationInitializer is a perfect fit for use with Spring's code-based #Configuration classes
WebApplicationInitializer « Interface to be implemented in Servlet 3.0+ environments in order to configure the ServletContext programmatically -- as opposed to (or possibly in conjunction with) the traditional web.xml-based approach. Implementations of this SPI will be detected automatically by SpringServletContainerInitializer, which itself is bootstrapped automatically by any Servlet 3.0 container. Using Servlet Spec 3.0 of Tomcat 7
From Spring 3.2 some Abstract class were listed which implemented WebApplicationInitializer which will be detected automatically by the SrevletContainer.
AbstractAnnotationConfigDispatcherServletInitializer extends
AbstractDispatcherServletInitializer extends
AbstractContextLoaderInitializer implements WebApplicationInitializer
Using Spring 4.1.6.RELEASE version with the modules core, web, webmvc, beans.
public class WebXML_DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { MvcServletXMLConfigurer.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Java-based configuration to Serve Static Resources with Spring. Spring Boot
#Configuration
#EnableWebMvc // <mvc:annotation-driven />
#ComponentScan(value = {"com.github.yash777.controllers"})
// <context:component-scan base-package="com.github.yash777" />
public class MvcServletXMLConfigurer extends WebMvcConfigurerAdapter implements WebMvcConfigurer {
/**
* <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
* p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
*
* #return InternalResourceViewResolver as a bean configuration.
*/
#Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
System.out.println("WebMvcConfigurer - addResourceHandlers() function get loaded...");
// <mvc:resources mapping="/styles/**" location="/css/" />
registry
.addResourceHandler("/styles/**")
.addResourceLocations("/css/") // webapp/css/
.setCachePeriod(3600)
.resourceChain(true) // Spring 4.1
.addResolver(new GzipResourceResolver()) // Spring 4.1
.addResolver(new PathResourceResolver()); // Spring 4.1
// <mvc:resources mapping="/static/**" location="/static/" />
registry.addResourceHandler("/static/**")
.addResourceLocations("/static/", "classpath:/static/") // src/main/resources/static/
.setCachePeriod(3600)
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
}
Listed a sample controller:
#Controller
#RequestMapping(value = { "/controller", "/c" })
public class Test extends HttpServlet {
private static final long serialVersionUID = 1L;
#RequestMapping(value = {"/message", "/m"}, method = RequestMethod.GET )
public void message(HttpServletRequest request, HttpServletResponse response ) throws IOException {
System.out.println("#Controller Get method called.");
}
#RequestMapping(value = "/getView", method = RequestMethod.GET )
public ModelAndView setViewName( Model model ) {
System.out.println("GET... /getView");
ModelAndView mav = new ModelAndView();
mav.setViewName("test");
return mav;
}
}
WEB-INF/web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>

Auto-wiring with spring in an init-param class of a servlet

I am having some difficulty auto-wiring beans into a class which is loaded as an init-param in a servlet for OData4j. I have tried many solutions including load-time-weaving but cannot seem to get it to work correctly because as I understand it, the class which is being passed as an init-param to the servlet is being loaded prior to Spring context being loaded at all. Below is the current state of my configuration, is there a way to have dependency injection in a class loaded in such a way? The end goal is to have the ExampleProducerFactory.java (which is an init-param of the OData servlet) having the UserDao bean autowired.
I have tried to just include the key pieces of each of these files, if there is additional configuration information needed, please comment.
applicationContext.xml
<context:component-scan base-package="com.project.core"/>
<context:spring-configured/>
<context:load-time-weaver weaver-class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver" />
web.xml
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<!-- read the XmlWebApplicationContext for spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>OData</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
<param-value>org.odata4j.producer.resources.ODataResourceConfig</param-value>
</init-param>
<init-param>
<param-name>odata4j.producerfactory</param-name>
<param-value>com.wildgigs.core.odata.ExampleProducerFactory</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>OData</servlet-name>
<url-pattern>/example.svc/*</url-pattern>
</servlet-mapping>
ExampleProducerFactory.java
#Configurable(autowire= Autowire.BY_NAME)
public class ExampleProducerFactory implements ODataProducerFactory {
#Autowired
private UserDao userDao;
#Override
public ODataProducer create(Properties arg0) {
InMemoryProducer producer = new InMemoryProducer("example");
List<User> users = userDao.findAll();
User[] usersArray = new User[users.size()];
users.toArray(usersArray);
final User[] usersArrayFinal = usersArray;
producer.register(User.class, Long.class, "Users", new Func<Iterable<User>>() {
public Iterable<User> apply() {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
while (tg.getParent() != null)
tg = tg.getParent();
return Enumerable.create(usersArrayFinal).take(usersArrayFinal.length);
}
}, "Id");
return producer;
}
}
UserDaoImpl.java
#Repository
public class UserDaoImpl extends GenericDaoImpl<User, Long> implements UserDao, Serializable {
#Transactional(readOnly = true)
public User getByUserName(String userName) {
Query query = getSession().createQuery("FROM User where upper(userName) = :name");
query.setString("name", userName.toUpperCase());
return (User) query.uniqueResult();
}
}
You should use the jersey SpringServlet instead of the ServletContrainer. With that instead of specifying resourceConfig in the init param you can define it as a spring bean.
A bean must be created in your spring config to inject into your class.
<bean id="userDao" class="com.yourdomain.pacakage.UserDao">

Categories