Feature request:
Provide better support for polymorphic deserialization (aka polymorphic type handling).
By polymorphic deserialization, I'm referring to the Animal / Dog / Cat example handled by Gson's RuntimeTypeAdapterFactory extra:
https://futurestud.io/blog/how-to-deserialize-a-list-of-polymorphic-objects-with-gson
Jackson has even more support for this:
http://wiki.fasterxml.com/JacksonPolymorphicDeserialization
and see example 4 in this Jackson tutorial:
http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html
In Moshi, it's not clear how to do this without writing a complex adapter. One approach is to leverage an intermediate class (following the Event example), but then the adapter still needs to deal with the Maps and Lists and other raw types that have already been parsed.
For example, see: http://stackoverflow.com/q/34049013/901597
Please provide a new adapter to fill the gap, or provide a new example showing how to write the equivalent of Gson's RuntimeTypeAdapterFactory.
I think we鈥檇 be good to include a _recipes_ document for Moshi, with lots of sample code.
Any progress on this issue ? This is a reason why we might prefer GSON over Moshi.
If you鈥檇 like, you should be able to port this class to Moshi.
https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java
Should I make a PR with this feature + relevant unit tests?
Sure. Maybe a contribution to our adapters submodule?
Has anybody successfully done this using adapters?
I will post a PR soon, if somebody wants to make an implementation before me, go for it :)
I don't think this is only a lack of documentation. I don't think this is currently possible. Gson has the JsonElement type, and Moshi simply has Map
Polymorphic deserialization is possible but in a little bit complicated and less memory efficient way.
Polymorphic deserialization requires a type parameter from JSON object to decide the actual type to deserialize. But there is no guarantee that a type parameter presents before any other tokens read from a JSON object. So the same token stream need to be read twice: the first time to determine the type and the object is deserialized with actual type at the second time.
Came up with a hack to clone a JsonReader object. Then it should be easy to port a RuntimeTypeAdapterFactory to moshi.
Any update on this issue? Could anyone point to the right way to solve polymorphic deserialization with Moshi? In case there is not official support from Moshi yet, is @kamikat hack acceptable as a temporary solution? Thanks.
Yes, you can do this now.
A general idea of an implemention: https://github.com/square/moshi/pull/264/files
I'll try to get blog posts with more explanations out to point to in the next week.
@NightlyNexus could you please take a look at the following gist?
https://gist.github.com/saguinav/3dfd88f78ab38a74e15cddc8b90398c5
I have implemented my own RuntimeJsonAdapterFactory which is heavily inspired on your implementation. The main differences are two:
RuntimeJsonAdapterFactory only supports one type of polymorphic deserialization case (base type + sub types). My implementation supports multiple cases.RuntimeJsonAdapter reads the entire JsonValue and transform it into a MapRuntimeJsonAdapter reads token by token from the buffer until it finds the "discriminator" field whose value determines the type of the polymorphism. While reading, the data gets copied into a temporary buffer and then it will be "merged" with the original and delegated to the specific subtype JsonAdapter. I think this way could be more performant.Please let me know what you think. Thanks in advance!
And if included it should be in the documentation... by the way, is there a recipes for moshi?
I have found some issues that are questions about how to do x or y...
@saguinav hey, based on NightlyNexus's above recipe, i've also made my adjusts, to add a default sub type, because some APIs have many sub types and it's hard to know them all in advance, so i deserialize to a generic type instead of raising JsonDataException, here it is, how do you think of it?
New plan: lets port Gson鈥檚 RuntimeTypeAdapterFactory.java to Moshi and add it to the moshi-adapters package. It shouldn鈥檛 require much code now that we have readJsonValue().
Any update on this?
@NightlyNexus What鈥檚 left on this one?
seems like the RuntimeJsonAdapterFactory in the adapters artifact handles the use case from the original post here.
Most helpful comment
606