Java Gson从反射字段类型解析泛型列表
我在将列表类型从反射对象转换为该对象的set方法时遇到问题 我不确定问题是在前端还是在Gson解析端,但我的测试代码如下:Java Gson从反射字段类型解析泛型列表,java,list,generics,serialization,gson,Java,List,Generics,Serialization,Gson,我在将列表类型从反射对象转换为该对象的set方法时遇到问题 我不确定问题是在前端还是在Gson解析端,但我的测试代码如下: public static void main(String[] args) throws Exception{ String json = "[52881]"; ListObject lo = new ListObject(); for(Field f : lo.getClass().getDeclaredFields()) if(
public static void main(String[] args) throws Exception{
String json = "[52881]";
ListObject lo = new ListObject();
for(Field f : lo.getClass().getDeclaredFields())
if(List.class.isAssignableFrom(f.getType())){
Method m = lo.getClass().getMethod(
new StringBuilder("set").append(f.getName().substring(0,1).toUpperCase()).append(f.getName().substring(1,f.getName().length())).toString(),
f.getType()
);
System.out.println(((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0]);
getListFromJson(m, lo, json,
((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0].getClass());
}
ListObject p = (ListObject) lo;
System.out.println(gson.toJson(p.getAList()));
for(long pid : p.getAList()){
System.out.println(pid);
}
}
@SuppressWarnings("unchecked")
public static <T> void getListFromJson(Method m, Object target, String json, Class<T> elementType) throws Exception {
m.invoke(target, (List<T>)gson.fromJson(json, new TypeToken<List<T>>(){}.getType()));
}
我在这里将这个答案用于getList方法:
这是因为Java泛型是如何实现的:
只能存在于编译器的头脑中或类文件元数据中。让我们仔细地看一看并做一个简短的分析:
@SuppressWarnings(“未选中”)
公共静态void getListFromJson(方法m、对象目标、字符串json、类elementType)引发异常{
m、 调用(target,(List)gson.fromJson(json,newTypeToken(){}.getType());
}
- 由于Java泛型的限制,
根本不在这里播放。这只是试图对该方法设置一些通用限制,但如果删除该参数,则不会有任何更改。此外,Class elementType
只能保存原始类型,即使您使用未选中的强制转换使Class
保存类似于Class
的内容,您仍然会获得最顶部的原始类型List
,并且您可以删除该参数(但是,对于下面描述的场景,请保留该参数)List
- 类型标记基于JVM允许存储超类参数化的事实。您可能会注意到,类型标记是使用编译时已知的类型参数进行参数化的:
或new-TypeToken
——在这种情况下,编译器可以基于已知类型生成适当的superlcass参数化。这些类型用于类型标记中<代码>在编译时未知。在运行时检查它:new-TypeToken
System.out.println(newTypeToken(){}.getType())代码>--输出为
。什么是T
?只是一个通配符,不是真正的类型T
- 您必须了解类型标记的用途:如果存在类似于
(非法且不是List.type
!)的东西,那么它们只是Java支持的一种便捷方式。类型标记只分析其参数化是返回的.class
实例,这些实例可能是Type
实例。此外,您可以创建自己的parameteredType
,而不使用类型标记,因为这些只是定义一些getter的接口。因此,为了动态构建类型令牌:ParameterizedType
- 如果您使用的是Gson 2.8.0,请使用
李>TypeToken.getParameterized(List.class,elementType).getType()
- 如果您有一个较旧的Gson版本,或者希望尽可能多地控制它,只需自己创建并返回一个
实例:ParameterizedType
- 如果您使用的是Gson 2.8.0,请使用
新参数化类型(){
@重写公共类型getRawType(){return List.class;}
@重写公共类型[]getActualTypeArguments(){返回新类型[]{elementType};}
@重写公共类型getOwnerType(){return null;}
}
非常自我描述,不是吗
- 为什么Gson返回的是
s而不是Double
s?Gson使用通配符Long
,使用默认策略,就好像类型完全未知一样:默认情况下,所有数字都使用double,因为它们可以保留所有标准的Java数值。这就是为什么当您仅取消引用列表元素(但不取消引用列表——局部变量不存在类型参数)时会出现强制转换异常
static <T> void getListFromJson(final Method method, final Object target, final String json, final Type elementType)
throws InvocationTargetException, IllegalAccessException {
final List<T> ts = gson.fromJson(json, TypeToken.getParameterized(List.class, elementType).getType());
method.invoke(target, ts);
}
static void getListFromJson(final方法、final对象目标、final字符串json、final类型elementType)
抛出InvocationTargetException,IllegalAccessException{
最终列表ts=gson.fromJson(json,TypeToken.getParameterized(List.class,elementType).getType());
调用(目标,ts);
}
请注意,现在elementType
参数开始玩游戏,类型标记用于创建parameteredType
实例,Gson现在可以对使用elementType
定义的类型使用反序列化策略(在该位置为Long
)
输出:
类java.lang.Long[52881]
52881
这是因为Java泛型是如何实现的:
只能存在于编译器的头脑中或类文件元数据中。让我们仔细地看一看并做一个简短的分析:
@SuppressWarnings(“未选中”)
公共静态void getListFromJson(方法m、对象目标、字符串json、类elementType)引发异常{
m、 调用(target,(List)gson.fromJson(json,newTypeToken(){}.getType());
}
- 由于Java泛型的限制,
根本不在这里播放。这只是试图对该方法设置一些通用限制,但如果删除该参数,则不会有任何更改。此外,Class elementType
只能保存原始类型,即使您使用未选中的强制转换使Class
保存类似于Class
的内容,您仍然会获得最顶部的原始类型List
,并且您可以删除该参数(但是,对于下面描述的场景,请保留该参数)List
- 类型标记基于JVM允许存储超类参数化的事实。您可能会注意到,类型标记是使用编译时已知的类型参数进行参数化的:
或new-TypeToken
——在这种情况下,编译器可以基于已知类型生成适当的superlcass参数化。这些类型用于类型标记中<代码>在编译时未知。在运行时检查它:new-TypeToken
System.out.println(newTypeToken(){}.getType())代码>--输出为
。什么是T
?只是一个通配符,不是真正的类型T
- 您必须了解类型标记的用途:它们只是一种方便的方式,可以实现J
for(long pid : p.getAList()){
static <T> void getListFromJson(final Method method, final Object target, final String json, final Type elementType) throws InvocationTargetException, IllegalAccessException { final List<T> ts = gson.fromJson(json, TypeToken.getParameterized(List.class, elementType).getType()); method.invoke(target, ts); }