且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Java类型作为GSON的参数

更新时间:2022-10-16 17:19:06

泛型在编译时工作。超类型标记工作的原因是因为(匿名)内部类可以访问它们的通用超类(超接口)的类型参数,而超类接口则直接存储在字节码元数据中。



编译.java源文件后,类型参数< T> 显然会被丢弃。由于在编译时不知道它,因此它不能存储在字节码中,所以它被擦除,Gson无法读取它。



更新

在newacct的回答后,我试图实现他在他的选项2中提出的建议,即实现 ParameterizedType 。代码如下所示(这里是基本的测试):

  class ListOfSomething< X>实现ParameterizedType {

private Class<?>包裹;

public ListOfSomething(Class< X> wrap){
this.wrapped = wrapped;
}

public Type [] getActualTypeArguments(){
return new Type [] {wrapped};
}

public Type getRawType(){
return List.class;
}

public Type getOwnerType(){
return null;
}

}

这段代码的目的是在> getFromJsonList()中使用:

  public List< T> fromJsonList(String json,Class< T> klass){
Gson gson = new Gson();
return gson.fromJson(json,new ListOfSomething< T>(klass));
}

即使这项技术有效,确实非常聪明(我不知道它和我从未想过它),这是最后的成就:

  List< Integer> list = new Factory< Integer>()
.getFromJsonList(text,Integer.class)

而不是

 列表<整数> fromJson(text,
new TypeToken< List< Integer>>(){}。getType());

对我来说,即使我同意 TypeToken s让代码看起来很讨厌:P

In GSON to get a list of objects you do

Gson gson = new Gson();
Type token = new TypeToken<List<MyType>>(){}.getType();
return gson.fromJson(json, token);

It works great, but I want to go further and have MyType parametrized so I can have a common function to parse list of objects with this code

// the common function 
public <T> List<T> fromJSonList(String json, Class<T> type) {
  Gson gson = new Gson();
  Type collectionType = new TypeToken<List<T>>(){}.getType();
  return gson.fromJson(json, collectionType);
}

// the call
List<MyType> myTypes = parser.fromJSonList(jsonString, MyType.class);

Sadly returns an array of StringMaps, not the type. T is being interpreted as another generic type, not my type. Any workaround ?

Generics work at compile-time. The reason super-type tokens work, is because (anonymous) inner classes can access the type arguments to their generic superclasses (superinterfaces), which in turn are stored directly in the bytecode metadata.

Once your .java source file is compiled, the type parameter <T> is obviously thrown away. Since it is not known at compile time, it cannot be stored in bytecode, so it's erased and Gson can't read it.

UPDATE

After newacct's answer, I tried to implement what he suggested in his option 2, ie implementing a ParameterizedType. The code looks like this (here is a basic test):

class ListOfSomething<X> implements ParameterizedType {

    private Class<?> wrapped;

    public ListOfSomething(Class<X> wrapped) {
        this.wrapped = wrapped;
    }

    public Type[] getActualTypeArguments() {
        return new Type[] {wrapped};
    }

    public Type getRawType() {
        return List.class;
    }

    public Type getOwnerType() {
        return null;
    }

}

the purpose of this code, is to be used inside getFromJsonList():

public List<T> fromJsonList(String json, Class<T> klass) {
    Gson gson = new Gson();
    return gson.fromJson(json, new ListOfSomething<T>(klass));
}

Even if the technique works and is indeed very clever (I didn't know it and I would have never thinked of it), this is the final accomplishment:

List<Integer> list = new Factory<Integer>()
         .getFromJsonList(text, Integer.class)

instead of

List<Integer> list = new Gson().fromJson(text,
         new TypeToken<List<Integer>>(){}.getType());

To me, all this wrapping in useless, even if I agree that TypeTokens make the code look nasty :P