spring-hateoas
spring-hateoas copied to clipboard
Returns duplicate links causing JSON deserialization exception
Vanilla resource User -
public class User implements Serializable {
private static final long serialVersionUID = 262950482349139355L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "FIRST_NAME", nullable = false, unique = false)
@Convert(converter = NameConverter.class)
private String firstName;
@Column(name = "LAST_NAME", nullable = false, unique = false)
@Convert(converter = NameConverter.class)
private String lastName;
@Column(name = "PHONE_NUM", nullable = false, unique = false)
@Convert(converter = PhoneNumberConverter.class)
private String phoneNum;
@Column(name = "EMAIL", nullable = true, unique = false)
@Convert(converter = OptionalStringConverter.class)
private Optional<String> email;
}
Search result with hostname changed in the URL - 2 _links present
{
"_links" : {
"self" : {
"href" : "http://hostname/users/search/findByLastName?lastName=doe{&page,size,sort}",
"templated" : true
}
},
"_embedded" : {
"users" : [ {
"firstName" : "John",
"lastName" : "Doe",
"phoneNum" : "111-111-1111",
"email" : null,
"_links" : { },
"_embedded" : { },
"_links" : {
"self" : {
"href" : "http://hostname/users/1",
"templated" : false
}
}
} ]
},
"page" : {
"size" : 20,
"totalElements" : 1,
"totalPages" : 1,
"number" : 0
}
}
The duplicate links are not present when the resource is accessed on it's own. However, when a client (a microservice in my case) makes a request using a RestTemplate, the response comes back with 2 _links as shown above.
@Override
public Collection<Long> getUserIdsByFirstName(String firstName) {
String findByFirstNameUri = UriComponentsBuilder.fromUriString(userServiceUrl).path("/users/search/findByFirstName").queryParam("firstName", firstName).toUriString();
// This is where ResponseEntity.body would have the 2 _links, if ResponseEntity<String> were used. I used a custom object to weed that out.
ResponseEntity<UserSearchResult> userSearchResult = restTemplate.exchange(findByFirstNameUri, GET, dummyEntity, UserSearchResult.class);
...
}
I'm using Spring Data JPA, Spring Data Rest, Spring HATEOAS and Spring Cloud. Here's a link to the project on my Github.
I encountered this multiple links issue today. It was a slightly different scenario but I managed to fix it by letting my resource extend ResourceSupport.
It's recommended for any Spring MVC/WebFlux controller to return one of HATEOAS's "types", ie a subclass of RepresentationModel in order for it to properly render hypermedia.
I just faced the same problem with 3.2.0.
The following base class generates two $.links property.
@JsonInclude(JsonInclude.Include.NON_NULL)
@Setter
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
//@SuperBuilder
@SuppressWarnings({
"java:S101", // class __Base...
"java:S119" // <SELF ...>
})
public abstract class __BaseType<SELF extends __BaseType<SELF>>
extends RepresentationModel<SELF>
implements Serializable {
/**
* Returns all {@link Link}s contained in this resource.
*
* @return all {@link Link}s contained in this resource.
* @apiNote Overridden to be annotated with {@link Schema.AccessMode#READ_ONLY} and
* {@link JsonProperty.Access#READ_ONLY}.
*/
@Schema(accessMode = Schema.AccessMode.READ_ONLY)
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@Override
public Links getLinks() {
return super.getLinks();
}
}
{
"links" : [ ],
...
"links" : {
"self" : {
"href" : "http://localhost:56923/api/stores/..."
},
"store" : {
"href" : "http://localhost:56923/api/stores/..."
}
}
}