Tuesday, August 24, 2010

RESTeasy JAX-RS embeddable server and SpringBeanProcessor

TJWS (Tiny Java Web Server and Servlet Container) is a very convenient miniature Java Web Server build as a servlet container with HTTPD servlet providing standard Web server functionality.

I have been using TJWS for testing a REST API to be deployed on JBoss application server. The advantage is that JUnit tests can run without the need to deploy a war file on JBoss. Since I have implemented the REST API with RESTEasy, I am using the embedded TJWS server part of the org.jboss.resteasy.plugins.server.tjws.TJWSEmbeddedJaxrsServer package.

The RESTEasy documentation (chapter 23) describes how to use the embedded container.

@Path("/")public class MyResource {

   @GET
   public String get() { return "hello world"; }
 
   public static void main(String[] args) throws Exception 
   {
      TJWSEmbeddedJaxrsServer tjws = new TJWSEmbeddedJaxrsServer();
      tjws.setPort(8081);
      tjws.getRegistry().addPerRequestResource(MyResource.class);
      tjws.start();
   }
}

As you can see, TJWS is very simple to use. You create an instance of the server, setup the port (this is very useful when for example certain ports are already used - I had to set a specific port for our Hudson continuous builds). Then you specify the class to test and you start the server.

In my JUnit tests, I start the server before each tests and stop it after the tests are completed:

private TJWSEmbeddedJaxrsServer server; 

@Before
    public void start() {
      
     server = new TJWSEmbeddedJaxrsServer();
     server.setPort(SERVER_PORT);
     server.getDeployment().getActualResourceClasses().add(MyResource.class);
     server.start();
    }

@After
    public void stop() {
     server.stop();
    }

Since I am using Spring I was interested to leverage the framework for dependency injection in order to configure certain server settings. However the RESTeasy documentation provides only some pseudo-code example:

public static void main(String[] args) throws Exception 
   {
      final TJWSEmbeddedJaxrsServer tjws = new TJWSEmbeddedJaxrsServer();
      tjws.setPort(8081);

      org.resteasy.plugins.server.servlet.SpringBeanProcessor processor = new SpringBeanProcessor(tjws.getRegistry(), tjws.getFactory();
      ConfigurableBeanFactory factory = new XmlBeanFactory(...);
      factory.addBeanPostProcessor(processor);

      tjws.start();
   }

I had to make some modifications to the code provided as follow:

@Before
    public void start() {
      
     server = new TJWSEmbeddedJaxrsServer();
     server.setPort(SERVER_PORT);
     server.getDeployment().getActualResourceClasses().add(MyResource.class);
     server.start();
     
     Resource resource = new FileSystemResource("src/test/resources/resources.xml");
     ConfigurableListableBeanFactory factory = new XmlBeanFactory(resource);
     SpringBeanProcessor processor = new SpringBeanProcessor(
             server.getDeployment().getDispatcher(),
             server.getDeployment().getRegistry(), 
             server.getDeployment().getProviderFactory());
     processor.postProcessBeanFactory(factory);
    }

Alternatively you can define your Spring resource file in a static string directly in your JUnit test class:

Resource resource = new ByteArrayResource(SPRING_BEAN_CONFIG_FILE.getBytes());