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());

3 comments:

Anonymous said...

I started to play around with the 2.2.2.GA release and wasn’t be able to use the Embedded Container. I also try it with the version 2.2.1 and 2.0.0.GA and I still have the same Exception.

The resource class looks like this

@Path(“/personliste”)
public class RestEasyPersonResouce {

@GET
@Path(“/hello/{name:.*}”)
public String sayHello(@PathParam(“name”) String name){
return “Hello ” + name;
}
}

The starter class looks like this


public class RestEasyStarter {

private TJWSEmbeddedJaxrsServer server;

public static void main( String[] args ) throws Exception
{
RestEasyStarter starter = new RestEasyStarter(“/resteasy”, 9005, RestEasyPersonResouce.class);
starter.startServer();
}
/**
* @param rootResourcePath
* @param port
* @param classes
*/
public RestEasyStarter(String rootResourcePath, int port, Class … classes) {
server = new TJWSEmbeddedJaxrsServer();
server.setPort(port);
server.setRootResourcePath(rootResourcePath);
server.getDeployment().getActualResourceClasses().addAll(Arrays.asList(classes));
}

public void startServer(){
server.start();
}

}


When i start the RestEasyStarter-class i get this Exception

Exception in thread “main” java.lang.NoSuchMethodError: org.jboss.resteasy.plugins.server.tjws.TJWSServletServer$FileMappingServe.runInBackground()V
at org.jboss.resteasy.plugins.server.tjws.TJWSServletServer.start(TJWSServletServer.java:152)
at org.jboss.resteasy.plugins.server.tjws.TJWSEmbeddedJaxrsServer.start(TJWSEmbeddedJaxrsServer.java:44)
at de.gilles.projects.resteasy.service.RestEasyStarter.startServer(RestEasyStarter.java:29)
at de.gilles.projects.resteasy.service.RestEasyStarter.main(RestEasyStarter.java:18)

May be i am missing something. I really need help to make it run. I couldn’t be able to start a discussion on Jboss Community, threrefore i make it in this blog

Anonymous said...

I started to play around with the 2.2.2.GA release and wasn’t be able to use the Embedded Container. I also try it with the version 2.2.1 and 2.0.0.GA and I still have the same Exception.

The resource class looks like this

@Path(“/personliste”)
public class RestEasyPersonResouce {

@GET
@Path(“/hello/{name:.*}”)
public String sayHello(@PathParam(“name”) String name){
return “Hello ” + name;
}
}

The starter class looks like this

public class RestEasyStarter {

private TJWSEmbeddedJaxrsServer server;

public static void main( String[] args ) throws Exception
{
RestEasyStarter starter = new RestEasyStarter(“/resteasy”, 9005, RestEasyPersonResouce.class);
starter.startServer();
}
/**
* @param rootResourcePath
* @param port
* @param classes
*/
public RestEasyStarter(String rootResourcePath, int port, Class … classes) {
server = new TJWSEmbeddedJaxrsServer();
server.setPort(port);
server.setRootResourcePath(rootResourcePath);
server.getDeployment().getActualResourceClasses().addAll(Arrays.asList(classes));
}

public void startServer(){
server.start();
}

}

When i start the RestEasyStarter-class i get this Exception

Exception in thread “main” java.lang.NoSuchMethodError: org.jboss.resteasy.plugins.server.tjws.TJWSServletServer$FileMappingServe.runInBackground()V
at org.jboss.resteasy.plugins.server.tjws.TJWSServletServer.start(TJWSServletServer.java:152)
at org.jboss.resteasy.plugins.server.tjws.TJWSEmbeddedJaxrsServer.start(TJWSEmbeddedJaxrsServer.java:44)
at de.gilles.projects.resteasy.service.RestEasyStarter.startServer(RestEasyStarter.java:29)
at de.gilles.projects.resteasy.service.RestEasyStarter.main(RestEasyStarter.java:18)

May be i am missing something. I really need help to make it run. I couldn’t be able to start a discussion on Jboss Community, threrefore i make it in the blog

Unknown said...

Hi
I'm a web developer, know some MVC frameworks, and some servers like Jboss, Weblogic but new to Jetty and JAX-RS. I finished the book RESTful Java with JAX-RS from Bill Burke. The book is not difficult to understand. But by the end, Bill Burke using Jetty to deploy it into the application and having a JUnit test will be called from Maven. Following the instruction, I run Maven and see the BUIL SUCCESSFUL, exactly as book said. But what is Jetty and how can I see it in term of URI like : http://localhost:9095/customers

I have some questions:
- if embedded, jetty must running somewhere in my machine after run maven?
- If it run somewhere then I can see it using http://? right?
Thanks a lot