SoFunction
Updated on 2025-05-09

How Java uses a unified structure to receive data with unfixed member names

This article introduces a method in Java to receive data with unfixed member names using a unified structure.

background

Recently, I was working on internal application development of Enterprise WeChat and encountered a small problem: the data returned by different interfaces of Enterprise WeChat are not exactly the same.

For example, the data structure returned by the obtaining department list interface is as follows:

{
    "errcode": 0,
    "errmsg": "ok",
    "department": [
        {
            "id": 2,
            "name": "Guangzhou R&D Center",
            "name_en": "RDGZ",
            "department_leader":["zhangsan","lisi"],
            "parentid": 1,
            "order": 10
        }
    ]
}

The data structure returned by the obtaining department member interface is as follows:

{
    "errcode": 0,
    "errmsg": "ok",
    "userlist": [
        {
            "userid": "zhangsan",
            "name": "Zhang San",
            "department": [1, 2],
            "open_userid": "xxxxxx"
        }
    ]
}

That is to say, the return frameworks of different interfaces are the same, all of them are errcode + errmsg + data parts, but the member names of the data parts are different, such as the abovedepartmentanduserlist

I don't know why I designed this way. From the habits of Java developers, if I designed it, I will try to keep the consistency of the data structure returned by the interface, such as using the data part.dataTo represent it, in this way, a unified generic structure can be used when serializing and deserializing.

Of course, this may be a difference in the development language or habits within Qiwei, or other reasons. We cannot explore it in depth here, just talk about how to deal with it.

analyze

After encountering this problem, the first reaction is to use the JSON structure to receive it, and then the data parts of different interfaces are read with different keys. It can be achieved, but it always feels not elegant enough.

Then I thought that there should be many open source packaging libraries for enterprise micro development on GitHub. Let’s take a look at their implementation and there may be better solutions, and there will be rewards in the end.

I mainly looked at two libraries:

  • /binarywang/WxJava
  • /NotFound403/wecom-sdk

The former is more well-known and contains more things, including the packaging of various development packages of WeChat and Qiwei. It is implemented using the method we mentioned earlier, using the JSON structure to receive the data of different interfaces, and then the data of different interfaces is read with different keys.

The latter wecom-sdk is a development package of Qiwei. Its implementation uses a unified generic structure to receive data.

The following intercepts the encapsulation codes of the two departments of the two libraries for management related interfaces:

WxJava version:

/binarywang/WxJava/blob/develop/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/

@Override
public List<WxCpDepart> list(Long id) throws WxErrorException {
    String url = ().getApiUrl(DEPARTMENT_LIST);
    if (id != null) {
      url += "?department"),
        new TypeToken<List<WxCpDepart>>() {
        }.getType()
      );
  }

@Override
public List<WxCpDepart> simpleList(Long id) throws WxErrorException {
    String url = ().getApiUrl(DEPARTMENT_SIMPLE_LIST);
    if (id != null) {
      url += "?department_id"),
        new TypeToken<List<WxCpDepart>>() {
        }.getType()
      );
  }
}

wecom-sdk version:

/NotFound403/wecom-sdk/blob/release/wecom-sdk/src/main/java/cn/felord/api/

@GET("department/list")
GenericResponse<List<DeptInfo>> deptList(@Query("id") long departmentId) throws WeComException;

@GET("department/simplelist")
GenericResponse<List<DeptSimpleInfo>> getSimpleList(@Query("id") long departmentId) throws WeComException;

Putting aside the introduction of the wecom-sdk version, the number of codes caused by the support of the Retrofit2 library, I also prefer the implementation of the wecom-sdk version in deserialization of the returned data.

accomplish

Next, we directly refer to the implementation method in wecom-sdk and write a generic class, which can be used to receive data returned by different interfaces of Qiwei:

@Data
public class WxWorkResponse<T> {

    @JsonProperty("errmsg")
    private String errMsg;

    @JsonProperty("errcode")
    private Integer errCode;

    @JsonAlias({
            "department",
            "userlist"
    })
    private T data;
}

The key role played in this is Jackson Curry's@JsonAliasAnnotation. Its official documentation is described as follows:

Annotation that can be used to define one or more alternative names for a property, accepted during deserialization as alternative to the official name. Alias information is also exposed during POJO introspection, but has no effect during serialization where primary name is always used.
Examples:
  public class Info {
    @JsonAlias({ "n", "Name" })
    public String name;
  }
  
NOTE: Order of alias declaration has no effect. All properties are assigned in the order they come from incoming JSON document. If same property is assigned more than once with different value, later will remain. For example, deserializing
   public class Person {
      @JsonAlias({ "name", "fullName" })
      public String name;
   }
   
from
   { "fullName": "Faster Jackson", "name": "Jackson" }
   
will have value "Jackson".
Also, can be used with enums where incoming JSON properties may not match the defined enum values. For instance, if you have an enum called Size with values SMALL, MEDIUM, and LARGE, you can use this annotation to define alternate values for each enum value. This way, the deserialization process can map the incoming JSON values to the correct enum values.
Sample implementation:
public enum Size {
       @JsonAlias({ "small", "s", "S" })
       SMALL,
  
       @JsonAlias({ "medium", "m", "M" })
       MEDIUM,
  
       @JsonAlias({ "large", "l", "L" })
       LARGE
   }
During deserialization, any of these JSON structures will be valid and correctly mapped to the MEDIUM enum value: {"size": "m"}, {"size": "medium"}, or {"size": "M"}.

Going back to our example, exceptdepartmentanduserlistIn addition, other keys are used, you can continue to@JsonAliasAdded in the annotation.

In this way, we deserialize and unify the encapsulation of different interfaces.getData()You can get the data part. You don’t have to worry about what the key of the data part is when using it.

The above is the detailed content of how Java uses a unified structure to receive data with unfixed member names. For more information about receiving unfixed data with unfixed Java, please pay attention to my other related articles!