Hi,
Working with JAX-RS, I'm seeing the need to be able to inject
dependencies (typically Spring-managed beans) in the resource classes.
I've done a bit of research on this topic, and found out the following:
* this need has come up before in JAX-RS circles (see the mailing lists
& blogs)
* there's no official JAX-RS solution yet, as for the generic case
there are some issues to resolve, for example both JAX-RS and Spring can
do constructor based injection.
* Jersey allows to provide a "ComponentProvider" responsible for
getting the instantiated bean [1]. Based on this, they have a branch [2]
where they're working on further Spring integration. Based on the
insights gained there, maybe the JAX-RS spec will evolve to a more
IoC-friendly model.
The Restlet JAX-RS extension has no support yet for plugging in custom
ways of instantiating the resource classes. Since I really wanted such a
feature, I've gone ahead and added it.
You can find it in the attached patch.
This doesn't include anything Spring-specific, but based on this
interface, one can use Spring's AutowireCapableBeanFactory.createBean()
method to let Spring instantiate the resource classes and inject
dependencies into them (as indicated with the @Autowire annotation).
Other approaches are also possible.
I'm looking forward to any comments on this, I hope it's possible to
include this feature or something similar in Restlet.
[1]
https://jersey.dev.java.net/source/browse/jersey/trunk/jersey/src/spi/com/sun/ws/rest/spi/service/ComponentProvider.java?rev=879&view=markup
[2]
https://jersey.dev.java.net/source/browse/jersey/branches/spring-integration/
--
Bruno Dumon http://outerthought.org/
Outerthought http://www.daisycms.org/
[EMAIL PROTECTED] http://www.kauriproject.org/
Index: modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/JaxRsRouter.java
===================================================================
--- modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/JaxRsRouter.java (revision 3061)
+++ modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/JaxRsRouter.java (working copy)
@@ -172,6 +172,8 @@
@SuppressWarnings("unchecked")
private final ThreadLocalizedContext tlContext = new ThreadLocalizedContext();
+ private ComponentProvider componentProvider;
+
/**
* Creates a new JaxRsRouter with the given Context. Only the default
* providers are loaded. If a resource class later wants to check if a user
@@ -337,7 +339,7 @@
Provider<?> provider;
try {
provider = new Provider<Object>(jaxRsProviderClass, tlContext,
- this.entityProviders, contextResolvers);
+ this.entityProviders, contextResolvers, componentProvider);
} catch (InstantiateException e) {
String msg = "Ignore provider " + jaxRsProviderClass.getName()
+ "Could not instantiate the Provider, class "
@@ -514,7 +516,7 @@
ResourceObject o;
try {
o = rrc.createInstance(tlContext, entityProviders,
- contextResolvers, getLogger());
+ contextResolvers, componentProvider, getLogger());
} catch (WebApplicationException e) {
throw e;
} catch (NoMessageBodyReaderException e) {
@@ -1132,4 +1134,12 @@
uris.add(rrc.getPathRegExp().getPathPattern());
return Collections.unmodifiableCollection(uris);
}
+
+ public ComponentProvider getComponentProvider() {
+ return componentProvider;
+ }
+
+ public void setComponentProvider(ComponentProvider componentProvider) {
+ this.componentProvider = componentProvider;
+ }
}
\ No newline at end of file
Index: modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/internal/wrappers/RootResourceClass.java
===================================================================
--- modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/internal/wrappers/RootResourceClass.java (revision 3061)
+++ modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/internal/wrappers/RootResourceClass.java (working copy)
@@ -44,6 +44,7 @@
import org.restlet.ext.jaxrs.internal.util.PathRegExp;
import org.restlet.ext.jaxrs.internal.util.Util;
import org.restlet.ext.jaxrs.internal.wrappers.provider.EntityProviders;
+import org.restlet.ext.jaxrs.ComponentProvider;
/**
* Instances represents a root resource class, see chapter 3 of JAX-RS
@@ -133,6 +134,8 @@
* [EMAIL PROTECTED] org.restlet.ext.jaxrs.JaxRsRouter}.
* @param allResolvers
* all available [EMAIL PROTECTED] ContextResolver}s.
+ * @param componentProvider
+ * object responsible for instantiating the resource class. Optional, thus can be null.
* @param logger
* The logger to use
* @return
@@ -149,21 +152,23 @@
*/
public ResourceObject createInstance(ThreadLocalizedContext tlContext,
EntityProviders entityProviders,
- Collection<ContextResolver<?>> allResolvers, Logger logger)
+ Collection<ContextResolver<?>> allResolvers, ComponentProvider componentProvider, Logger logger)
throws MissingAnnotationException, InstantiateException,
NoMessageBodyReaderException, InvocationTargetException,
ConvertRepresentationException, ConvertHeaderParamException,
ConvertPathParamException, ConvertMatrixParamException,
ConvertQueryParamException, ConvertCookieParamException {
- Constructor<?> constructor = this.constructor;
- Object instance;
- try {
- instance = WrapperUtil.createInstance(constructor, false,
- constructorLeaveEncoded, tlContext, entityProviders,
- allResolvers, logger);
- } catch (IllegalAnnotationException iae) {
- // should not be possible here
- throw new InstantiateException(iae);
+ Object instance = componentProvider != null ? componentProvider.getInstance(jaxRsClass) : null;
+ if (instance == null) {
+ Constructor<?> constructor = this.constructor;
+ try {
+ instance = WrapperUtil.createInstance(constructor, false,
+ constructorLeaveEncoded, tlContext, entityProviders,
+ allResolvers, logger);
+ } catch (IllegalAnnotationException iae) {
+ // should not be possible here
+ throw new InstantiateException(iae);
+ }
}
ResourceObject rootResourceObject = new ResourceObject(instance, this);
try {
Index: modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/internal/wrappers/provider/Provider.java
===================================================================
--- modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/internal/wrappers/provider/Provider.java (revision 3061)
+++ modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/internal/wrappers/provider/Provider.java (working copy)
@@ -55,6 +55,7 @@
import org.restlet.ext.jaxrs.internal.util.Util;
import org.restlet.ext.jaxrs.internal.wrappers.ContextInjector;
import org.restlet.ext.jaxrs.internal.wrappers.WrapperUtil;
+import org.restlet.ext.jaxrs.ComponentProvider;
/**
* Wraps a JAX-RS provider, see chapter 4 of JAX-RS specification.
@@ -105,6 +106,8 @@
* all entity providers.
* @param allResolvers
* all available [EMAIL PROTECTED] ContextResolver}s.
+ * @param componentProvider
+ * object responsible for instantiating the provider. Optional, thus can be null.
* @throws IllegalArgumentException
* if the class is not a valid provider, may not be
* instantiated or what ever.
@@ -121,7 +124,7 @@
@SuppressWarnings("unchecked")
public Provider(Class<?> jaxRsProviderClass,
ThreadLocalizedContext tlContext, EntityProviders mbWorkers,
- Collection<ContextResolver<?>> allResolvers)
+ Collection<ContextResolver<?>> allResolvers, ComponentProvider componentProvider)
throws IllegalArgumentException, InvocationTargetException,
MissingConstructorException, InstantiateException,
IllegalAnnotationException {
@@ -129,10 +132,13 @@
throw new IllegalArgumentException(
"The JAX-RS provider class must not be null");
Util.checkClassConcrete(jaxRsProviderClass, "provider");
- Constructor<?> providerConstructor = WrapperUtil.findJaxRsConstructor(
- jaxRsProviderClass, "provider");
- this.jaxRsProvider = createInstance(providerConstructor,
- jaxRsProviderClass, tlContext, mbWorkers, allResolvers);
+ Object instance = componentProvider != null ? componentProvider.getInstance(jaxRsProviderClass) : null;
+ if (instance == null) {
+ Constructor<?> providerConstructor = WrapperUtil.findJaxRsConstructor(
+ jaxRsProviderClass, "provider");
+ this.jaxRsProvider = createInstance(providerConstructor,
+ jaxRsProviderClass, tlContext, mbWorkers, allResolvers);
+ }
boolean isProvider = false;
if (jaxRsProvider instanceof javax.ws.rs.ext.MessageBodyWriter) {
this.writer = (javax.ws.rs.ext.MessageBodyWriter<T>) jaxRsProvider;
Index: modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/ComponentProvider.java
===================================================================
--- modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/ComponentProvider.java (revision 0)
+++ modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/ComponentProvider.java (revision 0)
@@ -0,0 +1,16 @@
+package org.restlet.ext.jaxrs;
+
+import org.restlet.ext.jaxrs.internal.exceptions.InstantiateException;
+
+/**
+ * Implement this interface to instantiate JAX-RS resource and provider classes
+ * yourself.
+ *
+ * <p>A ComponentProvider can be registered via [EMAIL PROTECTED] JaxRsRouter#setComponentProvider}.
+ *
+ * <p>When using a ComponentProvider, no JAX-RS constructor dependency injection will be
+ * performed, but instance variable injection will still be done.
+ */
+public interface ComponentProvider {
+ <T> T getInstance(Class<T> clazz) throws InstantiateException;
+}
Property changes on: modules/org.restlet.ext.jaxrs_0.9/src/org/restlet/ext/jaxrs/ComponentProvider.java
___________________________________________________________________
Name: svn:eol-style
+ native