Wednesday, January 28, 2015

Consume Spring Data REST HATEOAS HAL with RestTemplate

When you get Spring Data REST HATEOAS HAL in a web browser,

you will get the following result:

{
  "_links" : {
    "self" : {
      "href" : "http://localhost:18080/api/customers?page=0&size=100{&sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:18080/api/customers/search"
    }
  },
  "_embedded" : {
    "customers" : [ {
      "firstName" : "Jack",
      "lastName" : "Bauer",
      "_links" : {
        "self" : {
          "href" : "http://localhost:18080/api/customers/1"
        }
      }
    }, {
      "firstName" : "Chloe",
      "lastName" : "O'Brian",
      "_links" : {
        "self" : {
          "href" : "http://localhost:18080/api/customers/2"
        }
      }
    }, {
      "firstName" : "Kim",
      "lastName" : "Bauer",
      "_links" : {
        "self" : {
          "href" : "http://localhost:18080/api/customers/3"
        }
      }
    }, {
      "firstName" : "David",
      "lastName" : "Palmer",
      "_links" : {
        "self" : {
          "href" : "http://localhost:18080/api/customers/4"
        }
      }
    }, {
      "firstName" : "Michelle",
      "lastName" : "Dessler",
      "_links" : {
        "self" : {
          "href" : "http://localhost:18080/api/customers/5"
        }
      }
    } ]
  },
  "page" : {
    "size" : 100,
    "totalElements" : 5,
    "totalPages" : 1,
    "number" : 0
  }
}

but when you get it with RestTemplate,

you will get the following result:

{
  "links" : [ {
    "rel" : "self",
    "href" : "http://localhost:18080/api/customers?page=0&size=100{&sort}"
  }, {
    "rel" : "search",
    "href" : "http://localhost:18080/api/customers/search"
  }, {
    "rel" : "customer",
    "href" : "http://localhost:18080/api/customers/1"
  }, {
    "rel" : "customer",
    "href" : "http://localhost:18080/api/customers/2"
  }, {
    "rel" : "customer",
    "href" : "http://localhost:18080/api/customers/3"
  }, {
    "rel" : "customer",
    "href" : "http://localhost:18080/api/customers/4"
  }, {
    "rel" : "customer",
    "href" : "http://localhost:18080/api/customers/5"
  } ],
  "content" : [ ],
  "page" : {
    "size" : 100,
    "totalElements" : 5,
    "totalPages" : 1,
    "number" : 0
  }
}

Surprisingly the "content" is empty.

This is due to Accept header.

A web browser uses the following Accept header:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

but RestTemplate uses the following Accept header:

Accept: text/plain, application/json, application/*+json, */*

So the content type in a web browser will be as follows:

Content-Type:application/hal+json;charset=UTF-8

but the content type in RestTemplate will be as follows:

Content-Type: application/x-spring-data-compact+json;charset=UTF-8

You can consume it correctly with RestTemplate as follows:

@Test
public void test() {
RestTemplate restTemplate = restTemplate();

String url = "http://localhost:{port}/api/customers?page={page}&size={size}";

ResponseEntity<PagedResources<Customer>> responseEntity = restTemplate.exchange(
url, HttpMethod.GET, null,
new ParameterizedTypeReference<PagedResources<Customer>>() {},
port, 0, 100);
PagedResources<Customer> resources = responseEntity.getBody();
List<Customer> customers = new ArrayList(resources.getContent());
System.out.println(customers);
System.out.println(customers.get(0).getClass());
}

private RestTemplate restTemplate() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.registerModule(new Jackson2HalModule());

MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
converter.setObjectMapper(mapper);
return new RestTemplate(Arrays.asList(converter));
}

Reference:
http://stackoverflow.com/questions/23239052/why-does-resttemplate-not-bind-response-representation-to-pagedresources

11 comments:

  1. Finally! Some code that works! Been searching days for this.

    I would love to see how it can support Customer[] so I don't have to have that ugly exchange call.

    ReplyDelete
  2. Thanks very much! I too was looking for this for a while!

    ReplyDelete
  3. Nice and good article. It is very useful for me to learn and understand easily. Thanks for sharing your valuable information and time. Please keep updatingmulesoft online training

    ReplyDelete
  4. I am so proud of you and your efforts and work make me realize that anything can be
    done with patience and sincerity. Well I am here to say that your work has inspired me without a doubt. Here is i want to share
    about mulesoft training online with Free Bundle videos .

    ReplyDelete
  5. Charm Windows offers a large group of answers for upvc windows manufacturers gurugram which incorporate - Commotion dropping windows, Robber safe windows, sun based control windows, Security glass windows and modified benefit windows. Anything that the plan you have at the top of the priority list, anything that your practical need, Joy Windows has a superior exhibition answer for you.

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Go India Tour and Cabs leads in providing Taxi service in Jaipur that offers the most luxurious and reasonably priced taxi trips in world-class vehicles. We offer cab in Jaipur travel, outstation trips, weddings, corporate events, airport services, and sightseeing in Jaipur.

    ReplyDelete