Showing posts with label HATEOAS. Show all posts
Showing posts with label HATEOAS. Show all posts

Wednesday, May 21, 2014

Reading and writing JAX-RS Link objects

JAX-RS contains a rather nice handy representation of the a Link that can be serialised with and adapter into XML and JSON, unfortunately there is a bug in the JAX-RS spec that means that the standard adapter provided is missing the setters required to deserialise the Link later on.

This isn't a problem if you are using the JAX-B RI as it appears to be more relaxed than the standard; but it will be a problem for other implementations. There is a further bug if you are using MOXy, aka EclipseLink, to produce either JSON or XML that it will fail and just call toString() because it doesn't like the type adapter being an inner class of the class that is being adapted. (Bug TBC)


Direction JAXB RI + JAX-RS Adapter MOXy + JAX-RS Adapter MOXy + Outer Adapter MOXy + Outer Adapter + Setters MOXy + Inner Adapter (Different class)
Marshalling Yes No Yes Yes Yes
Unmarshalling Yes No No Yes No


The workaround is to create a new adapter as a top level class in order to replace the one provided by the standard. Just quickly it would look something like this:

import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.core.Link;

import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.namespace.QName;

public class LinkAdapter
    extends XmlAdapter {

    public LinkAdapter() {
    }

    public Link unmarshal(LinkJaxb p1) {
        
        Link.Builder builder = Link.fromUri(p1.getUri());
        for (Map.Entry<QName, Object> entry : p1.getParams().entrySet()) {
            builder.param(entry.getKey().getLocalPart(), entry.getValue().toString());
        }
        return builder.build();
    }

    public LinkJaxb marshal(Link p1) {
        
        Map<QName, Object> params = new HashMap<>();
        for (Map.Entry<String,String> entry : p1.getParams().entrySet()) {
            params.put(new QName("", entry.getKey()), entry.getValue());
        }
        return new LinkJaxb(p1.getUri(), params);
    }
}

With a simple POJO to go with it.

import java.net.URI;

import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.namespace.QName;

public class LinkJaxb  {

    private URI uri;
    private Map<QName, Object> params;


    public LinkJaxb() {
        this (null, null);
    }

    public LinkJaxb(URI uri) {
        this(uri, null);
    }

    public LinkJaxb(URI uri, Map<QName, Object> map) {
        
        this.uri = uri;
        this.params = map!=null ? map : new HashMap<QName, Object>();
        
    }



    @XmlAttribute(name = "href")
    public URI getUri() { 
        return uri;
    }

    @XmlAnyAttribute
    public Map<QName, Object> getParams() { 
        return params;
    }

    public void setUri(URI uri) {
        this.uri = uri;
    }

    public void setParams(Map<QName, Object> params) {
        this.params = params;
    }

}


With this you can read and write the Link objects to and from XML, and JSON with MOXy, to your hearts content.

Tuesday, May 20, 2014

Declarative Linking in Jersey 2.9 and up

A couple of weeks ago A couple of months ago I was looking how I was going to engineers new REST API for an Oracle Cloud project. Once of the things I had planned to do was to use the declarative link injection created in Jersey 1.x by Marc Hadley. Sadly this hadn't been forwarded ported yet, so a quick chat to the project lead and I took on the small medium sized job of bringing the code up to date.

One of the things that has changed in the new version is that in JAX-RS 2.0 there is a Link object so rather than being able to only inject String and URI you can also inject the correct rel attributes. This has means that the existing annotations coded by Marc have been merged into once simple set of annotations for both Link headers and for injected properties.

This functionality is available now, along with a simple example. The original version of the feature that I committed has some serious limitations that are described later, you will need a version of Jersey post 2.8 or you can build a 2.9-SNAPSHOT image that contains my changes currently to implement the example in this blog.

This blog looks at using this new API to provide simple injection for a collections API. One of the common patterns in RESTful services, in particular those based on JSON, is to have an array of structural links at the top level of the structure. For the purposes of this blog I am going to follow the form of the Collection+JSON hypermedia type.

{ "collection" :
  {
    "version" : "1.0",
    "href" : "http://example.org/friends/?offset=10&limit=10",
    
    "links" : [
      {"rel" : "create", "href" : "http://example.org/friends/"}
      {"rel" : "next", "href" : "http://example.org/friends/?offset=20&limit=10"}
      {"rel" : "previous", "href" : "http://example.org/friends/?offset=0&limit=10"}
    ],
   
    "items" : [
       ...
    ]
  }
}

So I can inject the links in the following form, not there is a bunch of boiler plate missing here for clarity. This is not the tidiest code; but in a later cycle it should be possible to simply them somewhat. The design currently uses EL to access properties - this has the advantage of making it possible to write back values as you can represent properties. I can understand it is disliked by some; but I am not sure if I see any value in moving to JavaScript at the moment. Also don't be put of by the @Xml annotations, I am using MOXy for JSON generation - this isn't an XML only thing.

{


  @XmlTransient
  private int limit, offset; // Getters for these

  @XmlTransient
  private int modelLimit; // Getters for these


  @InjectLink(
            resource = ItemsResource.class,
            method = "query",
            style = Style.ABSOLUTE,
            bindings = {@Binding(name = "offset", value="${instance.offset}"),
                @Binding(name = "limit", value="${instance.limit}")
            },
            rel = "self"
  )
  @XmlElement(name="link")
  private String href;

  @InjectLinks({
    @InjectLink(
          resource = ItemsResource.class,
          style = Style.ABSOLUTE,
          method = "query",
          condition = "${instance.offset + instance.limit < instance.modelLimit}",
          bindings = {
            @Binding(name = "offset", value = "${instance.offset + instance.limit}"),
            @Binding(name = "limit", value = "${instance.limit}")
          },
          rel = "next"
    ),
    @InjectLink(
          resource = ItemsResource.class,
          style = Style.ABSOLUTE,
          method = "query",
          condition = "${instance.offset - instance.limit >= 0}",
          bindings = {
            @Binding(name = "offset", value = "${instance.offset - instance.limit}"),
            @Binding(name = "limit", value = "${instance.limit}")
          },
          rel = "prev"
  )})
  @XmlElement(name="link")
  @XmlElementWrapper(name = "links")
  @XmlJavaTypeAdapter(Link.JaxbAdapter.class)
  List<Link> links;

  ....
}


The original porting of the declarative linking code that exists in version Jersey before 2.8 had very naive code with regards working out what the URI should be for a particular resource, it couldn't deal with any resources that were not at the root of the application, nor would it cope with query parameters which are so important when dealing with collections.

In theory there could be more than one URI for a particular resource class; but this code does need to assume a 1:1 mapping, the current implementation contains a simple algorithm that walks the Jersey meta-model to try to work out the structure, is this doesn't work in your can you can simple provide another implementation of ResourceMappingContext.

Some may question why should I use these ugly annotations when it might be easier just to inject the URI myself? Well the reason is to provide metadata that other tools can use. One of my next jobs is to extend this work to generate the hypermedia extensions and for this I need the above metadata. (Waiting on a pull request being approved before I can really get into it).

Finally it is worth noting that the paging model has its own problems which become apparent if you think of a REST collection as some kind of array that you can safely page over. Concurrent updates along with the lack of state mean that the client can never be sure they have the complete model and should expect to see some items more than once as the model is updated. Cursor or linking based schemes should be considered instead which is yet another good reminder as to why you should always treat the URI as opaque - the sever might need to changes its structure in the future. But that is a entirely different blog for another day.....

Update: See the following blog for some workarounds when reading and writing Link objects.

Monday, October 5, 2009

Proxy client based on Jersey with a bit of HATEOAS built in, version 2

I had some feedback and some time to reflect on my previous blog posting on this topic. So here is a revised version of that post. The basic proxying mechanism is the same; but how we deal with references to resource has been updated to remove any references to URIs. (Thank for the push in that direction Solomon.)

The root BucketsResource class is little changed from before, I had just added "Resource" post fix to make it easier to tell them apart from the bean.

package bucketservice;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("buckets")
public interface BucketsResource {

    @POST
    public BucketResource createNewBucketBound(String input);

    @GET
    @Produces("application/buckets+xml")
    public BucketList getBuckets();
    
    @Path("/{id}")
    public BucketResource getBucket();
}

The BucketResource class is slightly different than before in that we now specify a JAXB mapping class. The implementation of this is not important for the moment; but behind the scenes it converts the resource into a URI. For the purposes of XML (un)marshalling this type is now a URI. (I haven't tested it but this would most likely be the type in the published schema)

package bucketservice;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.core.Response;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import proxy.ResourceAdapter;


@XmlJavaTypeAdapter(BucketResource.Adapter.class)
public interface BucketResource {
     
    public static class Adapter
      extends ResourceAdapter<BucketResource> {
        
    }
    

    @GET 
    public String getBucket();

    @DELETE 
    public Response.Status delete();

}

Finally since we have put the XML "smarts" in the resource interface the BucketList class no longer needs to have any custom code generation.

package bucketservice;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class BucketList 
{
    
    BucketResource list[];

    public void setList(BucketResource[] list) {
        this.list = list;
    }

    public BucketResource[] getList() {
        return list;
    }
}

The client code is the same as before; but instead using the native getList method rather than the method we no longer have to generate. The advantage of working this way is that the two lists don't have to be maintained in sync as we would have done previously.

The problem that is not addressed is how to easily map domain objects into URIs; but Solomon has a reasonable solution to this in his blog. I am not sure though whether this as useful for the client case as your needs are different than when writing the server.

I did some work on converting values into resource objects cleanly by reading the annotations on the supplied resources. This would make it easier for a bean to for example create a "this" resource which would render as a URI. I need to write the code that will take a resource and extract the parameters in order to make this work bi-directionally.

    // Creating new buckets
    //
        
    BucketResource b15 = of(rootResource,BucketResource.class, BucketsResource.class).build(
                   "15");

    ResourceBuilder<BucketResource> bucketBuilder =
        of(rootResource, BucketResource.class, BucketsResource.class);

    BucketResource b7 = bucketBuilder.build(
                   "7");
    BucketResource b8 = bucketBuilder.build(
                   "8");

    // Extract parameters from a given set of resources
    //

    assert "8".equals(bucketBuilder.extract(b8);

I guess you could use the following to generate a self reference; but it is just not as pretty as Solomon's version.


    // Generating a "self reference"

    public class Bean
    {
       @XmlJavaTypeAdapter(BeanResourcePropertyAdapter.class)
       private String id;
    }

    public BeanResourcePropertyAdapter extends XmlAdapter<URI, String>
    {
       // TODO work out whether ??? can be derived from a context

       public URI marshal(String id)
       {
          return = ((ProxiedResource)of(????, BeanResource.class).build(id))
              .getURI();
       }

       public String unmarshal(URI br)
       {
          return of(????, BeanResource.class).extract(br);
       }
    }

A good deal more thinking on this to be done; but enough for today. Time to get some feedback.

Friday, September 18, 2009

java.lang.reflect.Proxy client based on Jersey with a bit of HATEOAS built in

Many people prefer the kind of dynamic fluent API that Jersey provides for calling RESTful services. This doesn't suit every situation though and in some cases it would be nice to have a statically typed interface. RESTEasy provides something along these lines; but I wanted something that worked with Jersey and to take it a bit further to support basic HATEOAS.

So consider the following two interfaces and one bean class that make up the service we are trying to call. Note that there isn't a one to one mapping with the server classes as unlike with SOAP/WSDL you can be a bit flexible. It wouldn't make sense to generate a static client that supports both XML and JSON content types for example where-as the server would support both.

package bucketservice;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;

@Path("buckets")
public interface Buckets {

    @POST
    public Bucket createNewBucketBound(String input);


    @GET
    @Produces("application/buckets+xml")
    public BucketList getBuckets();
    
    
    @Path("/{id}")
    public Bucket getBucket(@PathParam("id") String id);
}

Note there is a method for getting a bucket from an "id" property; but more likely you are going to want to create a resource directly from the URI. This you can do easily as we will see later.

The bucket itself is really simple as it just exposes the get and delete services.

package bucketservice;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;

public interface Bucket {

    @GET 
    public String getBucket();

    @DELETE 
    public Response.Status delete();

}

The bean class is straight forward enough but there is an extra annotation @MappedResource which is used to produce an extra method that is in terms of the resource rather than URIs. Currently this work is done with a Mk1 Human Generator but it wouldn't take too long to implement with with the APT.

package bucketservice;

import javax.xml.bind.annotation.XmlRootElement;

import proxy.MappedResource;


@XmlRootElement
public class BucketList 
{
    
    URI list[];

    public void setList(URI[] list) {
        this.list = list;
    }

    @MappedResource(Bucket.class)
    public URI[] getList() {
        return list;
    }
}

So the key part of the client example below is a static "of" method on ClientProxy that takes as it's input a web resource and the interface you want to use to talk to this resource and return a dynamic proxy based on the interface. This resource location shouldn't include any sub path information included on the interface.

The call to createNewBucketBound(...) results in a HTTP response of "201 Created" with the location of the resource as a URI. The proxy code knows the return type so will return a new proxy for the Bucket interface as determined by the return type of the method. You can then go off and happily invoke methods on this such as get or delete as if it was the real interface.

The rest of the method gets hold of a list of buckets, again these are dynamic proxies based on the interface given; deletes the resource, then show the list again to be sure.

package bucketclient;


import bucketservice.Bucket;
import bucketservice.BucketList;
import bucketservice.Buckets;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;

import static java.lang.System.out;

import java.net.URI;

import static proxy.ClientProxy.of;

import proxy.hateoas.HATEOASClientConfig;
 

public class BucketClient {
    public static void main(String[] args) {

        Client client = Client.create(new HATEOASClientConfig());
        WebResource rootResource = client.resource("http://localhost:7101/RSProxyClient-BucketService-context-root/jersey/");
        
        // Proxy

        Buckets buckets = of(rootResource, Buckets.class);
        out.println("Using proxy " + buckets);
        
        // Create me two buckets, note nothing is returned in the body of
        // the response message, just a location in the header. 
        //
        
        Bucket firstBucketRSP = 
            buckets.createNewBucketBound("First Bucket"); // POST -> 201
        Bucket secondBucketRSP = 
            buckets.createNewBucketBound("Second Bucket"); // POST -> 201
        
        // Get the contents of each
        //

        out.println("<Contents of buckets>");
        out.println(firstBucketRSP + "First # " 
           + firstBucketRSP.getBucket()); // GET .../id -> 200 text/plain
        out.println(secondBucketRSP + "# " 
           + secondBucketRSP.getBucket()); // GET .../id -> 200 text/plain
        out.println("</Contents of buckets>");
        
        // Get the list of buckets, use the injected getListAsResource method
        // to get bound interfaces
        //

        BucketList bucketList 
            = buckets.getBuckets(); // GET .../ -> 200 application/buckets+xml
        out.println("<Bucket List>");
        for (Bucket next : bucketList.getListAsResources()) {
            out.println("   " + next);
        }
        out.println("</Bucket List>");

        // Remove our buckets using the interface we had before
        //
        
        firstBucketRSP.delete(); // DELETE .../id -> 200
        secondBucketRSP.delete(); // DELETE ../id -> 200
        
        // Trace out bucket list again
        
        bucketList 
            = buckets.getBuckets(); // GET .../ -> 200 application/buckets+xml
        out.println("<Bucket List After Delete>");
        if (bucketList.getListAsResources()!=null)
        {
            for (Bucket next : bucketList.getListAsResources()) {
                out.println("   " + next);
            }
        }
        out.println("</Bucket List After Delete>");
        
    }
}

The getListAsResource(..) method as you might have noticed is not part of the BucketList interface and would be generated based on the @MappedResource annotation. How this this would happen I am not entirely sure; but you can start to see the start of a HATEOAS enabled client. Basically you can access the next resource along without any further work. You can imagine a "Transfer" bean that exposed the resources for the "Bank" at each end of the transfer. The client can deal with wiring this all up for you.

So the output of the run looks like this, note that all the Is-A object are dynamic proxies of the resource.

Using proxy Is-A:bucketservice.Buckets@[uri=http://localhost:7101/RSProxyClient-BucketService-context-root/jersey/buckets]
<Contents of buckets>
Is-A:bucketservice.Bucket@[uri=http://localhost:7101/RSProxyClient-BucketService-context-root/jersey/buckets/2]First # First Bucket
Is-A:bucketservice.Bucket@[uri=http://localhost:7101/RSProxyClient-BucketService-context-root/jersey/buckets/3]# Second Bucket
</Contents of buckets>
<Bucket List>
   Is-A:bucketservice.Bucket@[uri=http://localhost:7101/RSProxyClient-BucketService-context-root/jersey/buckets/2]
   Is-A:bucketservice.Bucket@[uri=http://localhost:7101/RSProxyClient-BucketService-context-root/jersey/buckets/3]
</Bucket List>
<Bucket List After Delete>
</Bucket List After Delete>

I hope you can see by example how easy it is to convert a URI into a strongly typed interface.

   URI bucket = ....
   Bucket bucketIF = of(client.resource(bucket), Bucket.class);

Ideally the interfaces would be generated from a sub set of a WADL, you would want to be able to filter by content-type and resource path. Again this kind of focused generation would have been much harder with JAX-WS / WSDL.

The code for this is still on my laptop, except for the code generation, and unfortunately it is not something I can distribute at the moment. This is something I am going to look into if people find this approach interesting.

Friday, May 29, 2009

HATEOAS, REST in the HTTP Analyzer in JDeveloper

I have been working on adding some REST support to JDeveloper back in the labs. In particular I have been focusing on support for HATEOAS in the HTTP Analyzer. I put together a quick viewlet that demonstrates the basic features to get some early feedback.

I cannot say if or when these features will ever see the light of day as per the standard Oracle SOP so please take this into consideration when watching the viewlet.

Update: I noticed that in the demo the create method returns 303, it should proper return "201 Created" to be correct.