On Wed, Feb 27, 2019 at 1:38 PM Samuel <[email protected]> wrote:
>
> Following classes:
>
> public class StructuralRule {
>
>    private List<Statement> statements;
>
>    .. /getter & setter
>
> }
>
>
> @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, 
> property = "id")
> @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "operator")
> @JsonSubTypes({
>         @JsonSubTypes.Type(value = StatementEquals.class, name = "equals"),
>         @JsonSubTypes.Type(value = StatementIn.class, name = "in"),
>         @JsonSubTypes.Type(value = StatementLike.class, name = "like"),
> })
> public abstract class Statement<T> {
>     private String key;
>     private T value;
>
>     public Statement() {
>     }
>
>     public Statement(String key, T value) {
>         this.key = key;
>         this.value = value;
>     }
>     .. /getter & setter
> }
>
>
>
> When serializing a StructuralRule-Object the property "operator" inside 
> Statement is serialized too.
>
> But when the List of Statements is serialized the "operator" disappears.
>
> And when a single Statement is serialized then the "operator" is there.
>
>
> new ObjectMapper().writeValueAsString(structuralRule)
>
> {"statements":[{"operator":"equals","id":1,"key":"keyx","value":"valy"}]}
>
> new ObjectMapper().writeValueAsString(structuralRule.getStatements())  // 
> missing "operator"
> [{"id":1,"key":"keyx","value":"valy"}]
>
> new ObjectMapper().writeValueAsString(structuralRule.getStatements().get(0))
> {"operator":"equals","id":1,"key":"keyx","value":"valy"}
>
>
> I think it's bug.
>
> What do you think?

It's not a bug in Jackson, but limitation of Java generics, known as
"Type Erasure".

Whereas value of property `statements` is known as `List<Statement>`
(from method/field declaration), runtime value return by
`getStatements()` can only be known as `List<?>` (that is, `List<?
extends Object>`), so element type is known only as `Object or
subtype`.
Because of `Object` does not have type info inclusion enabled, no type
information is included.

So: the main rule is to avoid using generic types as root values. This
mainly affects Collections and Maps.

There are 3 ways to resolve the problem

1. Use a wrapper POJO (non-generic) to contain generic types --
`StructuralRule` works fine
2. Use concrete subtype of generic types -- public class StatementList
extends List<Statement> { }
3. Force use of specific type on serialization too (you will always
need it on deser):

   objectMapper.writerFor(new TypeReference<List<Statement>>() { }).
       writeValue(listValue);

I hope this helps,

-+ Tatu +-

-- 
You received this message because you are subscribed to the Google Groups 
"jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to