google / gson

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

java.lang.AssertionError: illegal type variable reference #1343

Open kkmike999 opened 6 years ago

kkmike999 commented 6 years ago

i use gson 2.8.5 in android project,run app with proguard on real Android Phone. when execute code Type listType = new TypeToken<List<T>>() {}.getType(),then crash:

 java.lang.AssertionError: illegal type variable reference
        at libcore.reflect.TypeVariableImpl.resolve(TypeVariableImpl.java:111)
        at libcore.reflect.TypeVariableImpl.getGenericDeclaration(TypeVariableImpl.java:125)
        at libcore.reflect.TypeVariableImpl.hashCode(TypeVariableImpl.java:47)
        at java.util.Arrays.hashCode(Arrays.java:4153)
        at com.google.gson.internal.$Gson$Types$ParameterizedTypeImpl.hashCode($Gson$Types.java:502)
        at com.google.gson.reflect.TypeToken.<init>(TypeToken.java:64)
......

i have add these code in proguard.pro:

-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes Deprecated
-keepattributes SourceFile
-keepattributes LineNumberTable
-keepattributes *Annotation*
-keepattributes EnclosingMethod

# Gson specific classes
-keep class sun.** { *; }
#-keep class com.google.gson.stream.** { *; }

# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
lyubomyr-shaydariv commented 6 years ago

It doesn't look like a bug.listType cannot be declared with T (it looks like it's declared within your generic class capturing the class type variable only) at the declaration site, but it should be declared at the call site with a real type, and then passed to your generic class. The same goes to generic methods. Simple googling before posting would save you some time and give some hints: Gson illegal type variable reference - Stack Overflow.

kkmike999 commented 6 years ago

@lyubomyr-shaydariv maybe some other config cause this error. i config build.gradle

android {
 buildTypes{
    alpha {
            minifyEnabled true
            zipAlignEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'proguard-rules-2.0.pro'
            signingConfig signingConfigs.releaseConfig
            multiDexKeepProguard file('keep_in_main_dex.pro')
            debuggable = false

            // matchingFallbacks属性来设置回退策略(必填,http://codezjx.com/2017/11/23/gradle-plugin-3-0-0-migration/)
            matchingFallbacks = ['release']
        }
    }
}

the problem solve. But when config debuggable = ture, the error occur T_T.

YuanKJ- commented 5 years ago

I had the same problem

rosuH commented 4 years ago

@kkmike999 Toggled debuggable not help us. We convert a JSON string to List in our conditions. And then we got this error. But same code in other computers works fine.

public static <T> List<T> jsonToList(@NonNull String jsonStr) {
       try {
           List<T> objList = null;
           if (gson != null) {
               Type type = new TypeToken<List<T>>() {}.getType();
               objList = gson.fromJson(jsonStr, type);
           }
           return objList;
       }catch (Exception e){
           Log.i("json",e.getMessage());
           return null;
       }
 }

We tried below code to fix it by specified a type.

public static <T> List<T> jsonToList(@NonNull String json, Class<T> cls) {
        try {
            Gson gson = new Gson();
            List<T> list = new ArrayList<T>();
            JsonArray array = new JsonParser().parse(json).getAsJsonArray();
            for(final JsonElement elem : array){
                list.add(gson.fromJson(elem, cls));
            }
            return list;
        }catch (Exception e){
            Log.i("json",e.getMessage());
            return null;
        }
    }

Maybe it was compiled issue, hope it help.


Just using Gson in Retrofit converter:

api 'com.squareup.retrofit2:converter-gson:2.4.0'
Android Studio 3.6.1
Build #AI-192.7142.36.36.6241897, built on February 27, 2020
Runtime version: 1.8.0_212-release-1586-b04 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0
GC: ParNew, ConcurrentMarkSweep
Memory: 1979M
Cores: 12
Registry: ide.new.welcome.screen.force=true
Non-Bundled Plugins: String Manipulation, com.dengzii.plugin.adb, com.genymotion.idea, com.mfwebstudio.atomonedark.plugin.id, com.vermouthx.idea, net.seesharpsoft.intellij.plugins.file-preview, net.vektah.codeglance, cn.yiiguxing.plugin.translate, izhangzhihao.rainbow.brackets, BashSupport, com.developerphil.adbidea, some.awesome
lyubomyr-shaydariv commented 4 years ago

@rosuH No need to have it such complex. You can simply create a method like this:

public static <T> List<T> fromJsonToList(final String json, final Class<T> elementClass) {
    return gson.fromJson(json, TypeToken.getParameterized(List.class, elementClass).getType());
}

that will do the job. I'd only recommend this method if you provide the element types dynamically, not statically (also note that gson can be re-used, no need to new it). However, I believe you only need something like this:

private static final TypeToken<List<Short>> listOfShorts = new TypeToken<List<Short>>() {};
private static final TypeToken<List<Float>> listOfFloats = new TypeToken<List<Float>>() {};

public static void main(final String... args) {
    final String json = "[1,2,3,4,5,6]";
    System.out.println(gson.<List<Short>>fromJson(json, listOfShorts.getType()));
    System.out.println(gson.<List<Float>>fromJson(json, listOfFloats.getType()));
}

that would produce [1, 2, 3, 4, 5, 6] and [1.0, 2.0, 3.0, 4.0, 5.0, 6.0] respectively. It is a little more verbose, but you don't need to implement custom methods, and you can reuse type tokens too.

Marcono1234 commented 3 months ago

Could you please test if you still experience this AssertionError with the latest Gson version? And if that is the case, does that only occur on a real Android device (if so, which Android version and which device) or does it also occur for an Android emulator, in unit tests or even with a JDK?