Search |
||
Integrating Jersey and SpringPosted by mhadley on September 14, 2007 at 9:18 AM PDT
To further test the new resource provider SPI I described earlier I thought I'd try building a new resource provider that defers to Spring for resource creation. Note that I've never used Spring before so if there are better ways to accomplish what I did please let me know. I also ran into a problem that limited the integration more than I'd prefer (details at the end of this post). The Jersey dev list would be a great place to post any suggestions on how to improve the integration. ImplementationThe first task was to write a public Object getInstance(ResourceProviderContext context) {
try {
initSpringContext(context);
initBeanName();
Object resource = springContext.getBean(beanName, resourceClass);
context.injectDependencies(resource);
return resource;
} catch (Exception ex) {
throw new ContainerException("Unable to create resource", ex);
}
}
The protected static synchronized void initSpringContext(
ResourceProviderContext context) {
if (springContext==null) {
DummyResource r = new DummyResource();
context.injectDependencies(r);
springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(
r.servletConfig.getServletContext());
}
}
public static class DummyResource {
@Resource
public ServletConfig servletConfig;
}
Jersey is based on annotated classes whereas Spring is based on named beans. The Spring protected synchronized void initBeanName() {
if (beanName==null) {
String names[] = springContext.getBeanNamesForType(resourceClass);
if (names.length==0)
throw new RuntimeException("No configured bean for "+resourceClass.getName());
else if (names.length>1)
throw new RuntimeException("Multiple configured beans for "+resourceClass.getName());
beanName=names[0];
}
}
I couldn't see any straightforward way to determine which bean to use for a given resource class if there is more than one defined at the top level so the provider requires a single top-level bean for each resource class. The final task was to define a new annotation that instructs the Jersey runtime to use the Spring resource provider: @Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ResourceFactory(SpringProvider.class)
public @interface SpringFactory {}
ExampleWith the above implemented you can now write a resource class whose instantiation is controlled by Spring: @UriTemplate("{id}")
@SpringFactory
public class SpringResource {
private String name;
public SpringResource() {
name="unset";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@HttpMethod("GET")
@ProduceMime("text/plain")
public String getDescription() {
return "Name: "+getName();
}
}
With the following <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.0.xsd">
<bean id="bean1" scope="prototype" class="com.sun.ws.rest.spring.resources.SpringResource">
<property name="name" value="Mr. Bean"/>
</bean>
</beans>
The complete code is available here. No libraries are included in the ZIP file so you'll have to patch up the references to the required Jersey and Spring libraries. Integration ShortcomingI couldn't see any way to add support for Jersey-defined resources as constructor parameters. In an earlier post I described the new support for non-empty constructors. When using the Spring resource provider, the constructor can only include resources defined within the Spring configuration, not values supplied by Jersey. Is there a Spring API I could use to programatically add support for Jersey-defined constructor parameters ? »
Related Topics >>
Web Services and XML Comments
Comments are listed in date ascending order (oldest first)
|
||
|
|