google / gson

A Java serialization/deserialization library to convert Java Objects into JSON and back
Apache License 2.0
23.41k stars 4.29k forks source link

FutureTypeAdapter.read() throws unhelpful exception #625

Closed GoogleCodeExporter closed 1 year ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
When FutureTypeAdapter's delegate is null, the read() method throws an 
IllegalStateException with no message.  This then gets turned into a 
JsonSyntaxException

These two exceptions don't make it easy to diagnose what went wrong, and you 
can't easily tell if the issue is caused by a programming error, a bug in Gson, 
or with the json being parsed.  There's also no indication of what the 
developer can do to avoid hitting this exception. Adding javasdoc and a helpful 
method to the exception woudl be very nice. 

Below is a sample stack trace. 

E/Timber  ( 3055): Caused by: retrofit.converter.ConversionException: 
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException
E/Timber  ( 3055):  at 
retrofit.converter.GsonConverter.fromBody(GsonConverter.java:67)
E/Timber  ( 3055):  at 
retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:362)
E/Timber  ( 3055):  ... 9 more
E/Timber  ( 3055): Caused by: com.google.gson.JsonSyntaxException: 
java.lang.IllegalStateException
E/Timber  ( 3055):  at 
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(Reflecti
veTypeAdapterFactory.java:187)
E/Timber  ( 3055):  at com.google.gson.Gson.fromJson(Gson.java:805)
E/Timber  ( 3055):  at com.google.gson.Gson.fromJson(Gson.java:770)
E/Timber  ( 3055):  at 
retrofit.converter.GsonConverter.fromBody(GsonConverter.java:63)
E/Timber  ( 3055):  ... 10 more
E/Timber  ( 3055): Caused by: java.lang.IllegalStateException
E/Timber  ( 3055):  at 
com.google.gson.Gson$FutureTypeAdapter.read(Gson.java:885)
E/Timber  ( 3055):  at 
com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRunt
imeTypeWrapper.java:40)
E/Timber  ( 3055):  at 
com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(Collecti
onTypeAdapterFactory.java:81)
E/Timber  ( 3055):  at 
com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(Collecti
onTypeAdapterFactory.java:60)
E/Timber  ( 3055):  at 
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveType
AdapterFactory.java:95)
E/Timber  ( 3055):  at 
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(Reflecti
veTypeAdapterFactory.java:183)
E/Timber  ( 3055):  ... 13 more

Original issue reported on code.google.com by MhaleK...@gmail.com on 29 Jan 2015 at 5:26

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
I have the same exact issue and no ideas on how to actually fix it. As far as I 
have investigated 'delegate' can be null only when 
FutureTypeAdapter.setDelegate() was not called OR was called with a 'null' 
object. Seems that the latter is impossible to happen as only call to 
setDelegate is from Gson.java:355:

for (TypeAdapterFactory factory : factories) {
        TypeAdapter<T> candidate = factory.create(this, type);
        if (candidate != null) {
          call.setDelegate(candidate);
          typeTokenCache.put(type, candidate);
          return candidate;
        }
      }
      throw new IllegalArgumentException("GSON cannot handle " + type);

But the exception that should be thrown here when no 'candidate' was found in 
the loop is also never thrown or is just ignored somewhere else in the code.

I am reproducing this while trying to parse 8 collections of 100 objects in 
separate 8 threads. All of the objects are of the same type. I think an 
important factor is that it either happens at the very beginning of parsing 
process by the first thread of the first collection element or it never happens.

Original comment by maciej.p...@gmail.com on 17 Feb 2015 at 10:55

stravadave commented 9 years ago

Same issue here, not able to reproduce locally but find it very common in our crash reports.

josefdlange commented 8 years ago

Ran into this today. One quick workaround is to have separate instances of gson doing the work for each thing, at least from what I can see here.

I use gson in conjunction with retrofit, and I found that creating multiple instances of my retrofit interface ended up making the issue go away. This in effect meant separate instances of gson were being created.

Not the most memory-efficient solution but a solution nonetheless. Seems like something is getting lost when an instance is being asked to process multiple objects concurrently.

ninovanhooff commented 8 years ago

Has this issue been resolved, ie. is there still a crash? I'm upgrading from 2.4 to 2.7 to see whether the issue remains. The sources show that the topic of this issue is still relevant; no exception messages have been added.

Edit: even with version 2.7, I observed this exception. So instead I stopped using a Singleton as suggested.

dunhamsteve commented 7 years ago

I'm gonna leave this here for posterity. We're still on 2.6.2 and are hitting this, dunno if it's fixed in newer versions. This is what I think is happening:

If I'm right, then I think calling gsonInstance.getAdapter(YourRootClass.class) after constructing your shared gson instance would work around the issue. (I'm working around it by rewriting the rats-nest of classes that we're deserializing into.)

byencho commented 2 years ago

We are on 2.9.1 and still seeing this. I see there are a couple of PRs open to address this....https://github.com/google/gson/pull/1832 is even approved but is not merged. Is there a reason that has not been included in a fix?