Deserialise a generic list in Gson

后端 未结 2 402
隐瞒了意图╮
隐瞒了意图╮ 2020-12-06 07:30

I want to write a generic function which deserialise a generic type List with Gson here is the code:

private  List GetListFromFile(String f         


        
相关标签:
2条回答
  • 2020-12-06 08:13

    There is no way to do it without passing actual type of T (as Class<T>) to your method.

    But if you pass it explicitly, you can create a TypeToken for List<T> as follows:

    private <T> List<T> GetListFromFile(String filename, Class<T> elementType) {
        ...
        TypeToken<ArrayList<T>> token = new TypeToken<ArrayList<T>>() {};
        List<T> something = gson.fromJson(data, token.getType());
        ...
    }
    

    See also:

    • TypeToken
    0 讨论(0)
  • 2020-12-06 08:14

    The approach of use TypeToken won't work.

    new TypeToken<ArrayList<T>>() 
    

    is not possible because of how generics (type erasure) and reflection works. The whole TypeToken hack works because Class#getGenericSuperclass() does the following

    Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by this Class.

    If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code.

    In other words, if it sees ArrayList<T>, that's the ParameterizedType it will return and you won't be able to extract the compile time value that the type variable T would have had.

    Type and ParameterizedType are both interfaces. You can provide an instance of your own implementation.

    So, you have two options:

    Option 1: implement java.lang.reflect.ParameterizedType yourself and pass it to Gson.

    private static class ListParameterizedType implements ParameterizedType {
    
        private Type type;
    
        public 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)
    }
    

    Then simply:

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

    Note that as per javadoc, equals method should also be implemented.

    Option 2: Parse the list manually and then for each element use Gson

    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);
        }
    }
    
    0 讨论(0)
提交回复
热议问题