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:
http://localhost/user/talioswith a rel ofselfhttp://twitter.com/talioswith a rel oftwitter
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…