JsonDeserializer throws runtime error when parameterized type is not of type collection and JsonElement is of type JsonArray
See original GitHub issueWhen jsonElement
is of type JsonArray
and the JsonDeserialization<T>
type is not a collection, Gson will always throw an IllegalStateException
.
Above is the full code, note that Example
is an empty class.
Below is an image of the direct deserialization in debug mode. Note that the contents of instrumentJson
are irrelevant and that it is a correctly streamed JsonObject
from a JsonArray
.
However, if I decide to serialize to most-any other Objects, the jsonDeserializerContext#deserialize
has no problem whatsoever.
So my educated guess is if the current type is not matching the JsonElement
subtype (JsonObject
or JsonArray
), then it causes problems.
Below is confirmation that jsonElement
is of type JsonArray
My problem is sovled if I change the return type to List<Example>
as seen below.
But this does not fix my use-case of only wanting to return the first element from this list. It doesn’t fit my design pattern either.
Context
The original issue is the designers of the API I am deserializing from, thought it would be cool for a singular resource endpoint to instead of return a JsonObject
, return a JsonArray
that would always be of size 1. It is confirmed that this array will always be size one but they have no plans to change the API and I would prefer to keep the list#get(0)
logic out of my controller if possible and return the single element from the deserializing class.
Major Inquiry
It is possible to deserialize a JsonArray
without having to return a collection type when implementing JsonDeserializer<T>
?
Issue Analytics
- State:
- Created 3 years ago
- Comments:5
Top GitHub Comments
Thank you for the deep insight; apologies, I did not include the version I was using (
2.8.0
). Consider this closed.Thanks! The exception message does indeed come from Gson, but it appears you are using Gson 2.8.1 (or older). It might be worth upgrading to the latest version (2.8.6).
The problem is that the
JsonDeserializer
you are registering is calling itself: Initially you are telling Gson to deserialize your Example JSON array asExample.class
which works fine but then your JsonDeserializer callsjsonDeserializationContext.deserialize(instrumentJson, Example.class)
which invokes itself again (since it is registered forExample.class
), this time with a single Example JSON object which therefore causes the exception you are seeing.If you already know that your data is an array of Example and you only want the first one, then it might be easiest to directly access the
JsonArray
element or to use aJsonReader
(depending on the form in which you receive the JSON data):Otherwise if the Example array appears nested within other model classes, it becomes slightly more complicated. How this can be solved depends on the actual model classes you are using. You could implement a custom
TypeAdapterFactory
which creates an adapter which begins reading the array and then calls a delegate for deserializing theExample
object. If you always wan’t JSON arrays of Example to be deserialized as single Example, then you could register that factory on theGsonBuilder
. Otherwise you could use the@JsonAdapter
annotation on fields of typeExample
and then specify theTypeAdapterFactory
for that annotation (though don’t useGson.getDelegateAdapter(...)
in theTypeAdapterFactory
then because it is currently broken for@JsonAdapter
, see #1028).