Search code examples
springdependenciesinversion-of-controlcode-injectionrestlet

Injecting dependencies to Restlet ServerResource using Spring IoC


I'm building a REST service with Spring / Hibernate / Restlet / Jetty and I'm struggling with what I thought to be a simple task:

I need to inject DAO implementation (i.e. UserDao) to a ServerResource (in this case UserServerResource).

I'm using SpringRouter bean to establish routing to this resource in Spring XML configuration:

<bean name="restlet-user-server-resource"
      class="project.server.rest.UserServerResource" 
      scope="prototype" />

<bean name="restlet-api-server-application"
      class="org.restlet.Application">
        <property name="inboundRoot">
        <bean class="org.restlet.ext.spring.SpringRouter">
            <constructor-arg ref="restlet-api-server-application" />
            <property name="attachments">
            <map>
                <entry key="/user/{userId}"
                       value-ref="restlet-user-server-resource" />
            </map>
            </property>
        </bean>
    </property>
</bean>

And I've tried to inject the DAO both as @Autowired and as bean property (in "restlet-user-server-resource" bean p:userDao-ref="user-dao").

UserDao is specified as:

<bean name="user-dao,userDao"
      parent="dao-tx-template">

    <property name="target">
        <bean class="project.server.data.dao.UserDao"
              p:sessionFactory-ref="session-factory" />
    </property>
</bean>

Should be noted, that getBean('user-dao') works as expected and returns fully prepared instance of UserDao.

I've tried following:

  1. When restlet-user-server-resource bean is required directly using getBean from Spring context, internal userDao is null.
  2. When Restlet instantiates the UserServerResource class directly (so, string instead of ref is provided for SpringRouter), internal userDao is null.
  3. When Spring instantiates bean as stated above, internal userDao is null.

Also, in both (1) and (3), error is issued by Restlet: Unknown object found in the mappings. Only instances of Restlet and subclasses of org.restlet.resource.Resource and ServerResource are allowed.

Adding the current UserServerResource implementation (which is nothing, just a mock for infrastructure setup):

package project.server.rest;

import org.restlet.resource.ResourceException;
import org.restlet.resource.ServerResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;

import project.server.data.dao.UserDao;
import project.server.data.entities.User;
import project.server.rest.interfaces.UserResource;

@Configurable
public class UserServerResource 
extends ServerResource 
implements UserResource 
{
    private int userId;

    @Autowired
    private UserDao userDao;

    @Override
    public void doInit() throws ResourceException
    {
        String userIdString = (String)this.getRequestAttributes().get("userId");
        this.userId = Integer.parseInt(userIdString);
    }

    @Override
    public User represent() 
    {
        System.out.println(this.userDao);

        User user = new User();
        user.setId(this.userId);
        user.setUserName("Something");
        user.setEmailAddress("some@address.com");
        return (user);
    }

    public void setUserDao(UserDao dao)
    {
        this.userDao = dao;
    }

    public UserDao getUserDao()
    {
        return (this.userDao);
    }
}

I hope I've provided as much info as possible. Thank you for any advice!


Solution

  • Ok, I've made some desperate Google Searches and found a Restlet's Spring extension manual page once again, but now, not missing important point, which at the end solved my struggle. Here is the solution:

    <bean name="restlet-user-server-resource"
          class="project.server.rest.UserServerResource" 
          scope="prototype" 
          p:userDao-ref="user-dao" />
    
    <bean name="restlet-api-server-application"
          class="org.restlet.Application">
            <property name="inboundRoot">
            <bean class="org.restlet.ext.spring.SpringRouter">
                <constructor-arg ref="restlet-api-server-application" />
                <property name="attachments">
                <map>
                    <entry key="/user/{userId}">
                        <bean class="org.restlet.ext.spring.SpringFinder">
                            <lookup-method name="create" bean="restlet-user-server-resource" />
                        </bean>
                    </entry>
                </map>
                </property>
            </bean>
        </property>
    </bean>
    

    Important bit is the SpringFinder bean with create method used to lookup and instantiate the Spring bean instead of direct reference.