Skip to content

How to bind custom Hateoas link class to RestTemplate? #794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
VelDeveloper opened this issue Jan 30, 2019 · 2 comments
Closed

How to bind custom Hateoas link class to RestTemplate? #794

VelDeveloper opened this issue Jan 30, 2019 · 2 comments
Labels
in: client-side Only affects client-side in: documentation Reference documentation resolution: works as designed

Comments

@VelDeveloper
Copy link

I have a common library for a spring rest API of one my application.API exposes rest call with custom HATEOAS link.

ex)

[
  {
    "bookUid": "5c4ec057e21b840001968d31",
    "status": "PURCHASED_PENDING",
    "BookInfo": {
      ....
    },
    "_links": {
      "self": {
        "href": "http://localhost:9992/api/v1/books/5c4ec057e21b840001968d31",
        "accepts": "application/json"
      },
      "update-book": [
        {
          "href": "http://localhost:9992/api/v1/books/5c4ec057e21b840001968d31",
          "name": "ACTIVATE",
          "accepts": "application/json",
          "method": "PATCH"
        },
        {
          "href": "http://localhost:9992/api/v1/books/5c4ec057e21b840001968d31",
          "name": "CANCEL",
          "accepts": "application/json",
          "method": "PATCH"
        }
      ]
    }
  }
]

Please find the below custom link class,

public class SuperLink extends Link {

    @XmlAttribute
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String name;

    @XmlAttribute
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String accepts;

    @XmlAttribute
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String method;

    public SuperLink(Link link) {
        super(link.getHref(), link.getRel());
    }

    public SuperLink(Link link, String accepts) {
        super(link.getHref(), link.getRel());
        this.accepts = accepts;
    }

    public SuperLink(Link link, String accepts, String name, String method) {
        super(link.getHref(), link.getRel());
        this.accepts = accepts;
        this.name = name;
        this.method = method;
    }

    public String getAccepts() {
        return accepts;
    }

    public void setAccepts(String accepts) {
        this.accepts = accepts;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }
}

Client class:

public List<Resource<BookResponse>> getMyBooks(GetMyBookRequest request) throws IOException {
try {
          return List<Resource<BookResponse>> bookResponses = restOperations.exchange(builder.toUriString(), HttpMethod.GET, entity, new ParameterizedTypeReference<List<Resource<BookResponse>>>(){})
                  .getBody();
      } catch (ResourceAccessException e) {
          throw new IOException(e);
      }
}

Client sdk output:

[
  {
    "bookUid": "5c4ec057e21b840001968d31",
    "status": "PURCHASED_PENDING",
    "BookInfo": {
      ....
    },
    "_links": {
      "self": {
        "href": "http://localhost:9992/api/v1/books/5c4ec057e21b840001968d31",
      },
      "update-book": [
        {
          "href": "http://localhost:9992/api/v1/books/5c4ec057e21b840001968d31",
        },
        {
          "href": "http://localhost:9992/api/v1/books/5c4ec057e21b840001968d31",
        }
      ]
    }
  }
]

Question: How to link custom link class to RestTemplate or Jackson object Mapper? So that it will bind all the Hateoas link attribute.

Any help would be really appreciated.

@gregturn
Copy link
Contributor

gregturn commented Feb 7, 2019

In a nutshell, you can write any Jackson serializer/deserializer you want. And then you can register it with RestTemplate. (See this for a clue on how).

And RestTemplate will then delegate all calls to your Jackson module. The format you've shown isn't HAL, because according to section 5, accepts isn't a valid attribute for a link.

Simply put, you have a unique media type that Spring HATEOAS doesn't presently support. Pending completion of #728, I am working on an endeavor to make it easier to register your own custom media types. As for a custom Link type that has attributes not defined by either HAL or RFC 5988, you'll have to sort that out in your custom Jackson module.

@gregturn
Copy link
Contributor

gregturn commented Jul 31, 2020

To register your RestTemplate with hypermedia support check out our recent addition to client-side support.

Assuming you have applied this setting, you can then do a RestTemplate call to a hypermedia powered server (doesn't have to be Spring HATEOAS) using Spring HATEOAS's TypeReferences convenience classes:

ResponseEntity<EntityModel<User>> response = template.exchange("/resource", HttpMethod.GET, null, 
            new EntityModelType<User>() {}); // <--- use TypeReferences here to decode a response into Spring HATEOAS's type

There are also helpers CollectionModelType and PagedModelType, which support CollectionModel and PagedModel respectively.

@gregturn gregturn added in: client-side Only affects client-side in: documentation Reference documentation resolution: works as designed and removed unlikely labels Jul 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: client-side Only affects client-side in: documentation Reference documentation resolution: works as designed
Projects
None yet
Development

No branches or pull requests

2 participants