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 e
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> 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
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:
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.