#Service Spring as Managed property of ManagedBean class in jsf is null - spring

I've a webapp using JSF + Spring + Maven + JBoss (java 8).
I've a class ManagedBean with a property ManagedProperty which is a service spring.
In remote debugging I checked that the service is not injected and is null.
No errors in console (or server.log).
java class
#ManagedBean(name = "userBean")
#SessionScoped
public class UserBean implements Serializable {
...
#ManagedProperty(value = "#{loggedUserSession}")
private ILoggedUserSession loggedUserSession;
public String getUserLogin() {
return loggedUserSession.getUser();
}
public ILoggedUserSession getLoggedUserSession() {
return loggedUserSession;
}
public void setLoggedUserSession(ILoggedUserSession loggedUserSession) {
this.loggedUserSession = loggedUserSession;
}
...
}
service java class
#Service("loggedUserSession")
#Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class LoggedUserSessionImpl implements ILoggedUserSession, Serializable {...}
pom.xml
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.2.13</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>6.2</version>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0.SP1</version>
</dependency>
...
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
In the applicationContext.xml i mapped <context:component-scan ... /> and
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:conf.properties</value>
</property>
</bean>
I noticed the error at runtime.
I checked in web.xml, faces-config, applicationContext.xml and pom.xml but I didn't find anything strange.

Related

MockMvc to test SpringMVC Rest Web Service using JUnit, Mockito, and Hamcrest

Am using Spring MVC to create Restful Web Services...
Here's my pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.0.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>0.9.1</version>
<scope>test</scope>
</dependency>
WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>MyApp</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<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/mvc-dispatcher-servlet.xml</param-value>
</context-param>
</web-app>
WEB-INF/mvc-dispatcher-servlet.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
<import resource="classpath:database_db.xml" />
<context:component-scan base-package="com.myapp.rest" />
<mvc:annotation-driven />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
src/main/resources/database_db.xml:
<beans xmlns="http://www.springframework.org/schema/beans">
<bean id="dataSourceDB" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql://localhost/mydatabase?zeroDateTimeBehavior=convertToNull</value></property>
<property name="username"><value>root</value></property>
<property name="password"><value></value></property>
</bean>
</beans>
UserController:
#Controller
#RequestMapping("/v2")
public class UserController {
private final UserDAO dao;
#Autowired
public UserController(UserDAO dao) {
this.dao = dao;
}
#RequestMapping(value = "users/appId", method = RequestMethod.GET)
public #ResponseBody Object getUserDetails(#PathVariable String appId) {
Object response = null;
response = dao.getUser(appId);
return response;
}
}
UserDAO:
#Repository
public class UserDAO {
private JdbcTemplate jdbcTemplate;
#Autowired
public UserDAO(#Qualifier("dataSourceDB") DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// Various get and finder methods
}
src/test/java:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:**/mvc-dispatcher-servlet.xml")
#WebAppConfiguration
public class UserControllerTest {
#Autowired
private WebApplicationContext ctx;
private MockMvc mockMvc;
#InjectMocks
private UserController userController;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
}
#Test
public void appUser() throws Exception {
String appId = "1234FD57";
mockMvc.perform(get("/v2/users/{appId}", appId)
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk());
}
}
Here's the output:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.myapp.rest.controllers.UserControllerTest
MockHttpServletRequest:
HTTP Method = GET
Request URI = /v2/users/1234FD57
Parameters = {}
Headers = {Accept=[application/json]}
Handler:
Type = com.myapp.rest.controllers.UserController
Method = public java.lang.Object com.myapp.rest.controllers.UserController.getUserDetails(java.lang.String)
Async:
Was async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.751 sec
The test runs but the body doesn't contain any JSON (notice how its blank)...
When I change the contents of my test method to:
mockMvc.perform(get("/v2/users/{appId}",appId)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$[1].userId", is("1234FD57")));
Received the following error:
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.766 sec <<< FAILURE!
user(com.myapp.rest.controllers.UserControllerTest) Time elapsed: 0.157 sec <<< ERROR!
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.myapp.rest.controllers.UserControllerTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.myapp.rest.controllers.UserController
com.myapp.rest.controllers.UserControllerTest.userController; nested exception is org.springframework.beans.factory
NoSuchBeanDefinitionException: No qualifying bean of type [com.myapp.rest.controllers.UserController] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.mockito.InjectMocks(), #org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties
Its just like in the print() statement showing nothing for "Body" no JSON... Am getting really close, does anyone know what I am off by?
Since you are working with Spring 4.0.3 you have to use the old jsonpath 0.9.1, see https://jira.spring.io/browse/SPR-12299
I don't think you are initialising your UserController in your test. You can either:
Initialise it in the test yourself. UserController userController = new UserController();
#Autowire the UserController. But you would also need to include the configuration with your component scan into the #ContextConfiguration

Could not autowire field/expected at least 1 bean which qualifies as autowire candidate

I am pretty new to Spring and although I have used it for a couple of projects before and I've seen a lot of similar questions, I can't figure out what is wrong with this exception:
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'applicationController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: public service.UserServiceI controller.ApplicationController.userService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [service.UserServiceI] 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), #org.springframework.beans.factory.annotation.Qualifier(value=userService)}
This is the relevant part of the stack trace.
Here is my controller class:
#Controller
#RequestMapping("/")
public class ApplicationController {
#Autowired
#Qualifier("userService")
public UserServiceI userService;
}
This is my UserService interface:
public interface UserService {
//methods
}
And the implementation:
#Service("userService")
public class UserServiceI implements UserService{
#Autowired
private UserDao dao;
//methods
}
Here is my XML configuration file:
<context:component-scan base-package="configuration">
</context:component-scan>
<bean id="resView" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
</bean>
<mvc:default-servlet-handler/>
<mvc:resources location="/resources/css/" mapping="/resources/css/*">
</mvc:resources>
<mvc:resources location="/resources/js/" mapping="/resources/js/*">
</mvc:resources>
<context:annotation-config></context:annotation-config>
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:default-servlet-handler />
<context:component-scan base-package="controller">
</context:component-scan>
<context:component-scan base-package="dao"></context:component-scan>
<context:component-scan base-package="model"></context:component-scan>
<context:component-scan base-package="service"
use-default-filters="true">
</context:component-scan>
This is Spring configuration:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "{configuration, controller, dao, model, service}")
public class SpringConfig extends WebMvcConfigurerAdapter{
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WebContent/");
viewResolver.setSuffix(".jsp");
registry.viewResolver(viewResolver);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
And Hibernate configuration:
#Configuration
#EnableTransactionManagement
#ComponentScan({"configuration", "controller", "dao", "model", "service"})
#PropertySource(value = {"classpath:appProperties"})
public class HibernateConfig {
#Autowired
private Environment environment;
#Bean
public LocalSessionFactoryBean sessionFactory(){
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] {"model"});
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
#Bean
public Properties hibernateProperties(){
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect",environment.getRequiredProperty("hibernate.dialect"));
hibernateProperties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
hibernateProperties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
return hibernateProperties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
And pom.xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.6.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.31</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
I commented the code in Controller and the result was that it was unable to autowire SessionFactory, although it is defined. Please help me!
Few things:
You should autowire the interface, and not the implementation:
#Autowired
public UserService userService;
Remove the value param being passed to the #Service in UserServiceI, unless you want to use some fancy name, otherwise Spring will use the name of the bean in lowercases automatically (remember you should be autowiring the interface);
Are you sure your packages are named only controller, dao, etc and not xxx.yyy.controller? Because if they have a prefix, your scan is incorrect here:
<context:component-scan base-package="service"
use-default-filters="true">
</context:component-scan>
3.1. Just a tip, but you can use comma to separate your packages, instead of multiple declarations:
<context:component-scan base-package="service, dao, controller, ..." />
To debug, temporarily comment :
#Autowired
#Qualifier("userService")
public UserServiceI userService;
and print all the beans loaded by spring container in your controller :
#Autowired
private ApplicationContext applicationContext;
#RequestMapping("/print")
public void print() {
String[] beanNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println(beanName + " : " + applicationContext.getBean(beanName).getClass().toString());
}
}
and make sure your service bean is loaded.

Error creating bean 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#1'

I'm trying to create a web-app, using Maven and Intellij Idea. Tests work fine as installing in .war-file. But when I try to refer to my rest with jetty, I have lots of error cases:
Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#1' defined in ServletContext resource [/WEB-INF/rest-spring.xml]: Initialization of bean failed;
nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/JsonProcessingException
Here are rest module files:
Web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>restDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--the location of the spring context configuration file-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/rest-spring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>restDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
rest-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:model.properties</value>
<value>classpath:database.properties</value>
<value>classpath:automobile.properties</value>
</list>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath*:create-tables-model.sql"/>
<jdbc:script location="classpath*:create-tables-automobile.sql"/>
<jdbc:script location="classpath*:data-script.sql"/>
</jdbc:initialize-database>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter"/>
</list>
</property>
</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
<property name="prettyPrint" value="true" />
</bean>
<bean id="modelDao" class="com.dao.ModelDaoImpl">
<constructor-arg ref="dataSource" />
</bean>
<bean id="automobileDao" class="com.dao.AutomobileDaoImpl">
<constructor-arg ref="dataSource" />
</bean>
<bean id="modelService" class="com.service.ModelServiceImpl">
<property name = "modelDao" ref = "modelDao"/>
</bean>
<bean id="automobileService" class="com.service.AutomobileServiceImpl">
<property name = "automobileDao" ref = "automobileDao"/>
</bean>
<context:component-scan base-package="com.rest"/>
</beans>
ModelRestController
package com.rest;
import com.dto.ModelDto;
import com.general.Model;
import com.service.ModelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List;
/**
* Created by kohtpojiep on 23.01.16.
*/
#RestController
public class ModelRestController
{
private static final Logger LOGGER = LogManager.getLogger();
#Autowired
private ModelService modelService;
#RequestMapping(value="/models", method = RequestMethod.GET)
public #ResponseBody List<Model> getAllModels()
{
LOGGER.debug("Getting all models");
return modelService.getAllModels();
}
#RequestMapping(value="/model", method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.CREATED)
public #ResponseBody Integer addModel(#RequestBody Model model)
{
LOGGER.debug("Adding model modelName = {}", model.getModelName());
return modelService.addModel(model);
}
#RequestMapping (value="/model/{modelId}/{modelName}", method=RequestMethod.PUT)
#ResponseStatus(value = HttpStatus.ACCEPTED)
public #ResponseBody void updateModel(#PathVariable(value="modelId") Integer modelId,
#PathVariable(value="modelName") String modelName)
{
LOGGER.debug("Updating model modelId = {}", modelId);
modelService.updateModel(new Model(modelId,modelName));
}
#RequestMapping (value="/model/{modelName}", method = RequestMethod.DELETE)
#ResponseStatus(value = HttpStatus.NO_CONTENT)
public #ResponseBody void deleteModelByName(#PathVariable(value = "modelName") String modelName)
{
LOGGER.debug("Deleting model modelName= {}",modelName);
modelService.deleteModelByName(modelName);
}
#RequestMapping (value="/modelsdto", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.OK)
public #ResponseBody
ModelDto getModelsDto()
{
LOGGER.debug("Getting models Dto");
return modelService.getModelDto();
}
}
AutomobileRestController
package com.rest;
import com.dto.AutomobileDto;
import com.general.Automobile;
import com.service.AutomobileService;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List;
/**
* Created by kohtpojiep on 02.02.16.
*/
#RestController
public class AutomobileRestController
{
private static final Logger LOGGER = LogManager.getLogger();
#Autowired
AutomobileService automobileService;
private static LocalDate convertToLocalDate(String date)
{
DateTimeFormatter formattedDate = DateTimeFormat.forPattern("dd/MM/yyyy");
return formattedDate.parseLocalDate(date);
}
#RequestMapping(value = "/automobiles", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.ACCEPTED)
public #ResponseBody List<Automobile> getAllAutomobiles()
{
LOGGER.debug("Getting all automobiles");
return automobileService.getAllAutomobiles();
}
#RequestMapping(value = "/automobile", method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.CREATED)
public #ResponseBody Integer addAutomobile (#RequestBody Automobile automobile)
{
LOGGER.debug("Adding automobile modelName = {}",automobile.getModelName());
return automobileService.addAutomobile(automobile);
}
#RequestMapping(value = "/automobile/update", method = RequestMethod.PUT)
#ResponseStatus(value = HttpStatus.ACCEPTED)
public #ResponseBody void updateAutomobile (#RequestBody Automobile automobile)
{
LOGGER.debug("Updating automobile automobileId = {}", automobile.getAutomobileId());
automobileService.updateAutomobile(automobile);
}
#RequestMapping(value = "/automobile/{automobileId}", method = RequestMethod.DELETE)
#ResponseStatus(value = HttpStatus.NO_CONTENT)
public #ResponseBody void depeteAutomobile (#PathVariable (value="automobileId")
Integer automobileId)
{
LOGGER.debug("Deleting automobile automobileId = {}",automobileId);
automobileService.deleteAutomobileById(automobileId);
}
#RequestMapping(value = "/automobiles/date-sort", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.ACCEPTED)
public #ResponseBody List<Automobile> getAutomobilesSortedByDate (#RequestParam(value="firstDate")
String firstDate, #RequestParam (value="lastDate") String lastDate)
{
LOGGER.debug("Getting automobiles sorted by date:\n");
return automobileService.getAutomobilesSortedByDate(
convertToLocalDate(firstDate),convertToLocalDate(lastDate));
}
#RequestMapping(value = "/automobilesdto", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.OK)
public #ResponseBody
AutomobileDto getAutomobileDto()
{
LOGGER.debug("Getting automobile DTO");
return automobileService.getAutomobileDto();
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>usermanagement</artifactId>
<groupId>com.epam.brest.course2015</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>app-rest</artifactId>
<name>${project.artifactId}</name>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>com.epam.brest.course2015</groupId>
<artifactId>app-service</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.16.v20140903</version>
<configuration>
<stopPort>9091</stopPort>
<stopKey>STOP</stopKey>
<webAppConfig>
<contextPath>/rest</contextPath>
<allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
</webAppConfig>
<scanIntervalSeconds>10</scanIntervalSeconds>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8081</port>
</connector>
</connectors>
</configuration>
</plugin>
</plugins>
</build>
</project>
I saw solutions for similar situations: people offer to change versions of used frameworks and up the search level of component scan, but it doesn't work for me.
Add dependency to your POM:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
As you use dependency management in parent POM, there is no need to specify version.
Solved! The problem was I use not only jackson-core dependency, but also jackson databind, datatype and annotations and these dependencies had different versions: 2.7.1 for "core" and 2.4.3 for other ones. Now I use the same version for all of them and thus adding dependency had an affect. Thx for your help!)
I had the same problem. I used spring version 5.0.5.RELEASE and Jackson Core version 2.4.3.
I upgraded Jackson core up to 2.9.5 and it works now : exception "Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter' " dissapeared and my rest service works.
Before in my pom.xml :
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.3</version>
</dependency>
After :
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
I hope it will help.
Yes. Using version 2.9.5 works:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
I'm using spring-webmvc: 5.0.12.RELEASE, if that helps.

jersey-spring3 instantiating Spring-managed bean (null!)

I first want to point out that this is by and large the biggest problem in terms of time wasted that I have ever dealt with in my career. (Over two days straight now with essentially 0 progress.) Every single "work-around" or "solution" I have attempted hasn't worked, so I am blocked and pretty desperate for some assistance.
The problem in a nutshell is that Jersey/HK2 seems to always instantiate my Spring-managed beans AFTER they have already been instantiated by Spring, which tells me that jersey-spring3 is not doing its job, or at least not with my current setup (or any of the ~50 permutations of setups I have tried thus far.)
Note that when I use an empty constructor, those resource fields are null at run-time.
I do not understand why my current setup doesn't work as I am essentially copying this online example
Any help is more than appreciated!!
Configuration
- - - - - pom.xml - - - - -
<!-- ... -->
<dependencies>
<!-- Spring Dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument-tomcat</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-parent</artifactId>
<version>${spring.version}</version>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.version}</version>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-support</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-dao</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!-- / Spring Dependencies -->
<!-- API dependencies -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-processing</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<!-- / API dependencies -->
<!-- ... -->
</dependencies>
<!-- ... -->
<properties>
<!-- ... -->
<spring.version>3.0.5.RELEASE</spring.version>
<jersey.version>2.4.1</jersey.version>
<gson.version>2.2.4</gson.version>
<!-- ... -->
</properties>
<!-- ... -->
- - - - - web.xml - - - - -
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/beans.xml</param-value>
</context-param>
<!-- ... -->
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>fubar.rest.FubarJerseyApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<!-- ... -->
</web-app>
- - - - - beans.xml (Context Configuration) - - - - -
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- ... -->
<!-- beans-outbound-api has configuration for spring-jersey3 to work properly -->
<import resource="beans-api.xml" />
</beans>
- - - - - beans-api.xml - - - - -
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Services -->
<bean id="locationServiceV1" class="fubar.rest.v1.services.location.impl.LocationServiceV1" />
<bean id="locationServiceV2" class="fubar.rest.v2.services.location.impl.LocationServiceV2" />
<bean id="viewServiceV1" class="fubar.rest.v1.services.view.impl.ViewServiceV1" />
<bean id="viewServiceV2" class="fubar.rest.v2.services.view.impl.ViewServiceV2" />
<!-- Resources -->
<bean class="fubar.rest.resources.location.impl.LocationResource">
<constructor-arg index="0" ref="locationServiceV1" />
<constructor-arg index="1" ref="locationServiceV2" />
</bean>
<bean class="fubar.rest.resources.view.impl.ViewResource">
<constructor-arg index="0" ref="viewServiceV1" />
<constructor-arg index="1" ref="viewServiceV2" />
</bean>
</beans>
Code
- - - - - Resource (JAX-RS) - - - - -
#Path(RESTLocationResourceV1.PathFields.PATH_ROOT)
#Produces({V1_JSON, APPLICATION_JSON})
public class LocationResource
extends ResourceBase<LocationResource, ILocationServiceV1, ILocationServiceV2> {
private static final Logger logger = Logger.getLogger(LocationResource.class);
#Inject
public LocationResource(final LocationServiceV1 v1Loc, final LocationServiceV2 v2Loc) {
super(v1Loc, v2Loc);
logger.info(format(Messages.INF_INSTANTIATED, "LocationResource"));
}
#GET
#Path(PathFields.SUBPATH_LIST)
public LocationListV1 listV1(#HeaderParam(HEADER_API_KEY) String apiKey)
throws ApplicationException {
// Implementation
}
#GET
#Path(PathFields.SUBPATH_SEARCH)
public LocationListV1 searchV1(#HeaderParam(HEADER_API_KEY) String apiKey,
#QueryParam(QueryFields.QUERY) String likeText) throws ApplicationException {
// Implementation
}
}
- - - - - Service (Spring Bean) - - - - -
public class LocationServiceV1 extends ServiceBaseV1<LocationBean, LocationV1, LocationListV1>
implements
ILocationServiceV1 {
#Autowired
private LocationDao daoLoc;
public LocationServiceV1() {
super(new LocationBeanToJsonTranslatorV1());
}
#Override
public LocationListV1 listV1() throws ApplicationException {
// Implementation
}
#Override
public LocationListV1 searchV1(String likeText) throws ApplicationException {
// Implementation
}
}
(Essentially the same for version 2)
- - - - - Application (Jersey) - - - - -
public class FubarJerseyApplication extends ResourceConfig {
private static final class Messages {
static final String INF_STARTING_APPLICATION = "Starting %s!";
}
private static final Logger logger = Logger.getLogger(FubarJerseyApplication.class);
public FubarJerseyApplication() {
packages("fubar.rest");
logger.info(format(Messages.INF_STARTING_APPLICATION, this.getClass().getName()));
}
}
Invocation (Client)
curl http://my-ip-address/fubar/api/location/list
(500 Internal Server Error)
Error (Server)
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object
available for injection at Injectee(requiredType=LocationServiceV1,parent=
LocationResource,qualifiers={}),position=0,optional=false,self=false,
unqualified=null,344016971)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
at org.jvnet.hk2.internal.ClazzCreator.resolve(ClazzCreator.java:208)
at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:225)
at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:329)
at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:456)
at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:158)
at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2350)
at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:612)
at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:597)
at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:173)
at org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:185)
at org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:103)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:128)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131)
at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:110)
at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:65)
at org.glassfish.jersey.process.internal.Stages.process(Stages.java:197)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:250)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:983)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:361)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at fubar.server.springframework.SessionFilter.doFilter(SessionFilter.java:44)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at fubar.server.springframework.loader.ContextLoaderHttpInterceptor$LoaderState.filter(ContextLoaderHttpInterceptor.java:75)
at fubar.server.springframework.loader.ContextLoaderHttpInterceptor$StartedState.filter(ContextLoaderHttpInterceptor.java:120)
at fubar.server.springframework.loader.ContextLoaderHttpInterceptor.doFilter(ContextLoaderHttpInterceptor.java:62)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190)
at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:311)
at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:776)
at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:705)
at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:898)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
at java.lang.Thread.run(Thread.java:662)
API Log
Dec 10, 2013 13:36:28 INFO [main] fubar.rest.FubarJerseyApplication
- Starting fubar.rest.FubarJerseyApplication!
Dec 10, 2013 13:38:06 INFO [pool-1-thread-1] resources.location.impl.LocationResource
- LocationResource has been instantiated
Dec 10, 2013 13:38:06 INFO [pool-1-thread-1] resources.view.impl.ViewResource
- ViewResource has been instantiated
Update -- found this:
Catalina Log
Dec 10, 2013 1:36:42 PM org.glassfish.jersey.server.ApplicationHandler initialize
INFO: Initiating Jersey application, version Jersey: 2.4.1 2013-11-08 12:08:47...
Dec 10, 2013 1:36:43 PM org.glassfish.jersey.server.spring.SpringComponentProvider initialize
SEVERE: Spring context lookup failed, skipping spring component provider initialization.
Dec 10, 2013 1:38:00 PM com.sun.xml.bind.v2.runtime.reflect.opt.Injector inject
... so the ApplicationContext isn't found in SpringComponentProvider#initialize.
What's loading first? Spring or Jersey? It could be that your Spring context isn't initialized when SpringComponentProvider calls WebApplicationContextUtils.getWebApplicationContext(sc);. Try using Spring's ContextLoaderListener so that Spring does its initialization right after the app is deployed.
I ran into a lot of the same issues that you're experiencing with the jersey-spring3 library. It had problems finding my Spring ApplicationContext (looks like this is where you're stuck) and it blew up injecting setters that took a generic parameter as an argument.
If you get past the app context issue, I don't think what you have will work anyway. You defined the ViewResource and LocationResource beans in XML. From what I can tell, Jersey will only get the resource instance from Spring if the the resource class is annotated with #Component. Take a look at org.glassfish.jersey.server.spring.SpringComponentProvider, specifically component.isAnnotationPresent(Component.class):
// detect JAX-RS classes that are also Spring #Components.
// register these with HK2 ServiceLocator to manage their lifecycle using Spring.
#Override
public boolean bind(Class<?> component, Set<Class<?>> providerContracts) {
if (ctx == null) {
return false;
}
if(component.isAnnotationPresent(Component.class)) {
DynamicConfiguration c = Injections.getConfiguration(locator);
String[] beanNames = ctx.getBeanNamesForType(component);
if(beanNames == null || beanNames.length != 1) {
LOGGER.severe(LocalizationMessages.NONE_OR_MULTIPLE_BEANS_AVAILABLE(component));
return false;
}
String beanName = beanNames[0];
ServiceBindingBuilder bb = Injections.newFactoryBinder(new SpringComponentProvider.SpringManagedBeanFactory(ctx, locator, beanName));
bb.to(component);
Injections.addBinding(bb, c);
c.commit();
LOGGER.config(LocalizationMessages.BEAN_REGISTERED(beanName));
return true;
}
return false;
}
An unrelated issue was that we also wanted to move all of our JAX-RS annotations to interfaces. Whenever I tried it, I got "Could not find a suitable constructor for com.foo.ResourceInterface".
In the end, I solved all of my issues by not using jersey-spring3 and rolling my own Jersey to Spring connector. Here's what I did:
Configured all of my resources as regular Spring beans. You can use XML if you want.
In my Application, I added bindings to the HK2 container to use a factory whenever it needs an instance of one of the resources. My factory class simply returns the Spring managed instance of the resource.
Before the factory returns the Spring-managed bean, I use the Jersey/HK2 ServiceLocator to inject things that Jersey provides. For example, anything annotated with #Context.
My javax.ws.rs.Application looks like this:
public class RestConfig extends ResourceConfig {
private static final Log log = LogFactory.getLog(RestConfig.class);
#Inject
public RestConfig(ServiceLocator locator) {
super();
// specific to my app. get your spring beans however you like
Collection<Object> beans = BeanLocator.beansByAnnotation(RestResource.class);
DynamicConfiguration c = Injections.getConfiguration(locator);
for (Object bean : beans)
{
// tell jersey to use a factory for any interface that the bean implements. since your resources don't implement interfaces,
// you'll want to do something a bit different here.
for (Class<?> currentInterface : bean.getClass().getInterfaces())
{
if (log.isTraceEnabled())
log.trace("binding " + currentInterface.getSimpleName() + " to Spring managed bean");
ServiceBindingBuilder<Object> bb = Injections.newFactoryBinder(new StaticLookupFactory(locator, bean));
bb.to(currentInterface);
Injections.addBinding(bb, c);
}
}
// commit the changes to the HK2 container (don't skip this step!)
c.commit();
property("jersey.config.disableMoxyJson.server", true);
packages("com.foo.web.rest");
register(MoxyXmlFeature.class);
}
// a "factory" where the provide() method returns the spring managed bean
// that was passed to the constructor.
private static class StaticLookupFactory implements Factory<Object> {
private ServiceLocator locator;
private Object bean;
StaticLookupFactory(ServiceLocator locator, Object bean)
{
this.locator = locator;
this.bean = bean;
}
#Override
public Object provide() {
// inject this annotated with #Context, #Inject, etc
locator.inject(bean);
return bean;
}
#Override
public void dispose(Object instance) {
}
}
}
BeanLocator is a utility class that I wrote that makes it easy to grab bean instances using static methods when autowiring isn't available. For example, when working outside of Spring managed beans. Not too much going on there:
public static Collection<Object> beansByAnnotation(Class<? extends Annotation> annotation)
{
return applicationContext.getBeansWithAnnotation(annotation).values();
}
RestResource is also specific to our app. It's a custom stereotype that works like #Component, #Service, etc:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Component
public #interface RestResource {
String value() default "";
}
Note that Jersey allows you to register custom implementations of org.glassfish.jersey.server.spring.ComponentProvider to manage the lifecycle of resources on your own. I tried it but couldn't get it to recognize my implementation no matter what I did.
One other note... the locator.inject(bean) call that activates the Jersey dependency injection mechanism will processes anything marked with #Inject. Use #Autowired within your classes or configure your beans with XML to avoid having both Spring and Jersey attempt to resolve values for things annotated with #Inject.
We have a custom, asynchronous ContextLoader, so the interim solution required placing a total hack in the Jersey-Spring3 source to wait for the application to initialize before the custom component provider initializes.
P.S. For any poor soul who finds themselves having to do something like this, make sure META-INF/settings contains the SpringComponentProvider configuration.
(2014-04-18) Elaborating for #Scott
Note that this is a terrible hack and I would only attempt such a thing as a last resort when all other attempts have failed, like in my case. Also I would consult the Jersey mailing group about your problem before attempting anything like this.
That said... this is what I did to solve my problem:
Literally copied the source code of spring-jersey3 into my application/server, modifying the header of every file with the appropriate tags as per the license;
Created the following class --
===>
/**
* Hack class for RN-8979.
*
* #author ryan
*
*/
public class ContextLoadWaiter {
private static final Logger logger = Logger.getLogger(ContextLoadWaiter.class);
public void doWait() {
try {
while (ContextLoaderHttpInterceptor.isNotStarted()) {
logger.info("Waiting for ContextLoader to start...");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
logger.error("SpringComponentProvider was interrupted!");
}
}
}
Note that this is specific to *our* code-base as ContextLoaderHttpInterceptor is an http servlet where isNotStarted returns true if our custom ContextLoader (which happens to be asynchronous) is not yet loaded.
The custom asynchronous ContextLoader was put in place sometime by somebody for some reason along the lines of allowing the UI to display a "loading" page while the server boots up. (Probably not the correct way to add this UI "feature", but the code was there and the UI depended on it, so I had to deal with it...)
Since this part will not apply directly to you, the key thing is to debug through SpringComponentProvider (from here) and look at the value of the ClassPathXmlApplicationContext. If it is null, as it is in our case, then you need to figure out why it is null and wait on whatever ContextLoader you use to load before you initialize this component.
Placed this hacky line in SpringComponentProvider --
==>
...
private final ContextLoadWaiter waiter = new ContextLoadWaiter();
...
#Override
public void initialize(ServiceLocator locator) {
waiter.doWait(); // Wait on our asynchronous context loader.
this.locator = locator;
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Context lookup started");
}
...
Created this file: META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider with the contents being the fully qualified classpath to the SpringComponentProvider, e.g. com.company.server.nbi.rest.internal.jspring.SpringComponentProvider
Added the custom Jersey-spring3 package as a package to scan in the application; see below...
==>
/**
* Application configuration.
*
* #author ryan
*
*/
public class MyJerseyApplication extends ResourceConfig {
private static final class Messages {
static final String INF_STARTING_APPLICATION = "Starting %s!";
}
private static final Logger logger = Logger.getLogger(MyJerseyApplication.class);
public MyJerseyApplication() {
packages(
/* Internal providers */
"com.company.server.nbi.rest.providers",
/* Internal filters */
"com.company.server.nbi.rest.filters",
/* Spring injection support */
"com.company.server.nbi.rest.internal.jspring", // HERE!!!
/* Json providers */
"com.fasterxml.jackson.jaxrs.json",
/* Jackson exception mappers */
"com.fasterxml.jackson.jaxrs.base");
/* Resources */
register(ResourceA.class);
register(ResourceB.class);
register(ResourceC.class);
/* Miscellaneous features */
register(MultiPartFeature.class);
register(LoggingFilter.class);
logger.info(format(Messages.INF_STARTING_APPLICATION, this.getClass().getName()));
}
}
That's "it". Definitely not a solution to be proud of, but if you are in desperation mode like I was, it probably doesn't hurt to give it a shot.
This is the message that is key to understanding the issue. It indicates that Spring is failing to initialise correctly:
SEVERE: Spring context lookup failed, skipping spring component provider initialization.
(On a side note: because Spring is failing to initialise, the only JSR-330 implementation to try and resolve the #Inject is HK2 - which is why you're seeing the other issue).
Anyway, the problem is likely that your container isn't performing a scan for the annotations that make all the jersey-spring3 magic happen.
This behaviour is part of the Servlet 3.0 Specification (JSR-33, Section 1.6.2), so you should double check that your container supports this.
In the case of Tomcat - unless you're running Tomcat 7.0.29 or newer, you'll actually need to make sure that the Servlet version is specified in your web.xml.
http://tomcat.apache.org/tomcat-7.0-doc/changelog.html#Tomcat_7.0.29_(markt)
I hit this problem recently and it drove me nuts, and fixing the web.xml was easier than upgrading from Ubuntu/Precise!
Hope this helps!

Spring DI - Autowired property is null in a REST service

I'm getting started with Spring DI, but I'm struggling with dependency injection and the worse part is that I'm not even sure why as it seems ok to me. Hopefully you guys can help me out!
The problem is that a property annotated as #Autowired is always null
I've got a few projects with Maven structure:
com.diegotutor.lessondeliver
com.diegotutor.utility
I'm running the examples over Tomcat 7
I'm using the following dependencies in my pom.xml:
spring-context 3.2.4
spring-web 3.2.4
jersey-server 1.17.1
jersey-core 1.17.1
jersey-servlet 1.17.1
The simple idea is to have a RESTful service that through Dependency Injection is able to print out the value of a property located in a config file located at: D:\configuracion.conf.
At com.diegotutor.utility I have the following interface:
package com.diegotutor.utility;
public interface ConfigService {
public String getProperty(final String propertyName);
}
Implemented by:
package com.diegotutor.utility.impl;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;
import com.diegotutor.utility.ConfigService;
public class PropertyFileConfigService implements ConfigService{
Properties prop;
public PropertyFileConfigService (final InputStream input) throws IOException {
if(input == null) {
throw new IllegalArgumentException("Input stream can't be null");
}
prop = new Properties();
prop.load(input);
}
public PropertyFileConfigService (final String fileName) throws IOException {
final FileInputStream input = new FileInputStream(fileName);
prop = new Properties();
prop.load(input);
}
public PropertyFileConfigService(final Reader input) throws IOException {
prop = new Properties();
prop.load(input);
}
public String getProperty(final String propertyName) {
return prop.getProperty(propertyName);
}
}
And at com.diegotutor.lessondeliver I have the RESTful service where I would like to use an injected instance of the ConfigService:
package com.diegotutor.lessondeliver;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.diegotutor.utility.ConfigService;
#Path("/")
#Component
public class HelloWorld {
private static final Log log = LogFactory.getLog(HelloWorld.class);
#Autowired
private ConfigService configService;
#Path("/helloworld")
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getHello() {
String host = configService.getProperty("host");
return "Hello World! HOST" + host;
// configService IS NULL!!
//SO IT THROWS A NULLPOINTER EXCEPTION WHEN INVOKING getProperty ON IT
}
}
Finally at /com.diegotutor.lessondeliver/src/main/webapp/WEB-INF/service-beans.xml I have the following XML application context file, where I use the implementation of ConfigService (PropertyFileConfigService) injecting on it the path for the configuration file to read:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="configService" class="com.diegotutor.utility.impl.PropertyFileConfigService">
<constructor-arg type="java.lang.String"
value="D:\configuracion.conf" />
</bean>
<context:component-scan base-package="com.diegotutor" />
</beans>
Obviously I have specified in the web.xml of this com.diegotutor.lessondeliver web app that I want service-beans.xml as ConfigLocation and a listener ContextLoaderListener, and the RESTful service relies on ServletContainer
If I'm specifying context:component-scan to look for Components in com.diegotutor as suggested here and I'm forcing object creation through Spring by not using any new Statement as suggested here, Why am I getting the annotated configService as null? Why Spring is unable to inject an instance of com.diegotutor.utility.impl.PropertyFileConfigService?
Any help will be much appreciated!
Thank you
EDITED:
As requested, my web.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>com.diegotutor.lessondeliver</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/service-beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
You were right!
It seems that the problem is that Jersey is totally unaware of Spring and instantiates its own object. In order to make Jersey aware of Spring object creations (through dependency injection) I had to integrate Spring + Jersey.
To integrate:
Add maven dependencies
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-spring</artifactId>
<version>1.17.1</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
</exclusions>
</dependency>
Use SpringServlet for jersey-servlet in web.xml
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>
com.sun.jersey.spi.spring.container.servlet.SpringServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Now the #Autowired works properly and the object is not null anymore.
I'm a little bit confused about the exclusions I have to use in maven when using jersey-spring dependency, but that's another issue :)
Thank you!
Integration Spring with Jersey 2 (org.glassfish.*):
Maven
Some dependencies may be unnecessary, please check & clear it after things got working.
<properties>
<jersey.version>2.5</jersey.version>
</properties>
<!-- Jersey -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<!-- if your container implements Servlet API older than 3.0, use "jersey-container-servlet-core" -->
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-inmemory</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- Jersey + Spring -->
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>${jersey.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
web.xml
<servlet>
<servlet-name>my-rest-service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.package.with.rest.services</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>my-rest-service</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
applicationContext.xml
During the Spring upgrading I had to move it from /main/webapp/WEB-INF/ to /main/resources/ (details).
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="my.package.with.rest.services" />
</beans>
Example REST service
public interface MyService
{
String work(String s);
}
...
#Service
public class MyServiceImpl implements MyService
{
#Override
public String work(String s)
{
return "Hello, " + s;
}
}
...
#Path("demo/")
#Component
public class DemoRestService
{
#Autowired
private MyService service;
#GET
#Path("test")
public Response test(#FormParam("param") String par)
{
try
{
String entity = service.work(par);
return Response.ok(entity).build();
}
catch (Exception e)
{
e.printStackTrace();
return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Epic REST Failure").build();
}
}
}
or you can simply extend SpringBeanAutoWiringSupport class. Like this: public class DemoRestService extends SpringBeanAutoWiringSupport. By extending this support class, properties of your service class can be auto-wired.
Another possible option is to manually invoke autowiring in your jersey resource:
#Context
private ServletContext servletContext;
#PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, servletContext);
}
Hmm, you get a "manual autowiring"...

Resources