Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This pull request is part two, building on schmittjoh#1546.
I made some assumptions while making this change, and am very open to feedback. I've tested the Union functionality pretty thoroughly by running my external project's test suite against it, so I'm fairly confident that things work in general, but because of my inexperience with
jms/serializer
there may be many interactions that I've missed.This adds Union support for objects in 2 ways:
This is the easy case. For objects that have a field which specifies their type, i.e.:
I added a new Annotation:
UnionDiscriminator
that allows you to use this field to determine which object to deserialize into.For more complex cases, the
UnionDiscriminator
Annotation can also receive amap
attribute, which will map from the values contained in the discriminator field, to the fully qualified class.i.e.
Known issues with Discriminated Unions:
@Type
annotations don't support unions (I looked into modifying the lexer/parser, but it's pretty non trivial to add).->deserialize
. i.e. they are only supported when they are Properties on objects.There is no "correct way" to deserialize into Union Types without discriminated fields, so I borrowed an approach I've seen in other languages (I recently added a similar implementation to the
Python
dataclasses_json
package, but this approach is similar toTypeScript
'szod
package).Essentially, in order to deserialize a Union, I "try" to deserialize into the possible types one by one until I find a type that the data matches well, and I assume that is the correct type.
I first sort the objects based on the number of required properties on the object. If the Union is a mix of objects and primitives, I try the primitives first.
If while deserializing the JSON contains data of a type that doesn't match the Object, then we give up on that type.
If while deserializing, the JSON does not contain a required property from the Object, then we give up on that type.
If while deserializing, the JSON contains a field that the Object doesn't have a matching field for, then we ignore that field, continuing to deserialize the current type.
The bulk of the code supporting this change can be seen in the
UnionHandler
and theDerserializationGraphNavigator
.The enumeration of possible exceptions in
UnionHandler
seems like a point of fragility.The introduction of
requireAllRequiredProperties
field on theJsonDeserializationVisitor
is a bit peculiar - any feedback on a more idiomatic way to add this functionality is welcomed.@scyzoryck @goetas - sorry that this PR is so big! I hope you'll agree it's worth the time to add.