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;
}
Related
I've created a Servlet and added configuration in web.xml:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.foo.web.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myservlet/*</url-pattern>
</servlet-mapping>
Registered a bean for it:
<bean id="MyServlet" class="com.foo.MyServlet" autowire="byType">
<property name="MyService" ref="MyManager"/>
</bean>
I've created a bean which is injected into MyServlet
<bean id="MyManager" class="com.foo.MyService" autowire="byType">
</bean>
There s a setter method in the servlet used by spring for setting the property to the bean:
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private MyManager myService;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws
ServletException, IOException {
}
public void setMyService(MyManager myManager){
this.myService = myManager;
}
}
Autowiring is done correctly during the application startup, but when Servlet "catches" some request, this property (myService) is not instantiated (it's null). How or can I even have a Servlet with some autwired properties?
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
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'.
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>
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">