Using:
@JsonTypeInfo(
use = Id.NAME,
include = As.PROPERTY,
property = "_class"
)
On a Hibernate entity class (this could make a difference, as Hibernate tends to proxy objects), when serializing a single object, I correctly get the _class field:
new ObjectMapper().writeValueAsString(base.getSubScopes().get(0));
// Returns: {"_class":"Institute","id":36}
But for the entire collection it returns the JSON without _class data:
new ObjectMapper().writeValueAsString(base.getSubScopes());
// Returns: [{"id":36}]
The collection is of the Hibernate type PersistentBag. If I wrap the samething in an Arraylist though, I get the same result:
new ObjectMapper().writeValueAsString(Lists.newArrayList(base.getSubScopes()));
// Returns: [{"id":36}]
I see this behaviour on both 2.7.x and 2.8.0 versions.
Update: seems to not work because the type is deduced from the collection, rather on a per-instance basis. Related to #1127, #1188 . So a List<Inner> is serialized properly, a List<Object> containing an Inner object is not.
If this can be reproduced without any Hibernate usage, it belongs here; but if it is (which seems very likely, based on past experience) related to hibernate object handling, it should be moved it to jackson-datatype-hibernate repo issue tracker.
The issue I am experiencing seems not related to Hibernate. See the failing testcase I've introduced with a PR. @cowtowncoder
Unfortunately this is not a bug. See comments on PR on explanation.
This is not something that will be changed; many suggestions have been made to consider type information separately for each element, but this is not a change I will make.
@cowtowncoder Aha, I was thinking about that too. To me it would make sense to just always include type information if a super class has the annotation, in fact, I believed it was actually working that way. What specifically is your argument against that? I presume this approach would be slow and limit the optimisations Jackson can make for serialisation? Or is this just from the philosophy that a raw typed list can't be deserialised either, and therefore should not be serialisable?
Another option I could think of, I believe there is the mechanism to wrap an element in another tag. Perhaps we could do the reverse for serializing generic lists, make a wrapper (that has some annotation) and will then be serialized to a plain list?
Anyways, thanks for your response and I think I am going to look into returning the type information by default using the properties.
@JWGmeligMeyling super-class annotations are considered, that is not the problem.
Problem is that type information for root value (List) has element type of ?, that is, roughly Object. So information is simply not available when considering serializer for List value; unless explicitly passed.
This is how 2 work-arounds work: they make type information available for root values too, either by sub-classing (in which case generic types are available from class definition), or by telling ObjectMapper/ObjectWriter generic type.
And yes, third work around would indeed be to have non-generic POJO as root value; in that case full type is available. That is probably the cleanest approach.
Here is a workaround to force Jackson to serialize the class name at all times:
@JsonTypeInfo(
use=JsonTypeInfo.Id.CLASS,
include=JsonTypeInfo.As.EXISTING_PROPERTY,
property="class")
public interface MyInterface {
@JsonProperty("class")
public default String getClassName() {
return this.getClass().getName();
}
}
Note the use of EXISTING_PROPERTY to avoid adding duplicate "class" attributes if serializing the instance as a root object.
Most helpful comment
Here is a workaround to force Jackson to serialize the class name at all times:
Note the use of
EXISTING_PROPERTYto avoid adding duplicate"class"attributes if serializing the instance as a root object.