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

NPE while invoke toJson() or fromJson() for HashMap<String, String> #1778

Open
zewenwang opened this issue Sep 11, 2020 · 19 comments
Open

NPE while invoke toJson() or fromJson() for HashMap<String, String> #1778

zewenwang opened this issue Sep 11, 2020 · 19 comments
Labels
android Issues which are exclusive to Android, and don't occur with a JDK (even if ProGuard / R8 is used) bug needs-info proguard-r8 Issues relating to the use of ProGuard and/or R8, such as problems due to obfuscation

Comments

@zewenwang
Copy link

the exception:

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference
  libcore.reflect.TypeVariableImpl.hashCode(TypeVariableImpl.java:47)
  java.util.HashMap.hash(HashMap.java:338)
  java.util.HashMap.containsKey(HashMap.java:595)
  java.util.HashSet.contains(HashSet.java:203)
  com.google.gson.internal.$Gson$Types.resolve(.java:346)
  com.google.gson.internal.$Gson$Types.resolve(.java:381)
  com.google.gson.internal.$Gson$Types.resolve(.java:337)
  com.google.gson.internal.$Gson$Types.getSupertype(.java:283)
  com.google.gson.internal.$Gson$Types.getCollectionElementType(.java:302)
  com.google.gson.internal.bind.CollectionTypeAdapterFactory.create(CollectionTypeAdapterFactory.java:52)
  com.google.gson.Gson.getAdapter(Gson.java:458)
  com.google.gson.Gson.toJson(Gson.java:696)
  com.google.gson.Gson.toJson(Gson.java:683)
  com.google.gson.Gson.toJson(Gson.java:638)
  com.google.gson.Gson.toJson(Gson.java:618)

my code:

new Gson().fromJson(json, new TypeToken<HashMap<String, String>>() {}.getType());

environment

Gson version 2.8.5
The probability of this problem happens substantial increases,when gson version upgrades from 2.8.2 to 2.8.5 !

Same problem with #1298 , but not resolved.

@zewenwang
Copy link
Author

@Marcono1234
Copy link
Collaborator

Could this possibly be an Android bug (libcore.reflect.TypeVariableImpl is an Android class)? I assume Gson is not creating the TypeVariableImpl on its own but probably retrieves it somehow from a parameterized type, in that case Android would be the one creating that TypeVariableImpl which is causing the issues.

Could you please debug into TypeVariableImpl and check which expression is causing the NullPointerException?

@fvdcx
Copy link

fvdcx commented Sep 25, 2020

I also met this issue, but my code calls "toJson" on a HashMap<String, Object>. @Marcono1234 @zewenwang
how to escalate this bug?

@Marcono1234
Copy link
Collaborator

As written in my comment above it would probably first be useful to get more information about which variable is null.

@Aquarids
Copy link

Aquarids commented Nov 2, 2020

I also met this issue, but my code calls "toJson" on a HashMap<String, Object>. @Marcono1234 @zewenwang
how to escalate this bug?

metoo, is there a fixed method?

@Marcono1234
Copy link
Collaborator

As written above, it would be useful if you could provide more information:

Could this possibly be an Android bug (libcore.reflect.TypeVariableImpl is an Android class)? I assume Gson is not creating the TypeVariableImpl on its own but probably retrieves it somehow from a parameterized type, in that case Android would be the one creating that TypeVariableImpl which is causing the issues.

Could you please debug into TypeVariableImpl and check which expression is causing the NullPointerException?

@Aquarids
Copy link

Aquarids commented Nov 3, 2020

As written above, it would be useful if you could provide more information:

Could this possibly be an Android bug (libcore.reflect.TypeVariableImpl is an Android class)? I assume Gson is not creating the TypeVariableImpl on its own but probably retrieves it somehow from a parameterized type, in that case Android would be the one creating that TypeVariableImpl which is causing the issues.
Could you please debug into TypeVariableImpl and check which expression is causing the NullPointerException?

Sorry, here is the stacktrace.

libcore.reflect.TypeVariableImpl.hashCode(TypeVariableImpl.java:47)
java.util.HashMap.hash(HashMap.java:348)
java.util.HashMap.containsKey(HashMap.java:608)
java.util.HashSet.contains(HashSet.java:203)
com.google.gson.internal.$Gson$Types.resolve(.java:346)
com.google.gson.internal.$Gson$Types.resolve(.java:381)
com.google.gson.internal.$Gson$Types.resolve(.java:337)
com.google.gson.internal.$Gson$Types.getSupertype(.java:283)
com.google.gson.internal.$Gson$Types.getCollectionElementType(.java:302)
com.google.gson.internal.bind.CollectionTypeAdapterFactory.create(CollectionTypeAdapterFactory.java:52)
com.google.gson.Gson.getAdapter(Gson.java:458)
com.google.gson.Gson.toJson(Gson.java:696)
com.google.gson.Gson.toJson(Gson.java:683)
com.google.gson.Gson.toJson(Gson.java:638)

And my code is:

List<MyCustomClass> list = new ArrayList<>();
mGson.toJson(list);

or

List<MyCustomClass> list = new ArrayList<>();
mGson.toJson(list, TypeToken.getParameterized(List.class, MyCustomClass.class).getType());

@Cyux07
Copy link

Cyux07 commented Nov 3, 2020

it looks like a NULL generic declaration of class cause NPE.
https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/libcore/reflect/TypeVariableImpl.java

@Override
    public int hashCode() {
        return 31 * getName().hashCode() + getGenericDeclaration().hashCode();
    }

follow the trace, the toResolve's generic type lost?:

 private static Type resolve(Type context, Class<?> contextRawType, Type toResolve,
                              Collection<TypeVariable> visitedTypeVariables) {
    // this implementation is made a little more complicated in an attempt to avoid object-creation
    while (true) {
      if (toResolve instanceof TypeVariable) {
        TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve;
        if (visitedTypeVariables.contains(typeVariable)) {
          // cannot reduce due to infinite recursion
          return toResolve;
        } else {
          visitedTypeVariables.add(typeVariable);
        }
        toResolve = resolveTypeVariable(context, contextRawType, typeVariable);
        if (toResolve == typeVariable) {
          return toResolve;
        }

      }......

And the toResolve come from $Gson$Types.getGenericSupertype(context, contextRawType, supertype).

Maybe this method return a NULL generic type collection in some case?

static Type getSupertype(Type context, Class<?> contextRawType, Class<?> supertype) {
    if (context instanceof WildcardType) {
      // wildcards are useless for resolving supertypes. As the upper bound has the same raw type, use it instead
      context = ((WildcardType)context).getUpperBounds()[0];
    }
    checkArgument(supertype.isAssignableFrom(contextRawType));
    return resolve(context, contextRawType,
        $Gson$Types.getGenericSupertype(context, contextRawType, supertype));
  }

@Marcono1234
Copy link
Collaborator

Are you able to reproduce this exception when debugging on an emulator, or only for the deployed app? Which Android API Level does the target device have? Are you using a custom ProGuard configuration?

If possible could you please create a small example project which only contains the relevant code, which allows reproducing this issue (and describe reproduction steps if necessary).

@Aquarids
Copy link

Are you able to reproduce this exception when debugging on an emulator, or only for the deployed app? Which Android API Level does the target device have? Are you using a custom ProGuard configuration?

If possible could you please create a small example project which only contains the relevant code, which allows reproducing this issue (and describe reproduction steps if necessary).

Thanks for your reply, we have solved this problem by wrapping a JsonObject on the JsonArray. And this is an online occasional problem which reproted by our user, thus we also don't have more information to identify the reason of the problem.

@EmMper
Copy link

EmMper commented Dec 30, 2020

It happened to me on version 2.8.2, the same stack trace, and I also wrote the code below:

// Kotlin Code
Gson().fromJson(jsonString, object : TypeToken<List<MyCustomClass>>() {})

to deserialize with a type token, I think this may be a clue.
And this problem won't happened every time, actually the frequency of problems is pretty low. So I'm not sure how to reproducing it.
Now I'm trying to update Gson to the newest version 2.8.6, and I wonder will this issue happen again.

@EmMper
Copy link

EmMper commented Dec 30, 2020

Are you able to reproduce this exception when debugging on an emulator, or only for the deployed app? Which Android API Level does the target device have? Are you using a custom ProGuard configuration?
If possible could you please create a small example project which only contains the relevant code, which allows reproducing this issue (and describe reproduction steps if necessary).

Thanks for your reply, we have solved this problem by wrapping a JsonObject on the JsonArray. And this is an online occasional problem which reproted by our user, thus we also don't have more information to identify the reason of the problem.

So your resolvent is to use another serialization tool? I noticed that you are in Beijing too, may I get your wechat or something to communicate with you?

@Aquarids
Copy link

Aquarids commented Jan 4, 2021

Are you able to reproduce this exception when debugging on an emulator, or only for the deployed app? Which Android API Level does the target device have? Are you using a custom ProGuard configuration?
If possible could you please create a small example project which only contains the relevant code, which allows reproducing this issue (and describe reproduction steps if necessary).

Thanks for your reply, we have solved this problem by wrapping a JsonObject on the JsonArray. And this is an online occasional problem which reproted by our user, thus we also don't have more information to identify the reason of the problem.

So your resolvent is to use another serialization tool? I noticed that you are in Beijing too, may I get your wechat or something to communicate with you?

没,我就直接用jsonObject又包了层,原本是[{"xxx", "yyy"}],现在是 {"data": [{"xxx", "yyy"}]}就暂时解决了。原因就和上面Cyux07说的一样。

@EmMper
Copy link

EmMper commented Jan 8, 2021

Are you able to reproduce this exception when debugging on an emulator, or only for the deployed app? Which Android API Level does the target device have? Are you using a custom ProGuard configuration?
If possible could you please create a small example project which only contains the relevant code, which allows reproducing this issue (and describe reproduction steps if necessary).

Thanks for your reply, we have solved this problem by wrapping a JsonObject on the JsonArray. And this is an online occasional problem which reproted by our user, thus we also don't have more information to identify the reason of the problem.

So your resolvent is to use another serialization tool? I noticed that you are in Beijing too, may I get your wechat or something to communicate with you?

没,我就直接用jsonObject又包了层,原本是[{"xxx", "yyy"}],现在是 {"data": [{"xxx", "yyy"}]}就暂时解决了。原因就和上面Cyux07说的一样。

OK,了解了。但依然可以认为是Gson自己的bug吧?总感觉这样处理不能算是最终方案

@Marcono1234
Copy link
Collaborator

Marcono1234 commented Feb 3, 2022

In this pull request Gson users tried to solve this by modifying their ProGuard rules.
Could you please try, with the latest version of Gson, whether disabling any shrinking and obfuscation for class com.google.gson.reflect.TypeToken and class * extends com.google.gson.reflect.TypeToken solves this issue?

Or in general make sure you apply the ProGuard rules shown in proguard.cfg, except for the one for com.google.gson.examples.android.model.**.

@emanoellucasml
Copy link

Hello, does anyone know if doing what @Marcono1234 suggested here the problem is solved? I am going through the same problem but updating the library version would affect many people, so I wanted to be sure before doing it.

@Marcono1234
Copy link
Collaborator

Marcono1234 commented Aug 29, 2022

I just mentioned using the latest Gson version to avoid having to debug issues in older versions, which might already be fixed in the latest version. Though this appears to be caused by ProGuard (or R8) so I assume adjusting the ProGuard rules without upgrading Gson might work as well.

@vagrant1991
Copy link

https://issuetracker.google.com/issues/220725541

@vagrant1991
Copy link

vagrant1991 commented Sep 16, 2023

visit the above link, It sames like you have List, Map or Set (ex: ArrayList, HashSet) member in your java bean class, and not all of them using the @SerializedName annotation, so In R8 3.x, generics get stripped out, refer to : https://android.googlesource.com/platform/libcore/+/refs/heads/main/luni/src/main/java/libcore/reflect/TypeVariableImpl.java
when you call hashcode method, getGenericDeclaration return null, so you get NullPointerException,

com.google.gson.internal.$Gson$Types.getCollectionElementType(.java:302)

take a look at getCollectionElementType in $Gson$Types, As the method name show you, It's all about Collections.

@Marcono1234 Marcono1234 added the proguard-r8 Issues relating to the use of ProGuard and/or R8, such as problems due to obfuscation label Mar 29, 2024
@eamonnmcmanus eamonnmcmanus added the android Issues which are exclusive to Android, and don't occur with a JDK (even if ProGuard / R8 is used) label Jul 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
android Issues which are exclusive to Android, and don't occur with a JDK (even if ProGuard / R8 is used) bug needs-info proguard-r8 Issues relating to the use of ProGuard and/or R8, such as problems due to obfuscation
Projects
None yet
Development

No branches or pull requests

9 participants