【问题标题】:Get Type of ParameterizedType from generic从泛型获取 ParameterizedType 的类型
【发布时间】:2016-05-12 07:11:51
【问题描述】:

我无法完全理解反射的工作原理,因此在尝试为我的 GsonBuilder 注册自定义类型适配器时遇到了一些麻烦。

我需要为List<Something> 类型注册一个类型适配器。

这是一个有效的代码:

    gsonBuilder.registerTypeAdapter(
            new TypeToken<List<MyClass>>() { }.getType(), new ListDeserializer(MyClass.class)
    );

问题是我有很多类来注册我的类型适配器,并且我有一个 ListDeserializerSingleDeserializer 适配器。

我正在尝试通用,所以我只调用一个函数,传递我的GsonBuilder 和类,然后就可以了。

这是我的尝试:

private static <T> void registerTypeAdapter(GsonBuilder gsonBuilder, T clazz) {
    gsonBuilder.registerTypeAdapter(clazz.getClass(), new SingleDeserializer(clazz.getClass()));
    gsonBuilder.registerTypeAdapter(
            new TypeToken<List<T>>() {
            }.getType(), new ListDeserializer(clazz.getClass())
    );
}

它不适用于我的ListDeserializer。我的猜测是,由于TList 的泛型参数化类型,它无法在运行时检测到它。

有什么建议吗?

【问题讨论】:

    标签: java android generics gson


    【解决方案1】:

    是的,你不能在运行时使用new TypeToken&lt;List&lt;T&gt;&gt;() {}.getType(),因为泛型type erasureList&lt;T&gt; 在运行时只是 List&lt;Object&gt;。但你可以做的是创建ParameterizedType 并使用这样的东西:

    Type type = ParameterizedTypeImpl.make(List.class, new Type[]{clazz.getClass()}, null);
    gsonBuilder.registerTypeAdapter(type, new ListDeserializer(clazz.getClass()) );
    

    但是你真的需要泛型吗?你可以这样做

    private static void registerTypeAdapter2(GsonBuilder gsonBuilder, Class<?> clazz) {
        gsonBuilder.registerTypeAdapter(clazz, new SingleDeserializer());
        Type type = ParameterizedTypeImpl.make(List.class, new Type[]{clazz}, null);
        gsonBuilder.registerTypeAdapter(type, new ListDeserializer());
    }
    

    这里是演示:

    import com.google.gson.*;
    import com.google.gson.annotations.SerializedName;
    import com.google.gson.reflect.TypeToken;
    import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
    
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.ArrayList;
    import java.util.List;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            GsonBuilder gb = new GsonBuilder();
            registerTypeAdapter(gb, MyClass.class);
    
            Gson gson = gb.create();
            List data = new ArrayList<>();
            data.add(new MyClass("Bob"));
            data.add(new MyClass("Alice"));
    
            String listString = gson.toJson(data);
            String soloString = gson.toJson(new MyClass("Test"));
    
            Object resultList = gson.fromJson(listString, new TypeToken<List<MyClass>>() {}.getType());
            Object resultSolo = gson.fromJson(soloString, MyClass.class);
    
            System.out.println("RESULT:");
            System.out.println("FROM " + listString +" TO "+ resultList);
            System.out.println("FROM " + soloString +" TO "+ resultSolo);
    
        }
    
        private static void registerTypeAdapter(GsonBuilder gsonBuilder, Class<?> clazz) {
            gsonBuilder.registerTypeAdapter(clazz, new SingleDeserializer());
            Type type = ParameterizedTypeImpl.make(List.class, new Type[]{clazz}, null);
            gsonBuilder.registerTypeAdapter(type, new ListDeserializer());
        }
    
        private static class ListDeserializer implements JsonDeserializer {
            private static Gson gson = new Gson();
    
            @Override
            public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                System.out.println("Used ListDeserializer:  Type " + typeOfT);
    
                Type t = (typeOfT instanceof ParameterizedType) ?
                        ((ParameterizedType) typeOfT).getActualTypeArguments()[0] :
                        Object.class;
    
                Type type = ParameterizedTypeImpl.make(List.class, new Type[]{t}, null);
                List list = gson.fromJson(json, type);
                return list;
            }
        }
    
        private static class SingleDeserializer implements JsonDeserializer {
            private static Gson gson = new Gson();
    
            @Override
            public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                System.out.println("Used SingleDeserializer:  Type " + typeOfT);
                return gson.fromJson(json, typeOfT);
            }
        }
    
        public static class MyClass {
            @SerializedName("name")
            private String name;
    
            public MyClass(String name) {
                this.name = name;
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            @Override
            public String toString() {
                return "MyClass{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    }
    

    【讨论】:

    • 太棒了@varren!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多