shau-lok / google-gson

Automatically exported from code.google.com/p/google-gson
0 stars 0 forks source link

Alternative API for deserializing a generic object #265

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
I'm using the following code for deserializing a generic object like 
List<String>

The syntax becomes:
List<String> list = deserialize(json, List.class, String.class); 
Map<String, List<Integer>> map = deserialize(json, Map.class, String.class, 
List.class, Integer.class);

which is (arguably) cleaner compared to the TypeToken.

    public static <T> T deserialize(String string, Class<?> clazz, Class<?>... argsArr) {
        Type t = getType(clazz, new ArrayList<Class<?>>(Arrays.asList(argsArr)));
        return new Gson().fromJson(string, t);
    }

    private static Type getType(Class<?> clazz, List<Class<?>> args) {
        if (clazz.getTypeParameters().length == 0) {
            return clazz;
        }

        List<Type> types = new ArrayList<Type>();
        for (int n = 0; n < clazz.getTypeParameters().length; ++n) {
            types.add(getType(args.remove(0), args));
        }
        return new PT(clazz, types);
    }

    private static class PT implements ParameterizedType {

        private Class<?> type;
        private Type[] typeArgs;

        public PT(Class<?> type, List<Type> typeArgs) {
            this.type = type;
            this.typeArgs = typeArgs.toArray(new Type[0]);
        }

        @Override
        public Type[] getActualTypeArguments() {
            return typeArgs;
        }

        @Override
        public Type getOwnerType() {
            return type.getDeclaringClass();
        }

        @Override
        public Type getRawType() {
            return type;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null || obj.getClass() != PT.class) {
                return false;
            }
            PT other = (PT) obj;
            return type == other.type && Arrays.equals(typeArgs, other.typeArgs);
        }
    }

Original issue reported on code.google.com by goo...@boast.nl on 19 Nov 2010 at 10:16

GoogleCodeExporter commented 9 years ago
Thanks for sharing your thoughts. It is an interesting approach, and works well 
for your List<String> example. On the other hand, it is not descriptive enough 
for your Map example. What if it was a Map<K1<K2<K3<K4>>>, V1<V2>>? How would 
you know where the key description ends and the value description starts? 

Gson API is better off leaving the type construction out of its scope. 
In Gson 1.7, we are borrowing Types class from Guice that lets you create 
arbitrarily complex parameterized types on the fly. Checkout the latest code or 
stay tuned for our public 1.7 release.

Original comment by inder123 on 31 Jan 2011 at 11:31

GoogleCodeExporter commented 9 years ago
Your Map example would work equally well. The function #getType() is recursive: 
it checks how many generic types a class expects and then walks this tree depth 
first. 

You would simply specify it in the same order like you define it: (Map, K1, K2, 
K3, K4, V1, V2). Where the key description ends is obtained from the actual 
class files (class.getTypeParameters().length). As long as nobody invents 
variable generics your safe :)

Original comment by goo...@boast.nl on 1 Feb 2011 at 10:56