How to load Spring applicationContext into Jersey Application - spring

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

Related

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("");
}
}

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.

No unique bean of type is defined: expected single bean but found 0:

I have one spring based standalone project (PTSJMSProxy). I refer http://sahits.ch/blog/?p=2326
In the PTSJMSProxy I have followings.
1) SimpleWriterService.java
package com.test;
import org.springframework.stereotype.Service;
#Service
public class SimpleWriterService {
public void sayHello() {
System.out.println("Hello Spring DI service!");
}
}
2) ComponentConsumer.java
package com.test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class ComponentConsumer {
#Autowired
private SimpleWriterService service;
public void consume() {
service.sayHello();
}
}
3) ProxyJMSClient.java
package com.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ProxyJMSClient {
// I commented some portions,but working fine
// Example #Autowired and also in the constructure
// #Autowired
private ComponentConsumer consumer;
public ProxyJMSClient() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
// AutowireCapableBeanFactory acbFactory =
// context.getAutowireCapableBeanFactory();
// acbFactory.autowireBean(this);
consumer = context.getBean(ComponentConsumer.class);
}
public void callMyJMSClient() {
this.consumer.consume();
}
}
4) Test.java
package com.test;
public class Test {
public static void main(String[] args) {
(new ProxyJMSClient()).callMyJMSClient();
}
}
5) applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
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.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<tx:annotation-driven />
<context:annotation-config />
<context:component-scan base-package="com.test" />
</beans>
Now when I invoke Test.java from eclipse Run As -Java Application I get the expected out put.
Output - Hello Spring DI service!
=============================================================================
Now I created the Jar with Eclipse export as Jar. Jar Name -PTSJMSProxy.jar
===============================================================================
My objective is to use this jar from a non spring java project
===============================================================================
I created another java project in eclipse "TestProxy"
In that project I add all the required Spring Jar and PTSJMSProxy.jar
Created TestJMSProxy.java class
package com.proxy.test;
import com.wiley.fts.ProxyJMSClient;
public class TestJMSProxy {
public static void main(String[] args) {
(new ProxyJMSClient()).callMyJMSClient();
}
}
When I run - I get following exceptions
log4j:WARN No appenders could be found for logger (org.springframework.context.support.ClassPathXmlApplicationContext).
log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.test.ComponentConsumer] is defined: expected single bean but found 0:
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:269)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1083)
at com.wiley.fts.ProxyJMSClient.<init>(ProxyJMSClient.java:19)
at com.proxy.test.TestJMSProxyJar.main(TestJMSProxyJar.java:8)
How can I resolve this
NOTE: -
PTSJMSProxy is a spring based project - which has its own applicationContext.xml (Refer point no -5)
TestProxy is a NON Spring Java project - where I use PTSJMSProxy Jar
PTSJMSProxy Jar folder structure
PTSJMSProxy jar contains com,META-INF and applicationContext.xml under same level
The problem is resolved.
This is due to the loading problem of spring configuration xml file.
Code
String fileUrl = PTSJMSProxyClient.class.getClassLoader()
.getResource(SPRING_JMS_CFG_FILE).toString();
LOG.info("Spring jmsContext.xml file path :" +fileUrl);
xmlApplicationContext = new ClassPathXmlApplicationContext(fileUrl);
AutowireCapableBeanFactory acbFactory = xmlApplicationContext
.getAutowireCapableBeanFactory();
acbFactory.autowireBean(this);
client = xmlApplicationContext.getBean(MessageSenderImpl.class);
Sometime it also happens when you define basePackages wrongly inside #ComponentScan annotation like:
#ComponentScan("com.whodesire.model", "com.whodesire.util")
here the above one will considered as single package, if there are multiple packages to scan within your project, then you must mention packages like String[]
#ComponentScan( { "com.whodesire.model" , "com.whodesire.util" } )

Load annotated spring bean from Jar

If the spring bean used annotation in jar file, how can I load mythe bean instance in my class?
In jar file
package org.java.service.test;
#Service(value = "MyService")
public class MyService {
#Resource(name = "myproperties")
private Properties properties;
}
In my project
package org.java.project.test;
#Service(value = "OtherService")
public class OtherService {
#Resource(name = "MyService")
private MyService myService;
}
In spring-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" ....>
<context:annotation-config/>
<context:component-scan base-package=org.java.service.test, org.java.project.test"/>
.....
</beans>
I also try as below, it does not work
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" ....>
<context:annotation-config/>
<context:component-scan base-package="org.java.service.test"/>
<context:component-scan base-package="org.java.project.test"/>
.....
</beans>
I think the problem is not in your component-scan configuration.
Rather than using #Resource annotation on your field private MyService myService; you shoudl use #Autowired annotation.
So now your code in class OtherService will be like below:
package org.java.project.test;
#Service(value = "OtherService")
public class OtherService {
#Autowired
private MyService myService;
}
According to me that should work for you. Just try it. Cheers.
<context:component-scan>
scans those packages which are in the current project.

unable to use Spring Advice(#Before) using annotations

I am new to springs and trying to run a simple java application with java advices....
xml file...
<?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:aop="http://www.springframework.org/schema/aop"
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/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<aop:aspectj-autoproxy>
<aop:include name="com.cts.two.Advices"/>
</aop:aspectj-autoproxy>
<context:annotation-config/>
<context:component-scan base-package="com.cts.two"></context:component-scan>
</beans>
Advice Class
package com.cts.two;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class Advices implements Adv{
#Pointcut("execution(* com.cts.two.*.*(..))")
public void advice(){
}
#Before("advice()")
public void before(JoinPoint name) throws Throwable{
System.out.println("inside advices");
/*System.out.println(name.getClass() + " this is get class");
System.out.println(name.getSignature().getName() + " this is the get signatue and get name");*/
}
}
class on which advice needs to be applied...I want the before method of Advice class to be executed before below mentioned test() method
package com.cts.two;
import org.springframework.stereotype.Component;
#Component
public class ClassA {
private ClassB b= new ClassB();
public void setB(ClassB b) {
this.b = b;
}
public void test(){
System.out.println("inside classA test");
//b.test();
}
}
caller of methods/test class/main class
package com.cts.two;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class CallerAB {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context = new ClassPathXmlApplicationContext(
"AllAnnotations.xml");
ClassA calledA = (ClassA) context.getBean("classA");
calledA.test();
}
}
the problem is that when I run the code directly the test method of class A is executed but the advice is not...
Kindly advice..
Am i missing something ???
AspectJ 1.6.12 jar is also added...
Aspects should be decalred as beans.
#Aspect doesn't do it automatically, <aop:include> doesn't do it as well (it sets additional restriction on beans that can be used as aspects).
So, you need
#Aspect
#Component
public class Advices implements Adv { ... }
and don't need <aop:include>.
As mentioned in the answer from #axtavt you need to add the #Component annotation. But you also need to remove the <aop:include>. Your spring wiring xml should just be:
<aop:aspectj-autoproxy/>
<context:annotation-config/>
<context:component-scan base-package="com.cts.two"/>
As stated in the spring AOP documentation, the name attribute in the <aop:include> element is supposed to be a bean name, not a class name. Specifying a bean explicitly overrides Spring's auto-detection and specifying it incorrectly means that there is no aspect used at all.

Resources