Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Gson从反射字段类型解析泛型列表_Java_List_Generics_Serialization_Gson - Fatal编程技术网

Java 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(

我在将列表类型从反射对象转换为该对象的set方法时遇到问题

我不确定问题是在前端还是在Gson解析端,但我的测试代码如下:

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
    new-TypeToken
    ——在这种情况下,编译器可以基于已知类型生成适当的superlcass参数化。这些类型用于类型标记中<代码>在编译时未知。在运行时检查它:
    System.out.println(newTypeToken(){}.getType())--输出为
    T
    。什么是
    T
    ?只是一个通配符,不是真正的类型
  • 您必须了解类型标记的用途:如果存在类似于
    List.type
    (非法且不是
    .class
    !)的东西,那么它们只是Java支持的一种便捷方式。类型标记只分析其参数化是返回的
    Type
    实例,这些实例可能是
    parameteredType
    实例。此外,您可以创建自己的
    ParameterizedType
    ,而不使用类型标记,因为这些只是定义一些getter的接口。因此,为了动态构建类型令牌:
    • 如果您使用的是Gson 2.8.0,请使用
      TypeToken.getParameterized(List.class,elementType).getType()
    • 如果您有一个较旧的Gson版本,或者希望尽可能多地控制它,只需自己创建并返回一个
      ParameterizedType
      实例:
新参数化类型(){
@重写公共类型getRawType(){return List.class;}
@重写公共类型[]getActualTypeArguments(){返回新类型[]{elementType};}
@重写公共类型getOwnerType(){return null;}
}
非常自我描述,不是吗

  • 为什么Gson返回的是
    Double
    s而不是
    Long
    s?Gson使用通配符
    ,使用默认策略,就好像类型完全未知一样:默认情况下,所有数字都使用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
    new-TypeToken
    ——在这种情况下,编译器可以基于已知类型生成适当的superlcass参数化。这些类型用于类型标记中<代码>
    在编译时未知。在运行时检查它:
    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);
    }