@Entity
public Product {
@Id
public int id;
public String name;
@ManyToOne(cascade = {CascadeType.DETACH} )
Category category
@ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH} )
Set<Category> secondaryCategories;
}
and this entity:
@Entity
public Category {
@Id
public int id;
public String name;
}
I would like to be able to send a POST with json
{ name: "name", category: 2, secondaryCategories: [3,4,5] }
from client-side
and be able to be deserialized like:
{ name: "name", category: {id: 2 }, secondaryCategories: [{id: 3}, {id: 4}, {id: 5}] }
in case it was sent as
{ name: "name", category: {id: 2 }, secondaryCategories: [{id: 3}, {id: 4}, {id: 5}] }
I would like it to still work as now
what kind of annotation and custom deserializer I need? Hopefully the deserializer can work for all possible objects that have id as a property
Thanks!
Edit
- See the preferred zafrost's
@JsonCreator
answer (https://stackoverflow.com/a/46618366/986160) - See my complete answer (https://stackoverflow.com/a/46618193/986160) for extending
StdDeserializer
and using default deserialization throughObjectMapper
The complete solution after much struggle was - thanks to https://stackoverflow.com/users/1032167/varren's comment and https://stackoverflow.com/a/16825934/986160 I was able to use the default deserialization (through a local new objectMapper) in my
StdDeserializer
without the hurdles in this answer: https://stackoverflow.com/a/18405958/986160The code tries to parse an int and if it is a whole object it just passes it through - so it still works for example when you make a POST/PUT request of a
Category
or in other words whenCategory
is not embeddedfor each entity I need to behave like described I need to configure it in global ObjectMapper Bean of the Spring Boot application:
This is my ReflectionUtils from https://stackoverflow.com/a/14374995/986160
There are several options you could try, actually custom deserializer/serializer would probably make sense, but you also can achieve this with
@JsonIdentityInfo
(for deserialization) +@JsonIdentityReference
(if you need serialization as integer) annotations.Deserialization
So you need to annotate every class that can be deserialized from its id with
@JsonIdentityInfo
The hard part here is that you actually have to write custom
ObjectIdResolver
that can resolve objects from your db/other source. Take a look at my simple reflection version inMyObjectIdResolver.resolveId
method in example below:Serialization
Default behavior is described here: https://github.com/FasterXML/jackson-databind/issues/372 and will produce object for the first element and id for each element after. An ID/reference mechanism in Jackson works so that an object instance is only completely serialized once and referenced by its ID elsewhere.
Option 1. (Always as id)
Need to use
@JsonIdentityReference(alwaysAsId = true)
above each object field(can uncomment in demo at the bottom of the page)Option 2. (Always as full object representation)
This option is tricky because you will have to remove all the IdentityInfo for serialization somehow. One option could be to have 2 object mappers. 1 for serialization and 2-nd for deserialization and configure some sort of mixin or
@JsonView
Another approach that is easier to implement is to use
SerializationConfig
to ignore@JsonIdentityInfo
annotations completelyProbably the better approach would be to actually define
@JsonIdentityInfo
for deserializerconfig the same way and remove all annotations above classes. Something like thisAt this point you probably wish you just wrote custom serializer/deserializer
Here is working (simple Jackson without spring) demo:
Another approach is to use
@JsonCreator
factory method if you can modify your EntityOr even something like this should also work