Open eefalomac opened 4 years ago
That's not unexpected as a plain ObjectMapper
instance not aware of any media type specific serializers/deserializers will not produce proper output.
It also happens (as in my real case) if the ObjectMapper instance went through a configuration with
Jackson2HalModule module = new Jackson2HalModule();
objectMapper.registerModule(module);
objectMapper.setHandlerInstantiator(new Jackson2HalModule.HalHandlerInstantiator(new AnnotationLinkRelationProvider(), CurieProvider.NONE, MessageResolver.DEFAULTS_ONLY));
In any case: what should the poor object mapper do if it finds the @JsonIgnore
at the affordances
member?
You still seem to be lacking the registration of the Jackson2HalModule
.
The code snippet for the the object mapper is part of the spring boot configuration within
@Configuration
public class JacksonHalConfiguration extends AbstractJackson2HttpMessageConverter {
public JacksonHalConfiguration(ObjectMapper objectMapper) {
super(objectMapper, MediaTypes.HAL_JSON);
Jackson2HalModule module = new Jackson2HalModule();
objectMapper.registerModule(module);
objectMapper.setHandlerInstantiator(
new Jackson2HalModule.HalHandlerInstantiator(new AnnotationLinkRelationProvider(), CurieProvider.NONE,
MessageResolver.DEFAULTS_ONLY));
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
}
@Override
protected boolean supports(Class<?> clazz) {
return RepresentationModel.class.isAssignableFrom(clazz);
}
}
If I use the object mapper instance from Spring configured with our JacksonHalConfiguration
via autowiring in the test example given above (change the new ObjectMapper
with an autowired instance and use a real data object) I obtain as serialized string {"_links":{"self":{"href":"/v2/predefinedLists/countries"}},...
.
The created link observed in the debugger, however, has one (implicitely generated) affordance, which is lost after deserialization.
If you see that something is wrong in our configuration please give me a hint how to change it. If not, I'm still wondering about private @JsonIgnore List<Affordance> affordances;
It doesn't make sense to expect affordances to be deserialized as they're not serialized (hence the @JsonIgnore
) in the first place. For one this is due to HAL not exposing any kinds of affordances besides the links in the first place. But even for HAL Forms, the affordances model are used to produce the hypermedia format, not to consume them. Affordances are mostly driven by server side abstractions (like controller methods) that must not matter to clients in the first place. That's why that information must not be made available to clients.
Maybe we can take a step back and you describe what you're actually trying to achieve on an API exchange level. Seems we're too deep into discussing implementation details.
Okay, if affordances
shouldn't be serialized I want to point to the other side of my problem: the equals
method of Link
(in version 1.0.5 it seems to be Lombok @EqualsAndHashCode, in 1.1.1 explicitly implemented). It includes the affordances
in the comparison, and we are back to my original problem/question: how to compare objects with links after a serialization-deserialization cycle, e.g. after a transport via HTTP?
I'd like to re-bring up the question:
Maybe we can take a step back and you describe what you're actually trying to achieve on an API exchange level. Seems we're too deep into discussing implementation details.
Well, I'm not sure if I can make it clearer, but I'll try:
RepresentationModel<...>
equals
method of these data objects the equals
of the base class, i.e. that of RepresentationModel
, is includedResponseEntity<...>
)TestRestTemplate
)in short: some Spring Boot REST controller tests fail after upgrading to 2.2
I think the issue here is in 5. It doesn't make too much sense to compare a Link
(or even the entire model) instance on the client to the instance prepared on the server side to render the response instead of deserializing an instance on the client and verify the attributes you expect on that, potentially by creating a fresh instance with the expected setup and comparing the two.
The instances produced by the controller are very likely to contain state that's not available on the client. Imagine a RepresentationModel
implementation that's backed by a managed entity. An equals(…)
comparison to a deserialized instance of that on the client wouldn't succeed either.
Most tests that we see written are either fine with using JSONPath expressions on the response ($._links.foobar.href
and checking that value) or use the LinkDiscoverer
abstraction obtain a Link
instance via the expected rel and compare hrefs etc.
What would you recommend:
a) rigorously change what is described in (3), i.e. skip the RepresentaionModel
in the equals
method, or
b) only change the comparisons in the mentioned tests reflecting the special serialization circumstances?
In a REST controller test I compare an object with an added self link with the result of a HTTP transport (via TestRestTemplate). The result is not equal to the original, because the deserialized link has no affordance, where the original after adding the link has one. The reason seems to be the discrepancy between the
@JsonIgnore
onaffordances
and the inclusion of this member in theequals
method. This can simply be reproduced by test case according to the following (incomplete) example:At least in my special case with a real object and a real REST controller this test fails.