Java 具有动态ArrayList项类型的Gson TypeToken

Java 具有动态ArrayList项类型的Gson TypeToken,java,reflection,arraylist,gson,Java,Reflection,Arraylist,Gson,我有以下代码: Type typeOfObjectsList = new TypeToken<ArrayList<myClass>>() {}.getType(); List<myClass> objectsList = new Gson().fromJson(json, typeOfObjectsList); 但它不起作用。这是一个例外: java.sql.SQLException: Fail to convert to internal represen

我有以下代码:

Type typeOfObjectsList = new TypeToken<ArrayList<myClass>>() {}.getType();
List<myClass> objectsList = new Gson().fromJson(json, typeOfObjectsList);
但它不起作用。这是一个例外:

java.sql.SQLException: Fail to convert to internal representation: {....my json....}

您建议的语法无效。以下

new TypeToken<ArrayList<Class.forName(MyClass)>>
new TypeToken<ArrayList<T>>() 
newtypetoken
无效,因为您正在尝试传递一个需要类型名的方法调用

以下

new TypeToken<ArrayList<Class.forName(MyClass)>>
new TypeToken<ArrayList<T>>() 
newtypetoken()
这是不可能的,因为泛型(类型擦除)和反射是如何工作的。整个
TypeToken
hack是有效的,因为
Class#getGenericSuperclass()
执行以下操作

new TypeToken<ArrayList<Class.forName(MyClass)>>
new TypeToken<ArrayList<T>>() 
返回表示实体的直接超类的类型 (类、接口、基元类型或void)由该类表示

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

换句话说,如果它看到
ArrayList
,它将返回
参数化类型
,并且您将无法提取类型变量
t
将具有的编译时值

类型
参数化类型
都是接口。您可以提供自己实现的实例。

这对我很有用:

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);
    }
}
公共列表列表(类clazz)
抛出WSE异常{
试一试{
//消费远程方法
字符串strJson=getService().listEntity(clazz.getName());
JsonParser=新的JsonParser();
JsonArray数组=parser.parse(strJson.getAsJsonArray();
List lst=new ArrayList();
for(最终JsonElement json:array){
T entity=GSON.fromJson(json,clazz);
lst.add(实体);
}
返回lst;
}捕获(例外e){
抛出新的WSE异常(
“WS-method错误[Listenty()]”,e);
}
}

选项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)
}
然后简单地说:

Type type = new ListParameterizedType(clazz);
List<T> list = gson.fromJson(json, type);

你真的可以做到。您只需首先将数据解析为
JsonArray
,然后分别转换每个对象,并将其添加到
列表中:

Class<T> dataType;

//...

JsonElement root = jsonParser.parse(json);
List<T> data = new ArrayList<>();
JsonArray rootArray = root.getAsJsonArray();
for (JsonElement json : rootArray) {
    try {
        data.add(gson.fromJson(json, dataType));
    } catch (Exception e) {
        e.printStackTrace();
    }
}
return data;
类数据类型;
//...
JsonElement root=jsonParser.parse(json);
列表数据=新的ArrayList();
JsonArray rootArray=root.getAsJsonArray();
for(JsonElement json:rootArray){
试一试{
data.add(gson.fromJson(json,数据类型));
}捕获(例外e){
e、 printStackTrace();
}
}
返回数据;

sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
工作。不需要自定义实现

Type type = ParameterizedTypeImpl.make(List.class, new Type[]{childrenClazz}, null);
List list = gson.fromJson(json, type);
可用于地图和任何其他收藏:

ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, childrenClazz}, null);
以下是如何在自定义反序列化程序中使用它的演示:

您可以使用番石榴的更强大功能:

私有静态类型setModelAndGetCorrespondingList2(类类型){
返回新的TypeToken(){}
.where(新类型参数(){},类型)
.getType();
}

自从Gson 2.8.0以来,您可以使用创建
TypeToken
,然后
getType()
应该完成这个任务

例如:

TypeToken.getParameterized(ArrayList.class, myClass).getType()

完全有效的解决方案:

String json = .... //example: mPrefs.getString("list", "");
ArrayList<YouClassName> myTypes = fromJSonList(json, YouClassName.class);


public <YouClassName> ArrayList<YouClassName> fromJSonList(String json, Class<YouClassName> type) {
        Gson gson = new Gson();
        return gson.fromJson(json, TypeToken.getParameterized(ArrayList.class, type).getType());
    }
stringjson=//示例:mPrefs.getString(“list”,即“”);
ArrayList myTypes=fromJSonList(json,YouClassName.class);
公共ArrayList fromJSonList(字符串json,类类型){
Gson Gson=新的Gson();
返回gson.fromJson(json,TypeToken.getParameterized(ArrayList.class,type).getType());
}
使用kotlin,您可以使用以下函数在一行中转换(从/到)任何(JsonArray/JsonObject),而无需发送TypeToken:- 将任何类或数组转换为JSON字符串 将JSON字符串转换为任何类或数组
inline fun String?.fromJson():T?=这个?让我来{
val type=object:TypeToken(){}.type
Gson().fromJson(此类型)
}
要使用的示例:

val jsonArrayAsString=“[\'1\'、\'2\'、\'3\'”
val list=jsonArrayAsString.fromJson()
val jsonObjectAsString=“{”name:“示例”,“电子邮件”:”t@t.com"}"
val型号:Foo?=jsonObjectAsString.fromJson()
//或
val model=jsonObjectAsString.fromJson()
在kotlin中,您可以

inline fun <reified T> parseData(row :String): T{
   return Gson().fromJson(row, object: TypeToken<T>(){}.type)
}
内联数据(行:字符串):T{
返回Gson().fromJson(行,对象:TypeToken(){}.type)
}

事实上,我制作了一些扩展函数来解决这个问题,将列表保存到SharedReference,并在应用程序中的任何位置检索它们,如下所示:

fun Context.getList(key: String): String? {
 return getSharedPrefrences(App.getAppContext() as Application).getString(key, null)}

inline fun <reified T : Any> String?.fromJson(): T? = this?.let {
val type = object : TypeToken<T>() {}.type
Gson().fromJson(this, type)}
使用此选项将列表保存到SharedRef。例如:

fun <T> SaveList(key: String?, list: List<T>?) {
val gson = Gson()
val json: String = gson.toJson(list)
getSharedPrefrences(App.getAppContext() as Application).edit().putString(key, json).apply()}
fun存储列表(键:String?,列表:list?){
val gson=gson()
val json:String=gson.toJson(列表)
GetSharedReferences(App.getAppContext()作为应用程序).edit().putString(键,json).apply()}
从SharedRef返回任意位置的列表。像这样:

fun Context.getList(key: String): String? {
 return getSharedPrefrences(App.getAppContext() as Application).getString(key, null)}

inline fun <reified T : Any> String?.fromJson(): T? = this?.let {
val type = object : TypeToken<T>() {}.type
Gson().fromJson(this, type)}
fun Context.getList(key:String):String?{
返回getSharedReferences(App.getAppContext()作为应用程序).getString(key,null)}
内联有趣字符串?.fromJson():T?=这个?让我来{
val type=object:TypeToken(){}.type
Gson().fromJson(this,type)}
从已保存列表中保存和获取列表的用法如下:

saveList(Consts.SLIDERS, it.data)  

SetSliderData(this.getList(Consts.SLIDERS).fromJson<MutableList<SliderResponseItem>>()!!)
saveList(常量滑块、it.data)
SetSliderData(this.getList(Consts.SLIDERS).fromJson()!!)

这是一个SQLException。这与你发布的代码无关。给我们看看JDBC代码。@SotiriosDelimanolis它不是!我只想让
TypeToken()
code接受动态Arraylist类型。类似这样的事情:
TypeToken
我认为这是可能的,使用这里显示的技术:@BenoitDuffez小心。你链接的答案是做一些不同的事情。它使用了一个实际的
对象,因此Gson可以非常清楚地知道反序列化到什么类型。在OP的问题中,他们不想使用
对象,只想通过type参数来实现,而type参数在方法本身中不可用。@SotiriosDelimanolis:你完全正确。我以为把这个班
fun Context.getList(key: String): String? {
 return getSharedPrefrences(App.getAppContext() as Application).getString(key, null)}

inline fun <reified T : Any> String?.fromJson(): T? = this?.let {
val type = object : TypeToken<T>() {}.type
Gson().fromJson(this, type)}
saveList(Consts.SLIDERS, it.data)  

SetSliderData(this.getList(Consts.SLIDERS).fromJson<MutableList<SliderResponseItem>>()!!)