Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FutureTypeAdapter.read() throws unhelpful exception #625

Closed
GoogleCodeExporter opened this issue Mar 19, 2015 · 7 comments · Fixed by #1832
Closed

FutureTypeAdapter.read() throws unhelpful exception #625

GoogleCodeExporter opened this issue Mar 19, 2015 · 7 comments · Fixed by #1832
Labels

Comments

@GoogleCodeExporter
Copy link

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
Copy link
Author

[deleted comment]

@GoogleCodeExporter
Copy link
Author

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
Copy link

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

@josefdlange
Copy link

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
Copy link

ninovanhooff commented Aug 26, 2016

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
Copy link

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:

  • TypeA references TypeB which references TypeA
  • Gson.getAdapter(TypeA) creates a FutureTypeAdapter (thread local) for TypeA
  • In a sub-call, Gson.getAdapter(TypeB) uses the unfulfilled FutureTypeAdapter for TypeA.
  • On the way out, Gson.getAdapter(TypeB) registers with tokenTypeCache a type adapter that references the unfulfilled FutureTypeAdapter for TypeA
  • Between then and the call.setDelegate() in Gson.getAdapter(TypeA), we have an unfulfilled FutureTypeAdapter in the shared tokenTypeCache.

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
Copy link

byencho commented Nov 18, 2022

We are on 2.9.1 and still seeing this. I see there are a couple of PRs open to address this....#1832 is even approved but is not merged. Is there a reason that has not been included in a fix?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
7 participants