Theory In Practice

Creating Resources with HalBuilder

The other day when I posted about the release of the Halbuilder library I stupidly reused big portions of an email I was writing about the library, and included some client usage code using Jetbrain’s new language Kotlin.

Several people (and rightfully so) slapped me for that – so this post is all about how you generate, and consume HAL resources in pure Java.

Creating a basic Resource

The HalBuilder library, as its name suggests takes on a fluent builder approach to its API, but before we get to building we need a ResourceFactory as our entry point.

ResourceFactory rf = new ResourceFactory();

A ResourceFactory contains various defaults for our HAL resources, the only default default being a base URL of http://localhost for all new resources (overridable via a constructor argument).

Now that we have our factory – we’re ready to start building!

Resource r = rf.newResource("/user/talios")
               .withLink("http://twitter.com/talios", "twitter")
               .withProperty("name", "Mark Derricutt");

This gives us a Resource with two links:

  1. http://localhost/user/talios with a rel of self
  2. http://twitter.com/talios with a rel of twitter

and a name property with the value of Mark Derricutt. This can be converted to an XML representation with:

String xml = r.asRenderableResource().renderContent("application/hal+xml");

which yields:

<resource href="http://localhost/user/talios">
  <link rel="twitter" href="http://twitter.com/talios" />
  <name>Mark Derricutt</name>
</resource>

As well as individually adding properties using withProperty, HalBuilder provides additional withBean, withFields, and withSerializble methods to automatically add all “JavaBean” fields via get/set methods, all public fields as properties, or delegate to a Serializable interface.

Example’s of each usage of these can be found in the unit tests over on Github.

Embedded Sub-Resources

Along with links, the HAL format allows for embedding additional resources inside the current resource. This can easily be done using the withSubresource method:

Resource r2 = rf.newResource("/user/illegalargument")
                .withLink("http://twitter.com/illegalargument", "twitter")
                .withProperty("name", "Illegal Argument");

r.withSubresource("podcast", r2);

which generates the following XML:

<resource href="http://localhost/user/talios">
  <link rel="twitter" href="http://twitter.com/talios" />
  <name>Mark Derricutt</name>
  <resource href="http://localhost/user/illegalargument" rel="podcast self">
    <link rel="twitter" href="http://twitter.com/illegalargument" />
    <name>Illegal Argument</name>
  </resource>
</resource>

or the following JSON:

{
  "_links" : {
    "self" : {
      "href" : "http://localhost/user/talios"
    },
    "twitter" : {
      "href" : "http://twitter.com/talios"
    }
  },
  "name" : "Mark Derricutt",
  "_embedded" : {
    "podcast" : {
      "_links" : {
        "podcast self" : {
          "href" : "http://localhost/user/illegalargument"
        },
        "twitter" : {
          "href" : "http://twitter.com/illegalargument"
        }
      },
      "name" : "Illegal Argument"
    }
  }
}

Reading External Resources

Generating resources is one thing, but what about reading HAL resources from external sources? The ResourceFactory#newResource that we used to create the above resources, can also take a Reader, but rather than a Resource we get an immutable ReadableResource given to us (no withXXX methods).

ReadableResource somethingPostedToUs = rf.newResource(
  new InputStreamReader(request.getInputStream()));

In the next post we’ll look at how you can take that ReadableResource and convert it into a static, type safe Java class…

Recent comments

Blog comments powered by Disqus