If a class is already #Service, then does it need to be #Autowired in Spring Application class? - spring-boot

I'm following a tutorial and they #Service a class which in my mind should make it available to the whole application.
Why are the #Autowire-ing the class in Application?
Application:
#Configuration
#EnableAutoConfiguration // todo why not #SpringBootApplication
#ComponentScan
public class QuoteAppWsApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(QuoteAppWsApplication.class, args);
}
#Autowired
private EventBus eventBus; //
#Autowired // todo This is #Service...why is it be Autowired
private NotificationConsumer notificationConsumer;
NotificationConsumer:
#Service
public class NotificationConsumer implements Consumer<Event<NotificationData>> {
#Autowired
private NotificationService notificationService;
#Override
public void accept(Event<NotificationData> notificationDataEvent) { // .getData() belongs to Event<>
NotificationData notificationData = notificationDataEvent.getData(); //TODO Gets data from Event
try {
notificationService.initiateNotification(notificationData);
} catch (InterruptedException e) {
// ignore
}
}
}

#Service is a specialization of #Component. It is an annotation that tells Spring to include this class as a Bean in the Spring context. You can think of this as telling Spring what to pick up and put into the context during component scanning.
#Autowired is Spring's annotation to inject something from the context. You can think of this as you declaring what you want to get out of Spring. In general, you need to use this annotation on any field, constructor, or setter that you want Spring to invoke to supply you with the object that it's managing for the given type.
To answer your question, yes, you need both to declare what you want put into the context and when you want something out of the context.
Also, your first three annotations can be replaced with #SpringBootApplication. This annotation is a meta-annotation, meaning it's an annotation that it shorthand for including a series of other annotations. It's documented to include, among other things, all three of your annotations.

Related

Mockito mock does not work as expected in Spring MockMvc test

In an Spring mockmvc test I want to replace a bean by a mock implementation which is configured using Mockito.when() definitions. The definitions are indeed respected at the time the mock is configured, as well as at the time the mock is injected into a depending bean (a controller advice in my case) during application context startup. However, when the mock is used during a certain test, all when definitions are gone.
Why?
Some remarks:
The mock is completely new code, so it is impossible that I am not aware of any call to Mockito.reset().
the mock at the time of usage is the same as at the time of creation.
a bypassing solution to the problem is to configure the mock in a #BeforeEach method in AbstractTest. However, I want to understand why it does not work without.
Here a simplified and anonymized example
#Component
public class MyBean {
private String property;
...
public String getProperty() {
return property;
}
}
#ControllerAdvice
public class MyControllerAdvice() {
private MyBean myBean;
#Autowired
public MyControllerAdvice(MyBean myBean) {
this.myBean = myBean;
System.out.println(this.myBean.getProperty()); // --> outputs "FOOBAR"
}
#ModelAttribute
public String getMyBeanProperty() {
return myBean.getProperty(); // --> returns null
}
}
public class AbstractTest {
#Configuration
static class Config {
#Bean
public MyBean () {
MyBean myBean = Mockito.mock(MyBean.class, "I am a mock of MyBean");
when(myBean.getProperty()).thenReturn("FOOBAR");
}
}
}
That's not a problem of Mockito. I think you simplified the example a lot and we don't see the full picture, but I can say that main cause - 2 different beans MyBean: one is initialized with Spring's #Component, second is in configuration class with #Bean.
Why do you use #Component for POJO/DO?
#Bean in the configuration class is being initialized lazy so better way to use #PostConstruct
If you want to leave both beans mark MyBean in the configuration class as #Primary

Autowiring an #Component annotated class from within another #Component annotated class in spring mvc [duplicate]

Note: This is intended to be a canonical answer for a common problem.
I have a Spring #Service class (MileageFeeCalculator) that has an #Autowired field (rateService), but the field is null when I try to use it. The logs show that both the MileageFeeCalculator bean and the MileageRateService bean are being created, but I get a NullPointerException whenever I try to call the mileageCharge method on my service bean. Why isn't Spring autowiring the field?
Controller class:
#Controller
public class MileageFeeController {
#RequestMapping("/mileage/{miles}")
#ResponseBody
public float mileageFee(#PathVariable int miles) {
MileageFeeCalculator calc = new MileageFeeCalculator();
return calc.mileageCharge(miles);
}
}
Service class:
#Service
public class MileageFeeCalculator {
#Autowired
private MileageRateService rateService; // <--- should be autowired, is null
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile()); // <--- throws NPE
}
}
Service bean that should be autowired in MileageFeeCalculator but it isn't:
#Service
public class MileageRateService {
public float ratePerMile() {
return 0.565f;
}
}
When I try to GET /mileage/3, I get this exception:
java.lang.NullPointerException: null
at com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13)
at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14)
...
The field annotated #Autowired is null because Spring doesn't know about the copy of MileageFeeCalculator that you created with new and didn't know to autowire it.
The Spring Inversion of Control (IoC) container has three main logical components: a registry (called the ApplicationContext) of components (beans) that are available to be used by the application, a configurer system that injects objects' dependencies into them by matching up the dependencies with beans in the context, and a dependency solver that can look at a configuration of many different beans and determine how to instantiate and configure them in the necessary order.
The IoC container isn't magic, and it has no way of knowing about Java objects unless you somehow inform it of them. When you call new, the JVM instantiates a copy of the new object and hands it straight to you--it never goes through the configuration process. There are three ways that you can get your beans configured.
I have posted all of this code, using Spring Boot to launch, at this GitHub project; you can look at a full running project for each approach to see everything you need to make it work. Tag with the NullPointerException: nonworking
Inject your beans
The most preferable option is to let Spring autowire all of your beans; this requires the least amount of code and is the most maintainable. To make the autowiring work like you wanted, also autowire the MileageFeeCalculator like this:
#Controller
public class MileageFeeController {
#Autowired
private MileageFeeCalculator calc;
#RequestMapping("/mileage/{miles}")
#ResponseBody
public float mileageFee(#PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
If you need to create a new instance of your service object for different requests, you can still use injection by using the Spring bean scopes.
Tag that works by injecting the #MileageFeeCalculator service object: working-inject-bean
Use #Configurable
If you really need objects created with new to be autowired, you can use the Spring #Configurable annotation along with AspectJ compile-time weaving to inject your objects. This approach inserts code into your object's constructor that alerts Spring that it's being created so that Spring can configure the new instance. This requires a bit of configuration in your build (such as compiling with ajc) and turning on Spring's runtime configuration handlers (#EnableSpringConfigured with the JavaConfig syntax). This approach is used by the Roo Active Record system to allow new instances of your entities to get the necessary persistence information injected.
#Service
#Configurable
public class MileageFeeCalculator {
#Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
Tag that works by using #Configurable on the service object: working-configurable
Manual bean lookup: not recommended
This approach is suitable only for interfacing with legacy code in special situations. It is nearly always preferable to create a singleton adapter class that Spring can autowire and the legacy code can call, but it is possible to directly ask the Spring application context for a bean.
To do this, you need a class to which Spring can give a reference to the ApplicationContext object:
#Component
public class ApplicationContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
}
Then your legacy code can call getContext() and retrieve the beans it needs:
#Controller
public class MileageFeeController {
#RequestMapping("/mileage/{miles}")
#ResponseBody
public float mileageFee(#PathVariable int miles) {
MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
return calc.mileageCharge(miles);
}
}
Tag that works by manually looking up the service object in the Spring context: working-manual-lookup
If you are not coding a web application, make sure your class in which #Autowiring is done is a spring bean. Typically, spring container won't be aware of the class which we might think of as a spring bean. We have to tell the Spring container about our spring classes.
This can be achieved by configuring in appln-contxt or the better way is to annotate class as #Component and please do not create the annotated class using new operator.
Make sure you get it from Appln-context as below.
#Component
public class MyDemo {
#Autowired
private MyService myService;
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("test");
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
System.out.println("ctx>>"+ctx);
Customer c1=null;
MyDemo myDemo=ctx.getBean(MyDemo.class);
System.out.println(myDemo);
myDemo.callService(ctx);
}
public void callService(ApplicationContext ctx) {
// TODO Auto-generated method stub
System.out.println("---callService---");
System.out.println(myService);
myService.callMydao();
}
}
Actually, you should use either JVM managed Objects or Spring-managed Object to invoke methods.
from your above code in your controller class, you are creating a new object to call your service class which has an auto-wired object.
MileageFeeCalculator calc = new MileageFeeCalculator();
so it won't work that way.
The solution makes this MileageFeeCalculator as an auto-wired object in the Controller itself.
Change your Controller class like below.
#Controller
public class MileageFeeController {
#Autowired
MileageFeeCalculator calc;
#RequestMapping("/mileage/{miles}")
#ResponseBody
public float mileageFee(#PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
I once encountered the same issue when I was not quite used to the life in the IoC world. The #Autowired field of one of my beans is null at runtime.
The root cause is, instead of using the auto-created bean maintained by the Spring IoC container (whose #Autowired field is indeed properly injected), I am newing my own instance of that bean type and using it. Of course this one's #Autowired field is null because Spring has no chance to inject it.
Your problem is new (object creation in java style)
MileageFeeCalculator calc = new MileageFeeCalculator();
With annotation #Service, #Component, #Configuration beans are created in the
application context of Spring when server is started. But when we create objects
using new operator the object is not registered in application context which is already created. For Example Employee.java class i have used.
Check this out:
public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String name = "tenant";
System.out.println("Bean factory post processor is initialized");
beanFactory.registerScope("employee", new Employee());
Assert.state(beanFactory instanceof BeanDefinitionRegistry,
"BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used.");
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
if (name.equals(definition.getScope())) {
BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true);
registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
}
}
}
}
I'm new to Spring, but I discovered this working solution. Please tell me if it's a deprecable way.
I make Spring inject applicationContext in this bean:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
#Component
public class SpringUtils {
public static ApplicationContext ctx;
/**
* Make Spring inject the application context
* and save it on a static variable,
* so that it can be accessed from any point in the application.
*/
#Autowired
private void setApplicationContext(ApplicationContext applicationContext) {
ctx = applicationContext;
}
}
You can put this code also in the main application class if you want.
Other classes can use it like this:
MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);
In this way any bean can be obtained by any object in the application (also intantiated with new) and in a static way.
It seems to be rare case but here is what happened to me:
We used #Inject instead of #Autowired which is javaee standard supported by Spring. Every places it worked fine and the beans injected correctly, instead of one place. The bean injection seems the same
#Inject
Calculator myCalculator
At last we found that the error was that we (actually, the Eclipse auto complete feature) imported com.opensymphony.xwork2.Inject instead of javax.inject.Inject !
So to summarize, make sure that your annotations (#Autowired, #Inject, #Service ,... ) have correct packages!
What hasn't been mentioned here is described in this article in the paragraph "Order of execution".
After "learning" that I had to annotate a class with #Component or the derivatives #Service or #Repository (I guess there are more), to autowire other components inside them, it struck me that these other components still were null inside the constructor of the parent component.
Using #PostConstruct solves that:
#SpringBootApplication
public class Application {
#Autowired MyComponent comp;
}
and:
#Component
public class MyComponent {
#Autowired ComponentDAO dao;
public MyComponent() {
// dao is null here
}
#PostConstruct
public void init() {
// dao is initialized here
}
}
One of the below will work :
The class where you are using #Autowired is not a Bean (You may have used new() somewhere I am sure).
Inside the SpringConfig class you have not mentioned the packages the Spring should look for #Component ( I am talking about #ComponentScan(basePackages"here") )
If above two don't work .... start putting System.out.println() and figure out where it is going wrong.
If this is happening in a test class, make sure you haven't forgotten to annotate the class.
For example, in Spring Boot:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyTests {
....
Some time elapses...
Spring Boot continues to evolve. It is no longer required to use #RunWith if you use the correct version of JUnit.
For #SpringBootTest to work stand alone, you need to use #Test from JUnit5 instead of JUnit4.
//import org.junit.Test; // JUnit4
import org.junit.jupiter.api.Test; // JUnit5
#SpringBootTest
public class MyTests {
....
If you get this configuration wrong your tests will compile, but #Autowired and #Value fields (for example) will be null. Since Spring Boot operates by magic, you may have few avenues for directly debugging this failure.
In simple words there are mainly two reasons for an #Autowired field to be null
YOUR CLASS IS NOT A SPRING BEAN.
The class in which you define the #Autowire anotation is not a spring bean. Thus spring will not auto wire the members.
THE FIELD IS NOT A BEAN.
There is no bean with the type or type in hierarchy you specified in the #Autowired field is not yet present in the spring application context or registry
Another solution would be to put a call of
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
to MileageFeeCalculator constructor like this:
#Service
public class MileageFeeCalculator {
#Autowired
private MileageRateService rateService; // <--- will be autowired when constructor is called
public MileageFeeCalculator() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
}
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
I think you have missed to instruct spring to scan classes with annotation.
You can use #ComponentScan("packageToScan") on the configuration class of your spring application to instruct spring to scan.
#Service, #Component etc annotations add meta description.
Spring only injects instances of those classes which are either created as bean or marked with annotation.
Classes marked with annotation need to be identified by spring before injecting, #ComponentScan instruct spring look for the classes marked with annotation. When Spring finds #Autowired it searches for the related bean, and injects the required instance.
Adding annotation only, does not fix or facilitate the dependency injection, Spring needs to know where to look for.
This is the culprit of giving NullPointerException MileageFeeCalculator calc = new MileageFeeCalculator(); We are using Spring - don't need to create object manually. Object creation will be taken care of by IoC container.
UPDATE: Really smart people were quick to point on this answer, which explains the weirdness, described below
ORIGINAL ANSWER:
I don't know if it helps anyone, but I was stuck with the same problem even while doing things seemingly right. In my Main method, I have a code like this:
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {
"common.xml",
"token.xml",
"pep-config.xml" });
TokenInitializer ti = context.getBean(TokenInitializer.class);
and in a token.xml file I've had a line
<context:component-scan base-package="package.path"/>
I noticed that the package.path does no longer exist, so I've just dropped the line for good.
And after that, NPE started coming in. In a pep-config.xml I had just 2 beans:
<bean id="someAbac" class="com.pep.SomeAbac" init-method="init"/>
<bean id="settings" class="com.pep.Settings"/>
and SomeAbac class has a property declared as
#Autowired private Settings settings;
for some unknown reason, settings is null in init(), when <context:component-scan/> element is not present at all, but when it's present and has some bs as a basePackage, everything works well. This line now looks like this:
<context:component-scan base-package="some.shit"/>
and it works. May be someone can provide an explanation, but for me it's enough right now )
Also note that if, for whatever reason, you make a method in a #Service as final, the autowired beans you will access from it will always be null.
You can also fix this issue using #Service annotation on service class and passing the required bean classA as a parameter to the other beans classB constructor and annotate the constructor of classB with #Autowired. Sample snippet here :
#Service
public class ClassB {
private ClassA classA;
#Autowired
public ClassB(ClassA classA) {
this.classA = classA;
}
public void useClassAObjectHere(){
classA.callMethodOnObjectA();
}
}
This is only valid in case of Unit test.
My Service class had an annotation of service and it was #autowired another component class. When I tested the component class was coming null. Because for service class I was creating the object using new
If you are writing unit test make sure you are not creating object using new object(). Use instead injectMock.
This fixed my issue. Here is a useful link
Not entirely related to the question, but if the field injection is null, the constructor based injection will still work fine.
private OrderingClient orderingClient;
private Sales2Client sales2Client;
private Settings2Client settings2Client;
#Autowired
public BrinkWebTool(OrderingClient orderingClient, Sales2Client sales2Client, Settings2Client settings2Client) {
this.orderingClient = orderingClient;
this.sales2Client = sales2Client;
this.settings2Client = settings2Client;
}
In addition, don't inject to a static member, it will be null.
if you are using a private method, it will be null, try to change private to public in controller.

getting #autowired intance null when try trying to do operation on it,throwing null pointer exception

I am trying to save data on gemfire using crud repository. I have created one operation class to call save method of repository but at autowired instance I am getting null pointer exception. Below is my code:
public interface GeodeRepository extends CrudRepository<KeyValueBean, String> {
#Override
public KeyValueBean findOne(String name);
#Override
public <S extends KeyValueBean> Iterable<S> save(Iterable<S> entities);
}
#EnableGemfireRepositories(basePackageClasses = GeodeRepository.class)
#EnableAutoConfiguration
#Configuration
public class Operations {
#Autowired
private GeodeRepository repository;
public void saveKeyValueData(KeyValueBean keyValueBean) {
System.out.println("Repository is : " + repository);
repository.save(Arrays.asList(keyValueBean)); // <--- i am getting
// repository as null so
// getting null pointer
// exception
}
}
When we #Autowired any class make sure, you have declared that class as a #Component.
for example:
#Component
public class Operations {
#Autowired
private GeodeRepository repository;
public void saveKeyValueData(KeyValueBean keyValueBean) {
System.out.println("Repository is : " + repository);
repository.save(Arrays.asList(keyValueBean));
}
}
and try using #Autowired to Operation class to your class
in which class your are calling your saveKeyValueData() method.
So, what is not apparent from your example is how you "bootstrap" your application and it's features (e.g. Repositories) into action.
It is not simply enough to add the Spring #Configuration, Spring Boot's #EnableAutoConfiguration and SD GemFire's #EnableGemfireRepositories annotations and expect everything to be auto-configured and wired up successfully. I.e. you need a bootstrapping mechanism, like Spring Boot, especially if you are using the #EnableAutoConfiguration annotation.
For example...
import org.springframework.boot.SpringApplication;
...
class MyApplication {
public static void main(String[] args) {
SpringApplication.run(Operations.class, args);
}
}
Now, you could remove the #EnableAutoConfiguration from your Operations class and add the #SpringBootApplication to the MyApplication class, like so...
#SpringBootApplication
class MyApplication {
...
}
#SpringBootAppliation combines together Spring's #Configuration with Spring Boot's #EnableAutoConfiguration, along with many other useful meta-annotations, like Spring's #ComponentScan, enabling all sorts of magic to happen.
But, if you are not using Spring Boot, you can always bootstrap you application with the AnnotationConfigApplicationContext, like so..
class MyApplication
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(Operations.class);
applicationContext.registerShutdownHook();
}
}
This is essentially what the Spring Boot, SpringApplication class does for you anyway.
If you are developing a Web application, then of course you can specify the type of ApplicationContext created since you are using Java config, for instance. See here for more details.
Hope this helps!
Cheers,
John

Java 8 and Spring 4 : Use autowiring in interface

Java 8 added a new feature by which we can provide method implementation in interfaces.
Is there any way in Spring 4 by which we can inject beans in the interface which can be used inside the method body?
Below is the sample code
public interface TestWiring{
#Autowired
public Service service;// this is not possible as it would be static.
//Is there any way I can inject any service bean which can be used inside testWiringMethod.
default void testWiringMethod(){
// Call method of service
service.testService();
}
}
This is a bit tricky but it works if you need the dependency inside the interface for whatever requirement.
The idea would be to declare a method that will force the implemented class to provide that dependency you want to autowire.
The bad side of this approach is that if you want to provide too many dependencies the code won't be pretty since you will need one getter for each dependency.
public interface TestWiring {
public Service getService();
default void testWiringMethod(){
getService().testService();
}
}
public class TestClass implements TestWiring {
#Autowire private Service service;
#Override
public Service getService() {
return service;
}
}
You can created Class utils of application context and use it everywhere even not bean class .
you can have code somethins this :
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext context) {
ApplicationContextUtil.applicationContext = context;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
and add this to your spring configuration
<bean class="com.example.ApplicationContextUtil" id="applicationContextUtil"/>
now simple to use when you need :
ApplicationContextUtil.getApplicationContext().getBean(SampleBean.class)
this word in web and simple spring app.

How to Initialize Jersey Application (ResourceConfig) With Spring?

I'm using Jersey 2 and Spring, and I'm trying to initialize my Jersey application (i.e. the class derived from ResourceConfig) with parameters from the Spring context.
Background: I have a single Jersey application that I build (i.e. a single WAR) and I deploy it across a server cluster with different Spring configurations on different servers to enable or disable different parts of the server, e.g. some of the servers have /search resources turned on, etc. This was really easy in Jersey 1.0: I just put,
<context:component-scan base-package="com.mycompany.resources.search"/>
in a Spring config to have Jersey scan that particular package and enable the JAX-RS resource providers in it.
Now in Jersey 2.0 the Spring <context:component-scan ... /> doesn't work, so resources have to be programmatically registered in a startup class derived from ResourceConfig:
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("com.mycompany.resources.search");
}
}
So far so good, but I need to conditionally scan that package, and I can't figure out how to get any Spring configuration into the MyApplication class. I thought that constructor injection might work:
public class MyApplication extends ResourceConfig {
#Autowired
public MyApplication(#Qualifier("my-config") MyConfiguration myConfiguration) {
if (myConfiguration.isEnabled()) {
packages("com.mycompany.resources.search");
}
}
}
However HK2 complains that it can't find a default constructor to use... so this indicates to me that DI is in play in the construction of this class, but that the DI isn't using Spring.
Similarly, using the the Spring bean lifecycle doesn't work:
public class MyApplication extends ResourceConfig implements InitializingBean {
#Autowired
private MyConfiguration myConfiguration;
public MyApplication() {
}
#Override
public void afterPropertiesSet() throws Exception {
if (myConfiguration.isEnabled()) {
packages("com.mycompany.resources.search");
}
}
}
(The afterPropertiesSet method isn't called.)
So now I'm stuck: is there any way to configure a Jersey ResourceConfig application object using Spring?
UPDATE:
I accepted #JohnR's answer below but I'll also include my eventual solution which I think is a bit cleaner. #JohnR's answer was to have the object initialized twice: first by Spring and then by Jersey/HK2. When Spring initializes the object you cache the dependencies in a static member, and then when Jersey/HK2 initializes it later you can retrieve the dependencies.
I ended up doing this:
public class MyApplication extends ResourceConfig {
public MyApplication() {
ApplicationContext rootCtx = ContextLoader.getCurrentWebApplicationContext();
MyConfiguration myConfiguration = rootCtx.getBean(MyConfiguration.class);
if (myConfiguration.isEnabled()) {
packages("com.mycompany.resources.whatever");
}
}
}
Rather than having the object initialized twice, we let Jersey/HK2 initialize it but then we retrieve the dependencies from Spring.
Both solutions are vulnerable to timing: they both assume that Spring is initialized before Jersey/HK2.
Expanding on my previous comment:
Trying to extend ResourceConfig is dangerous if you don't know what you're doing. Jersey becomes unpredictable, and if you try to subclass it into an Abstract class, Jersey crashes.
Instead, the JAX-RS specification provides us with a very useful interface called Feature: It allows you to register any classes you want as if you were configuring your own application. Furthermore, you don't need to use the awkward AbstractBinder, you just specify what contracts you register your classes with.
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
// Don't use #Component here, we need to inject the Spring context manually.
public class MySpringFeature implements Feature {
#Context
private ServletContext servletContext;
private ApplicationContext applicationContext;
#Autowired
private MySecurityDAO mySecurityDAO;
#Autowired
private MySpringResponseFilter myResponseFilter;
#Override
public boolean configure(FeatureContext context) {
if(this.servletContext == null) {
return false; // ERROR!
}
this.applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
if(this.applicationContext == null) {
return false; // ERROR!
}
// This is where the magic happens!
AutowireCapableBeanFactory bf = applicationContext.getAutowireCapableBeanFactory();
bf.autowireBean(this);
// From here you can get all the beans you need
// Now we take a Spring bean instance,
// and register it with its appropriate JAX-RS contract
context.register(myResponseFilter, ContainerResponseFilter.class);
// Or, we could do this instead:
SomeSecurityFilter mySecurityFilter = new SomeSecurityFilter();
mySecurityFilter.setSecurityDAO(mySecurityDAO);
context.register(mySegurityFilter, ContainerRequestFilter.class);
// Or even this:
SomeOtherSpringBean someOtherBean = applicationContext.getBean(SomeOtherSpringBean.class);
context.register(someOtherBean, SomeOtherJerseyContract.class);
// Success!
return true;
}
}
And in your ResourceConfig:
public class MyApplication extends ResourceConfig() {
public MyApplication() {
register(MySpringFeature.class);
}
}
Ta-da!
So now I'm stuck: is there any way to configure a Jersey
ResourceConfig application object using Spring?
I don't think you can configure Jersey to obtain your ResourceConfig from Spring as a Spring managed bean. It's a bit hackish, but you could do something like this. Note that you'll end up with two instance of your ResourceConfig: one managed by Spring and another by Jersey:
public class MyApplication extends ResourceConfig {
// static, available to all instances
private static MyConfiguration myConfiguration;
public MyApplication() {
// when Spring creates the first instance of MyApplication, myConfiguration
// will be null because the setter wasn't called yet
if (myConfiguration != null)
{
// second instance created by jersey... Spring will have autowired
// the first instance, and myConfiguration is static
if (myConfiguration.isEnabled())
packages("com.mycompany.resources.search");
}
}
#Autowired
public void setMyConfiguration(MyConfiguration config)
{
// instance level setter saves to a static variable to make it available for
// future instances (i.e. the one created by jersey)
MyApplication.myConfiguration = config;
}
}
Again, this is fairly hackish. You'll want to make sure Spring is initialized before Jersey and look closely at any threading issues that could occur during initialization.

Resources