spring-projects / spring-projects/spring-hateoas
How to deal with model content polymorphism
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 1.1k
- Forks
- 476
- PR merge metrics
- No merged PRs in 30d
Description
Hi
I don't know if it's a real issue, but I can't find a way to deal with polymorphic content in RepresentationModel.
Let's say I have an abstract Shape class, extended by Square and Circle.
My API will expose an EntityModel< Shape > , and the clients should be able to get the concrete content type.
Made some tests, without success..
The JsonSubType field is ignored when the content is serialized.
Any way to make it works ?
Thanks
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.junit.Test;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.mediatype.MessageResolver;
import org.springframework.hateoas.mediatype.hal.CurieProvider;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
import org.springframework.hateoas.server.core.AnnotationLinkRelationProvider;
import static org.junit.Assert.*;
public class TestSpringHateoas {
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Circle.class, name = "CIRCLE"),
@JsonSubTypes.Type(value = Square.class, name = "SQUARE")
})
@Data
public class Shape {
private float x;
private float y;
}
@Data
public class Circle extends Shape {
private float radius;
}
public class Square extends Shape {
private float size;
}
@Test
public void tests() throws Exception {
var mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.setHandlerInstantiator(
new Jackson2HalModule.HalHandlerInstantiator(new AnnotationLinkRelationProvider(), CurieProvider.NONE, MessageResolver.DEFAULTS_ONLY));
// create a circle
var circle = new Circle();
circle.setX(10f);
circle.setY(10f);
circle.setRadius(5f);
assertEquals("{\"@type\":\"CIRCLE\",\"x\":10.0,\"y\":10.0,\"radius\":5.0}", mapper.writeValueAsString(circle));
// instantiate and serialize a circle
var circleModel = EntityModel.of(circle, Link.of("http://host/shape", IanaLinkRelations.SELF_VALUE));
var circleModelAsJson = mapper.writeValueAsString(circleModel);
// => missing '@type'
assertEquals("{\"x\":10.0,\"y\":10.0,\"radius\":5.0,\"links\":[{\"rel\":\"self\",\"href\":\"http://host/shape\"}]}", circleModelAsJson);
// try to deserialize as a shape (clients do not know the concrete type)
var shapeModel = mapper.readValue(circleModelAsJson, new TypeReference<EntityModel<Shape>>() {});
assertNotNull(shapeModel);
assertTrue(shapeModel.getContent() instanceof Circle);
}
}
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the Java example around EntityModel, Jackson2HalModule, and HalHandlerInstantiator. Compare direct Circle serialization with serialization through EntityModel, then check deserialization as EntityModel. Done means the polymorphic @type field is retained and the content is restored as Circle.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100