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

Reply via email to