Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


bowman badge bowman client

Bowman is a Java library for accessing a JSON+HAL REST API.


  • Simplified API consumption via automatic, lazy link traversal on an annotated client-side model

  • Tailor made for Spring Data REST

  • Analogous interface to JPA

  • RESTful CRUD and templated link query support

  • Polymorphic deserialisation

Standing on the shoulders of Spring HATEOAS and Jackson.

Usage Example

Given the following annotated model objects:

public class Person {

  private URI id;
  private String name;

  public Person() {}
  public Person(String name) { = name; }

  @ResourceId public URI getId() { return id; }
  public String getName() { return name; }


public class Greeting {

  private URI id;
  private Person recipient;
  private String message;

  public Greeting() {}
  public Greeting(String message, Person recipient)
    { this.message = message; this.recipient = recipient; }

  @ResourceId public URI getId() { return id; }
  @LinkedResource public Person getRecipient() { return recipient; }
  public String getMessage() { return message; }

Client instances can be constructed and used as demonstrated below.

The HTTP requests/responses corresponding to each instruction are shown in a comment beneath.

ClientFactory factory = Configuration.builder().setBaseUri("http://...").build()

Client<Person> people = factory.create(Person.class);
Client<Greeting> greetings = factory.create(Greeting.class);

URI id = Person("Bob"));
// POST /people {"name": "Bob"}
//  -> Location: http://.../people/1

Person recipient = people.get(id);
// GET /people/1
//  -> {"name": "Bob", "_links": {"self": {"href": "http://.../people/1"}}}

assertThat(recipient.getName(), is("Bob"));

id = Greeting("hello", recipient));
// POST /greetings {"message": "hello", "recipient": "http://.../people/1"}}
//  -> Location: http://.../greetings/1

Greeting greeting = greetings.get(id);
// GET /greetings/1
//  -> {"message": "hello", "_links": {"self": {"href": "http://.../greetings/1"},
// 			"recipient": {"href": "http://.../people/1"}}}

assertThat(greeting.getMessage(), is("hello"));

recipient = greeting.getRecipient();
// GET /people/1
//  -> {"name": "Bob", "_links": {"self": {"href": {"http://.../people/1"}}}

assertThat(recipient.getName(), is("Bob"));