具有动态ArrayList项类型的Gson TypeToken

Ami*_* Sh 68 java reflection arraylist gson

我有这个代码:

Type typeOfObjectsList = new TypeToken<ArrayList<myClass>>() {}.getType();
List<myClass> objectsList = new Gson().fromJson(json, typeOfObjectsList);
Run Code Online (Sandbox Code Playgroud)

它将JSON字符串转换List为对象.但是现在我希望在运行时定义ArrayList动态类型(不仅仅是myClass).

所述ArrayList的项目类型将与被定义反射.

我试过这个:

    private <T> Type setModelAndGetCorrespondingList2(Class<T> type) {
        Type typeOfObjectsListNew = new TypeToken<ArrayList<T>>() {}.getType();
        return typeOfObjectsListNew;
    }
Run Code Online (Sandbox Code Playgroud)

但它不起作用.这是例外:

java.sql.SQLException: Fail to convert to internal representation: {....my json....}
Run Code Online (Sandbox Code Playgroud)

old*_*god 49

既然Gson 2.8.0,你可以TypeToken#getParameterized(Type rawType, Type... typeArguments)用来创建TypeToken,那么getType()应该做的伎俩.

例如:

TypeToken.getParameterized(ArrayList.class, myClass).getType()
Run Code Online (Sandbox Code Playgroud)


Sot*_*lis 44

您提出的语法无效.下列

new TypeToken<ArrayList<Class.forName(MyClass)>>
Run Code Online (Sandbox Code Playgroud)

因为您尝试传递期望类型名称的方法调用,因此无效.

下列

new TypeToken<ArrayList<T>>() 
Run Code Online (Sandbox Code Playgroud)

由于泛型(类型擦除)和反射如何工作,因此是不可能的.整个TypeToken黑客的工作原理是因为Class#getGenericSuperclass()以下内容

返回表示此Class表示的实体(类,接口,基本类型或void)的直接超类的Type.

如果超类是参数化类型,则返回的Type对象必须准确反映源代码中使用的实际类型参数.

换句话说,如果它看到ArrayList<T>,ParameterizedType它将返回,并且您将无法提取类型变量T将具有的编译时间值.

Type并且ParameterizedType都是接口.您可以提供自己实现的实例.

  • @BenoitDuffez小心翼翼.你联系的答案是做一些不同的事情.它使用的是一个实际的`Class`对象,因此Gson可以很好地知道要反序列化的类型.在OP的问题中,他们希望不使用`Class`对象并且只通过类型参数来实现,而类型参数在方法本身中是不可用的. (2认同)

小智 29

选项1 - 实现java.lang.reflect.ParameterizedType自己并将其传递给Gson.

private static class ListParameterizedType implements ParameterizedType {

    private Type type;

    private ListParameterizedType(Type type) {
        this.type = type;
    }

    @Override
    public Type[] getActualTypeArguments() {
        return new Type[] {type};
    }

    @Override
    public Type getRawType() {
        return ArrayList.class;
    }

    @Override
    public Type getOwnerType() {
        return null;
    }

    // implement equals method too! (as per javadoc)
}
Run Code Online (Sandbox Code Playgroud)

那简单地说:

Type type = new ListParameterizedType(clazz);
List<T> list = gson.fromJson(json, type);
Run Code Online (Sandbox Code Playgroud)

请注意,根据javadoc,还应实现equals方法.

选项2 - (不要这样做)重用gson内部...

这也会起作用,至少与Gson 2.2.4一样.

Type type = com.google.gson.internal.$Gson$Types.newParameterizedTypeWithOwner(null, ArrayList.class, clazz);
Run Code Online (Sandbox Code Playgroud)


小智 7

这对我有用:

public <T> List<T> listEntity(Class<T> clazz)
        throws WsIntegracaoException {
    try {
        // Consuming remote method
        String strJson = getService().listEntity(clazz.getName());

        JsonParser parser = new JsonParser();
        JsonArray array = parser.parse(strJson).getAsJsonArray();

        List<T> lst =  new ArrayList<T>();
        for(final JsonElement json: array){
            T entity = GSON.fromJson(json, clazz);
            lst.add(entity);
        }

        return lst;

    } catch (Exception e) {
        throw new WsIntegracaoException(
                "WS method error [listEntity()]", e);
    }
}
Run Code Online (Sandbox Code Playgroud)


shm*_*sel 7

你可以用Guava更强大的方法做到这一点TypeToken:

private static <T> Type setModelAndGetCorrespondingList2(Class<T> type) {
    return new TypeToken<ArrayList<T>>() {}
            .where(new TypeParameter<T>() {}, type)
            .getType();
}
Run Code Online (Sandbox Code Playgroud)


var*_*ren 5

sun.reflect.generics.reflectiveObjects.ParameterizedTypeImplworkes.无需自定义实现

Type type = ParameterizedTypeImpl.make(List.class, new Type[]{childrenClazz}, null);
List list = gson.fromJson(json, type);
Run Code Online (Sandbox Code Playgroud)

可以与地图和任何其他集合一起使用:

ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, childrenClazz}, null);
Run Code Online (Sandbox Code Playgroud)

这是一个很好的演示如何在自定义反序列化器中使用它:使用Gson反序列 化ImmutableList


Ibr*_*mad 5

使用 kotlin,您可以使用以下函数在一行中转换(从/到)任何(JsonArray/JsonObject),而无需发送 TypeToken :-

将任何类或数组转换为 JSON 字符串

inline fun <reified T : Any> T?.json() = this?.let { Gson().toJson(this, T::class.java) }
Run Code Online (Sandbox Code Playgroud)

使用示例:

 val list = listOf("1","2","3")
 val jsonArrayAsString = list.json() 
 //output : ["1","2","3"]

 val model= Foo(name = "example",email = "t@t.com") 
 val jsonObjectAsString = model.json()
//output : {"name" : "example", "email" : "t@t.com"}
Run Code Online (Sandbox Code Playgroud)

将 JSON 字符串转换为任何类或数组

inline fun <reified T : Any> String?.fromJson(): T? = this?.let {
    val type = object : TypeToken<T>() {}.type
    Gson().fromJson(this, type)
}
Run Code Online (Sandbox Code Playgroud)

使用示例:

 val jsonArrayAsString = "[\"1\",\"2\",\"3\"]"
 val list = jsonArrayAsString.fromJson<List<String>>()

 val jsonObjectAsString = "{ "name" : "example", "email" : "t@t.com"}"
 val model : Foo? = jsonObjectAsString.fromJson() 
 //or 
 val model = jsonObjectAsString.fromJson<Foo>() 
Run Code Online (Sandbox Code Playgroud)