Skip to content
yunglin edited this page Sep 14, 2010 · 8 revisions

Introduction

tapestry-jersey is inspired by Tynamo’s tapestry-resteasy and provides the Jersey integration to Tapestry5. With tapestry-jersey, you can expose tapestry managed services as jax-rs services.

Installation

I. add dependency to your pom.xml

 <dependency>
  <groupId>com.bluetangstudio</groupId>
  <artifactId>tapestry-jersey</artifactId>
  <version>1.0.3-SNAPSHOT</version>
 </dependency>

II. configure the base path for your restful services. (optional)

By default, tapestry-jersey will forward requests prefixed with ‘/rest’ to Jersey ServletContainer. If you would like to change this, you can add the following lines to your AppModule class.

public static void contributeApplicationDefaults(MappedConfiguration<String, String> configuration) {
    configuration.add(JerseySymbols.REQUEST_PATH_PREFIX, "/rest");
 }

III. code your first tapestry-jersey service.

package com.bluetangstudio.shared.jersey.test.services.rest;
  import javax.ws.rs.GET;
  import javax.ws.rs.Path;
  @Path("/rest/helloworld")
  public interface HelloWorld {
      @GET
      public String getHello();
  }
package com.bluetangstudio.shared.jersey.test.services.rest;
public class HelloWorldImpl implements HelloWorld {
    public String getHello() {
        return "hello";
    }
}

IV. expose tapestry managed services to Jersey.

To expose HelloWorldImpl to jersey, you have to define the service scope for it in Tapestry first. Here, I use default scope(singleton) for the HelloWorld service. You can use PerThread scope but this will make Tapestry to create a new instance of HelloWorldImpl for each new request.

Next, you have to expose your services to Jersey by contributing your service instances to JerseyRootResources. If your service is a singleton service, configuration.add(objectLocator.getService(HelloWorld.class)); will add your singleton service to Jersey.

If the service is a PerThread service, objectLocator.getService(HelloWorld.class) will return your service instance wrapped in a PerThreadManager proxy. This proxied instance will create a thread local HelloWorldImpl instance for each new request.

AppModule.java
    public static void bind(ServiceBinder binder) {
        binder.bind(HelloWorld.class, HelloWorldImpl.class);
    }
    public static void contributeJerseyRootResources(Configuration<Object> configuration,
          ObjectLocator objectLocator) {
        configuration.add(objectLocator.getService(HelloWorld.class));
    }

Useful Tips

The default json serializer generate a single element node if an array element only contains one sub-element.
for example

int[] collections = new int[] {1}  => {collections: 1}
int[] collections = new int[] {1,2} => {collections: [1,2]}

This cause lots of trouble when parsing json outputs. Jersey would like to change its default json serialization implementation but it can’t due to backward compatibility. To fix this issue by yourself, please add jackson libraries to your dependencies and contribute JacksonJsonProvider to JerseyRootResources

   <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-json</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-core-asl</artifactId>
            <version>1.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-jaxrs</artifactId>
            <version>1.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-xc</artifactId>
            <version>1.5.5</version>
        </dependency>
        <dependency>
            <groupId>com.bluetangstudio</groupId>
            <artifactId>tapestry-jersey</artifactId>
            <version>1.0.3-SNAPSHOT</version>
        </dependency>
   
    public static JacksonJsonProvider buildJacksonJsonProvider() {
        ObjectMapper mapper = new ObjectMapper();
        AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
        // make deserializer use JAXB annotations (only)
        mapper.getDeserializationConfig().setAnnotationIntrospector(introspector);
        // make serializer use JAXB annotations (only)
        mapper.getSerializationConfig().setAnnotationIntrospector(introspector);
        return new JacksonJsonProvider(mapper);
    }
   public static void contributeJerseyRootResources(Configuration<Object> configuration, 
            JacksonJsonProvider jsonProvider) {
        configuration.add(jsonProvider);
    }

END.