Spring Cloud FeignClient decoding application/hal+json Resource<Object> return type

2.5k views Asked by At

I'm developing a REST API using Spring Cloud, Spring Data JPA, Spring Data Rest and Spring Boot. The server implementation generates the various data items correctly, according to the HAL spec and so forth. It generates the HAL+JSON as follows:

{
  "lastModifiedBy" : "unknown",
  "lastModifiedOn" : "2015-06-04T12:19:45.249688",
  "id" : 2,
  "name" : "Item 2",
  "description" : null,
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/pltm/accounts/2"
    },
    "customers" : {
      "href" : "http://localhost:8080/pltm/accounts/2/customers"
    },
    "users" : {
      "href" : "http://localhost:8080/pltm/accounts/2/users"
    },
    "groups" : {
      "href" : "http://localhost:8080/pltm/accounts/2/groups"
    }
  }
}

Now I'm trying to implement the client implementation, using the FeignClient Spring Cloud library. I've defined my client interface as follows.

@FeignClient("serviceId")
@RequestMapping(value = "/api", consumes = MediaType.APPLICATION_JSON_VALUE)
public interface PltmClient
{
  // Account Requests
  @RequestMapping(method = RequestMethod.GET, value = "/accounts")
  PagedResources<Resource<Account>> getAccounts();

  @RequestMapping(method = RequestMethod.GET, value = "/accounts/{id}")
  Resource<Account> getAccountAsResource(@PathVariable("id") Long id);

  @RequestMapping(method = RequestMethod.GET, value = "/accounts/{id}")
  Account getAccount(@PathVariable("id") Long id);
}

When I call the getAccout() method, I get back my domain object Account with the details from the JSON document. That object is a simple POJO. All of the fields are filled in properly.

public class Account
{
   private Long id;
   private String name;
   private String description;

   /** Setters/Getters left out for brevity **/
 }

But when I call the getAccountAsResource(), it works and I get back a Resource object that has the data. However, the call to Resource.getContent() returns an Account object that is not completely filled out. In this case, the Account.getId() is NULL, which is causing problems.

Any ideas why this is happening? One idea I had is that the Resource class defines a getId() method, and that is somehow confusing the Jackson ObjectMapper.

The larger question is if this whole method is viable or is there a better way? Obviously, I could just use the plain POJO as my return type, but that looses the HAL information on the client side.

Has anyone successfully implemented a Java-based client implementation for Spring Data REST server endpoints?

1

There are 1 answers

3
spencergibb On BEST ANSWER

Account not having an id is a feature of spring-data-rest. You need to enable populating of the id on the server side.

I also add a different method to return the id (in Account)

@JsonProperty("accountId")
public String getId() {
    return id;
}

Enable id

@Configuration
public class MyConfig extends RepositoryRestMvcConfiguration {

    @Override
    protected void configureRepositoryRestConfiguration( RepositoryRestConfiguration config) {
        config.exposeIdsFor(Account.class);
    }
}

I have used it here: https://github.com/spencergibb/myfeed, though I believe where I use resources, I'm using RestTemplate.