Java Type Generic as Argument for GSON

前端 未结 13 1703
陌清茗
陌清茗 2020-11-27 12:51

In GSON to get a list of objects you do

Gson gson = new Gson();
Type token = new TypeToken>(){}.getType();
return gson.fromJson(json         


        
相关标签:
13条回答
  • 2020-11-27 13:28

    I've taken Raffaele's approach one step further and generified the class, so that it works with every class A, where B is a non-parameterized class. Might be useful for Sets and other Collections.

        public class GenericOf<X, Y> implements ParameterizedType {
    
        private final Class<X> container;
        private final Class<Y> wrapped;
    
        public GenericOf(Class<X> container, Class<Y> wrapped) {
            this.container = container;
            this.wrapped = wrapped;
        }
    
        public Type[] getActualTypeArguments() {
            return new Type[]{wrapped};
        }
    
        public Type getRawType() {
            return container;
        }
    
        public Type getOwnerType() {
            return null;
        }
    
    }
    
    0 讨论(0)
  • 2020-11-27 13:31

    In Kotlin you can simply use this function:

    inline fun <reified T> fromJson(json: String): T {
      return Gson().fromJson(json, object: TypeToken<T>(){}.type)
    }
    

    and use it like

    val myTypes: List<MyType> = fromJson(jsonString);
    

    It will parse any object including gereric types as List. Keyword inline and reified ensures that type will not be erased.

    For detail info I can recommend this Medium post

    0 讨论(0)
  • 2020-11-27 13:31

    In kotlin simple use for example:

    Get places function

    fun getPlaces<T> (jsonString : String, clazz: Class<T>) : T { val places : T = Gson().fromJson(jsonString,clazz) return places }

    Then you can use as:

    val places = getPlaces(Array<Place>::class.java)
    
    0 讨论(0)
  • 2020-11-27 13:32
    public <T> List<T> fromJSonList(String json) {
      Gson gson = new Gson();
      Type collectionType = new TypeToken<List<T>>(){}.getType();
      return gson.fromJson(json, collectionType);
    }
    
    //Just call
    List<MyType> myTypes = parser.<MyType>fromJSonList(jsonString);
    
    0 讨论(0)
  • 2020-11-27 13:35

    Generics work at compile-time. The reason super-type tokens work, is because (anonymous) inner classes can access the type arguments to their generic superclasses (superinterfaces), which in turn are stored directly in the bytecode metadata.

    Once your .java source file is compiled, the type parameter <T> is obviously thrown away. Since it is not known at compile time, it cannot be stored in bytecode, so it's erased and Gson can't read it.

    UPDATE

    After newacct's answer, I tried to implement what he suggested in his option 2, ie implementing a ParameterizedType. The code looks like this (here is a basic test):

    class ListOfSomething<X> implements ParameterizedType {
    
        private Class<?> wrapped;
    
        public ListOfSomething(Class<X> wrapped) {
            this.wrapped = wrapped;
        }
    
        public Type[] getActualTypeArguments() {
            return new Type[] {wrapped};
        }
    
        public Type getRawType() {
            return List.class;
        }
    
        public Type getOwnerType() {
            return null;
        }
    
    }
    

    the purpose of this code, is to be used inside getFromJsonList():

    public List<T> fromJsonList(String json, Class<T> klass) {
        Gson gson = new Gson();
        return gson.fromJson(json, new ListOfSomething<T>(klass));
    }
    

    Even if the technique works and is indeed very clever (I didn't know it and I would have never thinked of it), this is the final accomplishment:

    List<Integer> list = new Factory<Integer>()
             .getFromJsonList(text, Integer.class)
    

    instead of

    List<Integer> list = new Gson().fromJson(text,
             new TypeToken<List<Integer>>(){}.getType());
    

    To me, all this wrapping in useless, even if I agree that TypeTokens make the code look nasty :P

    0 讨论(0)
  • 2020-11-27 13:35

    Kotlin "ListOfSomething" solution that worked for me:

    fun <T: Any> getGsonList(json: String, kclass: KClass<T>) : List<T> {
    
        return getGsonInstance().fromJson<List<T>>(json, ListOfSomething<T>(kclass.java))
    }
    
    
    internal class ListOfSomething<X>(wrapped: Class<X>) : ParameterizedType {
    
        private val wrapped: Class<*>
    
        init {
            this.wrapped = wrapped
        }
    
        override fun getActualTypeArguments(): Array<Type> {
            return arrayOf<Type>(wrapped)
        }
    
        override fun getRawType(): Type {
            return ArrayList::class.java
        }
    
        override fun getOwnerType(): Type? {
            return null
        }
    }
    
    0 讨论(0)
提交回复
热议问题