Spring Autowiring Issues in a Servlet - spring

I am having some issues with Autowiring
First off i create an Embedded server
Main.java
Server server = new Server(8080);
CXFNonSpringServlet cxf = new CXFNonSpringJaxrsServlet();
ServletHolder servlet = new ServletHolder(cxf);
servlet.setInitParameter("javax.ws.rs.Application", "com.asd.dispatcher.rest.testApplication");
servlet.setName("services");
servlet.setForcedPath("services");
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/hello");
server.setHandler(context);
context.addServlet(servlet, "/*");
server.start();
testApplication.java
public class testApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(testServlet.class);
return classes;
}
}
testServlet.java
#Path("/people")
#Component
#Scope("prototype")
public class testServlet {
#Autowired
private StatsService statsService;
#Produces({ "application/json" })
#GET
public String getPeople(#QueryParam("page") #DefaultValue("1") final int page) {
System.out.println("======= getPeople");
//statsService.printStats();
return "Hello World";
}
}
Now my issue is that my statsService is not being autowired in testServlet.java, yet i can autowire it into another class annotated with #Service,
is this because of me using a CXFNonSpringServlet??
or is it because of the way i am trying to Autowire?

Ok i got it working
Ok so i fixed it (i would post this as the answer but cant answer my own question :/ )
putting the answer here to help anyone else with the same problem
After having a look at the following
Autowiring in servlet
I came to the conclusion that a Post Construct method that gets the applicationContext and then the bean would work
Eg: my code would be this
#Path("/people")
#Component
#Scope("prototype")
public class testServlet {
private StatsService statsService;
#PostConstruct
public void initStats() {
System.out.println("============================= Init");
ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
statsService = context.getBean("statsService", StatsService.class);
}
#Produces({ "application/json" })
#GET
public String getPeople(#QueryParam("page") #DefaultValue("1") final int page) {
System.out.println("======= getPeople");
statsService.printStats();
return "Hello World";
}
}
Although this is not autowiring it does work, if there is anyone who knows how to do this with autowiring i would love to know as it would be far cleaner then the solution i found.
*on a side note i picked up a new issue with this 'solution' to my problem in that the statsService that i have also has other beans autowired in, and it seems although the auto wiring initializes these beans any changes to their state in another class are not reflected in the statsService infact the state of these beans remain unchanged (although that might be the suspected behavior i am still new to spring so i am not sure)

I don't know what CXFNonSpringServelt is, but my question is: Have you added the lines above in the context-config.xml file of your application?
<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-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
...
...
<context:component-scan base-package="package of the classes with annotations" />
And in your server class you should add the annotation #Service
#Service("myService")
public class MyService ...
And you can use the #Authowire like this:
public class Client{
#Autowire
MyService myservice;
...

Related

Spring Autowiring a list into a bean results in a NoSuchBeanDefinitionException

In a Spring 3.1.3.RELEASE project I want to create and autowire a list that contains some enum to some service.
Unfortunately the autowiring fails (NoSuchBeanDefinitionException), while I can retrieve the bean in the context and manually wire the dependency.
Here is a small testcase showcasing the issue (using Spring 3.1.3 and JUnit):
The XML context (int package /junk):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="junk"/>
<util:list id="myList" value-type="junk.GreatThings">
<value>SUPER</value>
<value>COOL</value>
</util:list>
</beans>
The enum:
package junk;
public enum GreatThings {AMAZING, GREAT, SUPER, COOL}
The test class (in package junk - I've removed the import for clarity):
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath*:junkcontext.xml"})
public class TestAutowiringSupport {
#Autowired #Qualifier("myList") List<GreatThings> greatThings;
#Test public void testSuperCool() {
Assert.assertThat(greatThings, hasItem(SUPER));
Assert.assertThat(greatThings, hasItem(COOL));
}
}
This result in a NoSuchBeanDefinitionException.
I have try to put a #Qualifier with my bean id to help Spring to perform the wiring without any success.
My IDE is however able to detect the wiring by itself:
And if I use the Spring lifecycle callbacks to get back the bean and wire it manually then, it is fine.
Version that compiles and runs fine:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath*:junkcontext.xml"})
public class TestAutowiringSupport implements ApplicationContextAware
{
ApplicationContext ctx;
List<GreatThings> greatThings;
#Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {this.ctx = ctx;}
#PostConstruct
public void manualWiring() {greatThings = (List<GreatThings>) ctx.getBean("myList");}
#Test public void testSuperCool() {
Assert.assertThat(greatThings, hasItem(SUPER));
Assert.assertThat(greatThings, hasItem(COOL));
}
}
What's wrong with the autowiring in this case ?
Looks like some problem with generics.
With Spring 4.1 I am able to execute this code: where greatThings is of type List<Object>
#Qualifier("myList")
#Autowired List<Object> greatThings;
#Test
public void testSuperCool() {
Assert.assertThat(greatThings, Matchers.hasSize(2));
Assert.assertThat(greatThings, Matchers.hasItem(GreatThings.SUPER));
Assert.assertThat(greatThings, Matchers.hasItem(GreatThings.COOL));
}
As stated in the reference documentation, placing the #Autowired annotation over a typed collection means "find all beans of the given type (GreatThings in your case), put them in a collection and inject that collection". You are getting the exception because there are no beans of type GreatThings declared.
The problem is that there is no easy way to declare enum values as beans. Then again I don't see the use case to be honest.

Spring Configuration with annotations #Autowired not working - step by step

I have performed this steps in order to use annotation based configuration:
a) beans.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-3.2.xsd">
<context:annotation-config/>
<context:component-scan base-package="test.*"/>
</beans>
b) then I have this component:
package test;
#Component
public class InMemoryUserService implements UserService
c) then I try to use autowire:
#Autowired
private UserService userService;
and in runtime userService is null.
Basic stuff is set up properly (like dependencies etc.) because in first version of the test app I was using xml based configuration and it was working smoothly.
And this is a class that uses autowireing:
public class DemoApplication {
#Autowired
private UserService userService;
public DemoApplication() {
}
public static void main(String[] args) {
DemoApplication da = new DemoApplication();
da.userService.getUserByEmail("blabla#gmail.com");
}
}
Is there anything else I'm missing?
That is because -
DemoApplication is not a spring managed bean. Make it spring managed by adding #Component similar to UserService.
Use spring bean factory or application context, say ClasspathXMLApplicationContext, to get the DemoApplication instead of new operator.
How will spring know that it has to run this DemoApplication.
You have to run it with a SpringJunit4ClassRunner something like below:
Annotate your DemoApplication as shown below:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class DemoApplication {
#Autowired
private UserService userService;
#Test
public void testBean() {
userService.getUserByEmail("");
}
}

How to load Spring applicationContext into Jersey Application

I'm creating a Jersey JAX-RS web service with the following:
package com.mycompany.rest.config;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
return getRestResourceClasses();
}
private Set<Class<?>> getRestResourceClasses() {
Set<Class<?>> resources = new java.util.HashSet<Class<?>>();
resources.add(com.mycompany.rest.controllers.UserController.class);
return resources;
}
}
However, when I try and integrate a spring applicationContext such as the following :
<?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">
<context:component-scan base-package="com.mycompany.rest.user"/>
<bean id="userService" class="com.mycompany.rest.user.UserServiceImpl" />
</beans>
I get null pointers from my controller class for the userService being loaded by the bean pasted above. I'm assuming this is because the application context is not being loaded into the Jersey application.
Is there a way of doing this?
If you want to inject Spring beans into your Jersey resource classes, you need to add jersey-spring3 dependency to your class path. see https://jersey.java.net/documentation/latest/spring.html
An hello-world example can be found at https://github.com/jersey/jersey/tree/2.19/examples/helloworld-spring-webapp
I had the same problem, and i fixed it by adding #autowired to my service, and extending SpringBeanAutowiringSupport like the following :
#Path("/mails")
public class MailController extends SpringBeanAutowiringSupport{
#Autowired
private MailService mailService;
#GET
#Path("/{code}")
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public String getMails(#PathParam("code") String code) throws Exception {
//function logic
}
Note that this is working without integrating jersey-springx.jar
And I'm using Spring 3 along with jersey-bundle-1.19.1.jar

Converting spring xml to java configuration with implicit setter autowiring and ComponentScan

I have two classes: vehicle.Tire and vehicle.Car.
package vehicle;
#Named
public class Tire {
private String age;
}
package vehicle;
#Named
public class Car {
private Tire tire;
// Spring calls this setter because default-autowire="byName" of xml configuration
public void setTire(Tire newTire) {
this.tire = newTire;
}
public Tire getTire() {
return this.tire;
}
}
The following spring xml works fine.
<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-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
default-autowire="byName">
<context:component-scan base-package="vehicle" />
</beans>
I tried to create a java configuration above:
#Configuration
#ComponentScan(basePackages={"vehicle"})
public VehicleConfig {
}
I'm not using #Inject nor #Autowired annotations in the classes, but spring autowires and it works with xml.
Using java configuration, the method setTire of Car is not called :(
What is missing? How can I change java configuration using component scan without modifying Car and Tire classes? Is there default-autowire="byName" xml tag attribute equivalent in java?
I used the class above to test java configuration
#Test
public class VehicleConfigTest {
public void testTire() {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
applicationContext.register(VehicleConfig.class);
applicationContext.refresh();
Car car = applicationContext.getBean(Car.class);
Assert.assertNotNull(car.getTire());
}
}
Thanks in advance.
There is no equivalent in sprig java configuration to default-autowire="byName" global xml tag attribute.
More, the right way to have injection is using #Inject annotation by cdi or #Autowired annotation by spring. So, the class Car should be modified:
package vehicle;
#Named
public class Car {
#Inject
private Tire tire;
public Tire getTire() {
return this.tire;
}
}
Now, both xml or java configuration works.

MyBatis-Spring + #Configuration - Can't autowire mapper beans

I have been trying to create a Spring project that uses MyBatis for the data access layer as a proof of concept for my team. I really want to avoid XML configuration if at all possible, so I'm attempting to wire everything together using annotated #Configuration classes.
Everything seems to be wired correctly, but my mapper beans are not being AutoWired into my service layer.
In my example I'm trying to wire together a UserDao, User entity, and a UserService.
UserDao
public interface UserDao {
#Select("SELECT * FROM users WHERE id = #{userId}")
User get(#Param("userId") Integer userId);
}
User
#Component("User")
public class User implements Entity {
public Integer userId;
public String username;
/** ... getters/setters ommitted **/
}
UserServiceImpl
#Service("UserService")
public class UserServiceImpl {
private UserDao userDao = null;
public User getUserDetails(Integer userId) {
return userDao.get(userId);
}
#Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
I'm wiring these together using two configuration classes.
ApplicationContextConfig
#Configuration
#EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
#Import(DefaultDataAccessConfig.class) // I'm importing this because I thought ordering might be important, otherwise I was hoping to just let the component scanning pull in additional configuration files
#ComponentScan(basePackages="com.example.gwtspringpoc.server",
excludeFilters=#Filter(type=FilterType.ANNOTATION,
value=Controller.class))
public class ApplicationContextConfig {
/** No bean definitions needed here **/
}
DefaultDataAccessConfig
#Configuration
#EnableTransactionManagement
public class DefaultDataAccessConfig implements TransactionManagementConfigurer {
#Bean
public DataSource dataSource() {
OracleDataSource ods = null;
try {
ods = new OracleDataSource();
} catch (SQLException e) {
throw new RuntimeException(e);
}
ods.setURL("jdbc:oracle:thin:#//localhost:9601/sid");
ods.setUser("user");
ods.setPassword("pass");
return ods;
}
#Override
#Bean(name="transactionManager")
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
public SqlSessionFactory sqlSessionFactory() {
SqlSessionFactoryBean sf = new SqlSessionFactoryBean();
sf.setDataSource(dataSource());
try {
return (SqlSessionFactory) sf.getObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Bean
public SqlSession sqlSessionTemplate() {
return new SqlSessionTemplate(sqlSessionFactory());
}
/*
* This did not work at all. It seems to be configured correctly, but the UserDao bean never
* got created at any stage, which was very disappointing as I was hoping not to have to
* create a bean definition for each DAO manually
*/
/*#Bean
public static MapperScannerConfigurer mapperScannerConfig() {
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.ca.spna.gwtspringpoc.server.model.dao");
msc.setAnnotationClass(Repository.class);
return msc;
}*/
/*
* Because the above code did not work, I decided to create the mapping manually.
* This is most likely my problem - something about this setup. My understanding
* is that the MapperFactoryBean once instantiated by Spring, will create a proxy
* object of type UserDao with the name "userDao" that can be injected elsewhere.
*/
#Bean
public MapperFactoryBean<UserDao> userDao() {
MapperFactoryBean<UserDao> mfb = new MapperFactoryBean<UserDao>();
mfb.setMapperInterface(UserDao.class);
return mfb;
}
}
You can read the comments above the last two methods in the above code snippet to gain more insight into how I'm creating the UserDao bean.
Once I got all the configuration setup, I created a unit test to try to test the UserService using the AnnotationConfigContextLoader, but was immediately hit with the following exception when trying to run the test:
Exception
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.example.gwtspringpoc.server.service.UserServiceImpl.setUserDao(com.example.gwtspringpoc.server.model.dao.UserDao); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.example.gwtspringpoc.server.model.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
After seeing that, I commented out the #Autowired in the UserService and went back to my unit test and injected the ApplicationContext so I could inspect it, and the bean named "userDao" is in fact a MapperProxy instance.
So, is my understanding of how the MapperFactoryBean works off track or is it just not very compatible with annotation driven configuration? Additionally, if anyone has any idea how to make the MapperScannerConfigurer work correctly, I would appreciate it greatly!
After some time I was able to figure things out, so I'll answer my own question in case others run into something similar as there wasn't a whole lot of information available out there and it took some searching.
The problem comes down to the fact that MapperScannerConfigurer is a BeanDefinitionRegistryPostProcessor. As it turns out, this is the same mechanism used to process the #Configuration files and register the #Bean annotated methods. Unfortunately, one BeanDefinitionRegistryPostProcessor cannot make use of another, according to this Spring Jira ticket: https://jira.springsource.org/browse/SPR-7868
The suggestion here was to create an XML configuration for the processor and then include an #ImportResource annotation in the Java based configuration to pull it in. Well, that suggestion isn't fully accurate. You can't simply create an XML file with the configuration and pull it into the Java based configuration if you are still planning to have your configuration bootstrapped via an AnnotationConfigContextLoader. Instead, you have to revert back to loading your configuration via XML first and then creating a bean for your configuration file(s) the "old-fashion" way. For me this, was pretty trivial.
New Application Context
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<!--
Because MapperScannerConfigurer is a BeanDefinitionRegistryPostProcessor, it cannot be
configured via #Configuration files with a #Bean annotaiton, because those files are
themselves configured via a BeanDefinitionRegistryPostProcessor which cannot spawn
another one.
-->
<bean id="myBatisMapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.gwtspringpoc.server.model.dao"/>
<property name="annotationClass" value="org.springframework.stereotype.Repository"/>
</bean>
<!--
Load the rest of our configuration via our base configuration class
-->
<bean class="com.example.gwtspringpoc.server.spring.config.ApplicationContextConfig" />
</beans>
I then bootstrap the context container the traditional way, by providing a ContextConfigLocation. This works for me because the ApplicationContextConfig that I reference in the above XML handles everything else - including component scanning which will pick up all of my other #Configuration files.
Once I did this, all of my problems went away. I was able to #Autowire the UserDao as I expected and all was wonderful.
Note:
When I tried manually defining UserDao by creating a MapperFactoryBean, like in my original question's code example, there was a UserDao bean created but it was of type MapperProxy and would not #Autowire. However, I could get it to load by name using #Repository("userDao"), for what that's worth. I believe that the MapperFactoryBean suffers from a similar problem as the MapperScannerConfigurer and is simply not compatible with #Configuration files, alas.
From mybatis.3.2.0 and mybatis-spring.1.2.0,
instead of MapperFactoryBean, you can use MapperScan for this.
#Configuration
#MapperScan("org.mybatis.spring.sample.mapper")
public class AppConfig
{
#Bean
public DataSource dataSource()
{
return new EmbeddedDatabaseBuilder().addScript("schema.sql").build();
}
#Bean
public DataSourceTransactionManager transactionManager()
{
return new DataSourceTransactionManager(dataSource());
}
#Bean
public SqlSessionFactory sqlSessionFactory() throws Exception
{
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
return sessionFactory.getObject();
}
}
Another possible solution can be found in the jira ticked that Jason mentioned. Solved my problem and I did not have to use XML configuration which I try to avoid at any cost...
https://jira.spring.io/browse/SPR-7868
#Configuration
public class A implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
#Override
public void postProcessBeanDefinitionRegistry(...) {
...
}
#Override
public void postProcessBeanFactory(...) {
...
}
#Override
public int getOrder() {
return 0;
}
}
You'll have to have a context:component-scan in your spring configurations to enable auto detection of #Component . Check the reference.

Resources