question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Serialising generic value classes via Reference Types (like Optional) fails to include type information

See original GitHub issue

After going through a couple issues, I came to understand that Jackson always uses declared type of value to figure out whether to include type information. This is done to ensure that type settings are identical between serialization and deserialization.

However isn’t that statement false for templated class?. This robustness would be better ensured if the type id settings would be bound to declared types for all untemplated classes but were bound to both declaration and component classes for templated classes. This would imply obtaining the type information at runtime, thus serialisation/deserialisation of templated classes would be a little bit less efficient but that drawback would be negligeable at least in my case.

This would allow for serialisation/deserialisation of Templated classes who’s component class are abstract ex. List<AbstractItem>

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.PROPERTY, property = "type")
@JsonSubTypes({
	@JsonSubTypes.Type(name = "ItemADto", value = ItemADto.class)
	@JsonSubTypes.Type(name = "ItemBDto", value = ItemBDto.class)
})
public abstract class AbstractItemDto {...}

@JsonTypeName("ItemADto")
public class ItemADto {...}

@JsonTypeName("ItemBDto")
public class ItemBDto {...}

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:20 (11 by maintainers)

github_iconTop GitHub Comments

2reactions
pwhissellcommented, Jun 27, 2017

Given the example I have a list of item’s who’s classes are part of a polymorphic hierarchy

List<AbstractItemDto> items = new ArrayList<>();
items.add(new ItemADto());
items.add(new ItemBDto());

When I serialize this list,

ObjectMapper mapper = new ObjectMapper();
String itemsJson = mapper.writeValueAsString(items);

then the type information concerning ItemADto and ItemBDto are not serialized and therefor lost.

/* 
itemsJson == 
"[
    {},
    {}
]"
*/

Since AbstractItemDto specifies the usage of a “type” attribute for JsonTypeInfo @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.PROPERTY, property = "type")

I would expect the serialized string to contain the “type” attribute necessary for the list’s deserialization

/* 
itemsJson == 
"[
    {type: "ItemADto"},
    {type: "ItemBDto"}
]"
*/

this would allow me to effectively deserialise itemsJson into a list containing one instance of ItemADto and one instance of ItemBDto

1reaction
cowtowncodercommented, Jun 28, 2017

@pwhissell Ah. No, it’s not because this is not supported, but due to Java Type Erasure. This is a FAQ. (type erasure meaning that runtime type can not be detected as anything but List<?>)

My main suggestion is really to avoid ever using generic types as root value (that is, value directly passed to ObjectMapper/ObjectWriter). They are fine everywhere else, when reached via property, since generic signature is actually retained in class definition, and thereby accessible.

Instead, either:

  1. Use temporary sub-class that binds type parameters (like class MyList extends ArrayList<Pojo> { }
  2. Use wrapper POJO that has generic type.

But if you really really want to use Lists, Maps or generic POJOs as root values, you need to pass type parameter to work around type erasure:

mapper.writerFor(new TypeReference<List<AbstractDTO.>>() { })
    .writeValueAsBytes(value);

As things are, there may be issues here too, unfortunately, as this forces type for serializer to use AbstractDTO, and not just as base type. This may or may be a problem, depending on exactly where properties for subtypes exist. There is a filed issue to allow specifying just the base type (distinct from full value types), but it has not been implemented.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Problem with Deserialization of Generic Classes
There is an idea, try accept monetaryType as the String type parameter, and you can custom converter in the Generic class for handling...
Read more >
Why Isn't Optional Serializable? - nipafx.dev
As described above, value types are not handled by reference, which means they have no identitiy. This implies that no identity based mechanism ......
Read more >
XmlSerializer Class (System.Xml.Serialization) | Microsoft Learn
Serializes and deserializes objects into and from XML documents. The XmlSerializer enables you to control how objects are encoded into XML.
Read more >
Java Optional as Return Type - Baeldung
When getting an Optional return type, we're likely to check if the value is missing, leading to fewer NullPointerExceptions in the applications.
Read more >
TorchScript Language Reference - PyTorch
To instantiate an empty list or dict of other types, use Python 3 type hints . Example (type annotations for Python 3):. import...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found