Author: kidou @ criminal for reprint need to retain the author information in the obvious position, and links to the original If the blog is not appropriate welcome message communication www.jianshu.com/p/d62c2be60…

Do you really know how to use Gson? In section 3 of the Gson Usage Guide (I), I explained how generics can be used in Gson to simplify our class design, but then introduced a new problem: encapsulation. New TypeToken

(){}; B: It’s troublesome. Is there a better way?

Is there a better way? B: of course! I believe that many people have made their own attempts, but some people are happy and others are worried, but it doesn’t matter, we will solve this problem today.

convention

1. The JSON format involved in this article

{"code":"0","message":"success","data":{}} // data is an array {"code":"0","message":"success","data":[]}Copy the code

Result > Result >

1. Why and how to encapsulate

1. Why encapsulate:
  • writenew TypeToken<XXX>(){}Trouble, IDE formatting is not good
  • A different place each timenew TypeToken<XXX>(){}Operations generate a new class
  • For any classXXXThere are only two casesnew TypeToken<Result<XXX>>(){}andnew TypeToken<Result<List<XXX>>>(){}
  • Convenient unified management
2, how to package

As can be seen from the above, the simplest method is to provide two methods corresponding to Array and Object respectively and receive a parameter, that is, tell the type of XXX. New TypeToken

(){} and new TypeToken

>>(){} are automatically completed.

Method prototype:

Public static <T> Result<T> fromJsonObject(Reader, Class<T> clazz) {} public static <T> Result<List<T>> fromJsonArray(Reader, Class<T> clazz){}Copy the code

Two, why failure?

For those of you who have tried to encapsulate it, you’ve probably written:

public static <T> Result<List<T>> fromJsonArray(Reader reader) {
    Type type = new TypeToken<Result<List<T>>>(){}.getType();
    return GSON.fromJson(reader, type);
}
Copy the code

T is a TypeVariable, and it does not change into the desired XXX when it is run. So the generic information obtained via TypeToken is just “Result >”.

Three, how to solve?

TypeToken is used to fetch a generic class, and the Type returned is Type. The real generic information is stored in this Type.

Type is the parent interface for all types in Java. Before 1.8, it was an empty interface. Since 1.8, getTypeName() has been added. ParameterizedType, GenericArrayType, WildcardType, TypeVariable, Class. Only ParameterizedType will be used for these interfaces during this encapsulation, so let’s be brief:

ParameterizedType is a type of type <>, for example, Map

. The following uses Map

as an example to illustrate the functions of each of these methods.
,user>
,user>

Public interface ParameterizedType extends Type {// Returns Map<String,User> So return [string.class, user.clas] Type[] getActualTypeArguments(); // Map<String,User> Map, so the return value is map.class Type getRawType(); GetOwnerType (); getOwnerType(); getOwnerType(); }Copy the code

So, now that we know what’s going on with the generics we need, we’re done with the empty methods we left behind.

Implement a simple ParameterizedType
public class ParameterizedTypeImpl implements ParameterizedType { private final Class raw; private final Type[] args; public ParameterizedTypeImpl(Class raw, Type[] args) { this.raw = raw; this.args = args ! = null ? args : new Type[0]; } @Override public Type[] getActualTypeArguments() { return args; } @Override public Type getRawType() { return raw; } @Override public Type getOwnerType() {return null; }}Copy the code
2. Generate generics required by Gson
2.1 Data is an Object
public static <T> Result<T> fromJsonObject(Reader reader, Class<T> clazz) {
    Type type = new ParameterizedTypeImpl(Result.class, new Class[]{clazz});
    return GSON.fromJson(reader, type);
}
Copy the code
2.2 Parsing Data is an array

The case of Array is one step further than the case of Object.

public static <T> Result<List<T>> fromJsonArray(Reader reader, Class<T> clazz) {ParameterizedTypeImpl(list. Class, new Class[]{clazz}); ParameterizedTypeImpl(result. class, new Type[]{listType}); // Result<List<T> Type Type = new ParameterizedTypeImpl(result. class, new Type[]{listType}); return GSON.fromJson(reader, type); }Copy the code

This code is less, do not provide source code

Although this blog post uses Gson as an example, it’s not really about Gson as much as it is about Java’s generics foundation, so this encapsulation approach can be applied to other frameworks as well.

Finally take this opportunity to amway a simple generics generation library TypeBuilder, its initial implementation of the purpose is to let you quickly generate generic information, but also to make some parameters check, to ensure correctness.

Use the code above to give you an example

public static <T> Result<List<T>> fromJsonArray(Reader reader, Class<T> clazz) {
    Type type = TypeBuilder
            .newInstance(Result.class)
            .beginSubType(List.class)
            .addTypeParam(clazz)
            .endSubType()
            .build();
    return GSON.fromJson(reader, type);
}

public static <T> Result<T> fromJsonObject(Reader reader, Class<T> clazz) {
    Type type = TypeBuilder
            .newInstance(Result.class)
            .addTypeParam(clazz)
            .build();
    return GSON.fromJson(reader, type);
}
Copy the code