fastJson deserialize generic process to what I can learn

will parse the json

In our daily coding work, often encounter such a formulation or json structure

{
  "resultcode": "200",
  "reason": "成功的返回",
  "result": {
    "area": "浙江省温州市平阳县",
    "sex": "男",
    "birthday": "1989年03月08日"
  }
}
复制代码

For the provider of the interface, the outermost layer resultcode reasonand resultthese three elements are there. Therefore, we can define such a Responseclass

public class Response<T> {
    private String resultcode;

    private String reason;

    private T result;

}
复制代码

The use of generics to decide what the final result is filled to the inside. Of course, here is filled with an object, we tentatively it can be defined as Userthe class

public class User {
    private String area;
    private String sex;
    private String birthday;
}
复制代码

Thus, our data will be in accordance with the agreed rules of json example, returned to the caller. As the caller, the machine is receiving this data, we need to define the following classResopnseUser

public class ResopnseUser {
    private String resultcode;

    private String reason;

    private User result;
}

public class User {
    private String area;
    private String sex;
    private String birthday;
}
复制代码

Then we can use fastJson be happy to resolve the

        String  testJson = "{\"resultcode\":\"200\",\"reason\":\"成功的返回\",\"result\":{\"area\":\"浙江省温州市平阳县\",\"sex\":\"男\",\"birthday\":\"1989年03月08日\"}}";
        ResponseUser response1 =  JSONObject.parseObject(testJson,ResponseUser.class);

复制代码

We can see, it did get the results we want

Thinking improvements

However, this has a less severe consequences. I docking with each provider an interface, you have to generate a corresponding class. Over time, these special classes will become more and more, will be more deeply nested. Since the provider can abstract a Responseclass, then I can deal with that to the provider?

        String  testJson = "{\"resultcode\":\"200\",\"reason\":\"成功的返回\",\"result\":{\"area\":\"浙江省温州市平阳县\",\"sex\":\"男\",\"birthday\":\"1989年03月08日\"}}";
        Response<User> response =  JSONObject.parseObject(testJson,Response.class);
复制代码

Unfortunately, our results are not expected, only the outermost data analysis is successful, the inner layer resultremains JSONObject.

Recourse to universal forum

Lucky thing, in which thousands of engineers not only thought of this approach, and have someone to solve such a problem! Down through a variety of search, we found fastJson provides TypeReferencethis class can solve our problems.

String  testJson = "{\"resultcode\":\"200\",\"reason\":\"成功的返回\",\"result\":{\"area\":\"浙江省温州市平阳县\",\"sex\":\"男\",\"birthday\":\"1989年03月08日\"}}";
        Response<User> response =  JSONObject.parseObject(testJson,new TypeReference<Response<User>>(){});
复制代码

Well, we've got the results you want, you can finally unified interface to all of the outermost layer of the return value judgment.

Not stop there

And so on, we did not find any questions for me? Generics will perform at compile time type erasure ah! This is the first time we directly use the Response<User> response = JSONObject.parseObject(testJson,Response.class);invalid Cause. So, even if we wrote so new TypeReference<Response<User>>(){}not the same will be erased it? It is a run-time how to get to the actual type we defined? By looking at TypeReferencethe source code, the source code is fortunately very simple and less code. First enter is its constructor protected TypeReference(), through debug we found that the implementation of the second row in the code, it has received written our generics.

        Type superClass = getClass().getGenericSuperclass();

        Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
复制代码

This code is very simple, get to its parent class getGenericSuperclass()to get to the actual type. Continue to follow up the code, we can see that it calls a native method private native String getGenericSignature0();to obtain some information to the class and the parent class ClassRepositoryand Type. At this time, we look back to new TypeReference<Response<User>>(){}actually create an TypeReferenceanonymous inner class by class getGenericSuperclass(), get to the actual type information.

Continue to root out

Let us now look at our income, note must be 2:00:

  1. Generics will perform at compile time type erasure .
  2. To acquire its parent class getGenericSuperclass()to get to the actual type. Etc., these two are mutually contradictory ah. 1 said no, two said'll find, in the end is how it happened? By looking at the bytecode compiled files, we found the answer.
    This is the code that contains Response<User> response = JSONObject.parseObject(testJson,new TypeReference<Response<User>>(){});information about the methods of the class file decompile. We can see it one more LocalvariableTypeTable, which is Signatureexactly the type of information stored in the actual. ** That is not completely erase type, type parameter we still can get by way of reflection. ** called erasing method just codebyte code erasing property. In addition, we also see the InnerClasseslist, there is an inner class called Main $ 1, this is what wenew TypeReference<Response<User>>(){}

to sum up

  1. By JSONObject.parseObject(testJson,new TypeReference<Response<User>>(){});the way, to solve the problem json nested generics. Convenient, fast and intuitive
  2. You can getClass().getGenericSuperclass();get to the real type. Authentication Code
  // 这类创建了一个HashMap的匿名子类
        HashMap<String,Integer> subIntMap = new HashMap<String,Integer>(){};

        System.out.println(subIntMap.getClass().getSuperclass());

        Type subClassType = subIntMap.getClass().getGenericSuperclass();
        if(subClassType instanceof ParameterizedType){
            ParameterizedType p = (ParameterizedType) subClassType;
            for (Type t : p.getActualTypeArguments()){
                System.out.println(t);
            }
        }
复制代码

Output

class java.util.HashMap
class java.lang.String
class java.lang.Integer
复制代码
  1. Type is not completely erased, the type of the parameter can get through reflection. Authentication Code
 ResponseUser response = new ResponseUser();
        Field field = response.getClass().getField("result");
        System.out.println("result Type is "+ field.getType());
        System.out.println("result GenericType is "+ field.getGenericType());
public class ResponseUser {
    private String resultcode;

    private String reason;

    public List<User> result;
}
复制代码

Output

result Type is interface java.util.List
result GenericType is java.util.List<com.jd.jr.alpha.cpa.fastJson.User>
复制代码

Guess you like

Origin juejin.im/post/5d4aa5ab6fb9a06b297536bb