Solution to the mismatch between the field name in the JSON string and the field name in the Java class (use of @JsonProperty(“”) and @JSONField(name = “”))

1.1 Background

1.1.1 The so-called background, that is, what is the purpose and reason for writing this blog?

Recently, I encountered a very strange requirement at work. I used WebService to adjust a third-party interface, but the return value of the third-party interface was an Xml structure. It was not surprising at first. But then something unexpected happened. The field names of this Xml structure were in Chinese, and the data in the nodes I needed was not a JSON structure. So I need to parse the data in the Xml node first, then use split to split it, convert it into a JSON structure, and finally map the JSON to custom objects. But there is a problem. I need to match the Chinese field with the Java entity field and save it in the database. But since there are too many fields, it would be too troublesome to use enumeration or if to match one by one, and it is not concise enough. I was wondering if there is an annotation that can solve this problem?

First of all, the first thing I thought of was the @TableField annotation in MyBatis-Plus, but this annotation is mainly used for mapping entity class fields and database table fields, which does not meet my needs (haha, because I graduated not long ago, I have never encountered it before) I have come across this problem before, so I have just learned about the two annotations @JsonProperty(“”) and @JSONField(name = “”)).

Then I learned about the use of @JsonProperty(“”) and @JSONField(name = “”) through checking. After testing, I finally chose @JsonProperty(“”).

1.2 About @JsonProperty(“”)

1.2.1 Introduction

@JsonProperty is an annotation in the Jackson library, used to map a property in the JSON object to a field in the Java class when deserializing JSON data.

The syntax format of @JsonProperty is @JsonProperty("propertyName"), where propertyName is the property name in the JSON object, which is to be mapped to Field name in Java class.

Using the @JsonProperty annotation ensures that field names match between the JSON data and the Java class, allowing for correct deserialization. For example, if there is a property named “name” in the JSON data, then there should be a field named “name” in the Java class and marked with the @JsonProperty("name") annotation , so that the Jackson library can correctly map the “name” attribute in the JSON data to the “name” field in the Java class.

In addition to specifying the property name, @JsonProperty also supports some other options, such as setting the order of fields, whether they can be serialized, whether they can be deserialized, etc.

In short, @JsonProperty is one of the important annotations in the Jackson library for field mapping when deserializing JSON data.

1.2.2 For example (@JsonProperty can map not only English, but also Chinese)

Note: Don’t quote the wrong dependency: import com.fasterxml.jackson.annotation.JsonProperty;

Here I will take mapping Chinese as an example:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserBo implements Serializable {

    @JsonProperty("Name")
    private String name;
    @JsonProperty("phone")
    private String phone;
    @JsonProperty("city")
    private String city;

}
/**
 * @Author ZhaoShuHao
 * @Date 2023/11/11 15:09
 */
public class UserController {
    public static void main(String[] args) throws IOException {
        String user = "{"Name":"Zhang San","City":"Beijing","Telephone number":"1212323"}";
// UserBo userBo1 = JSONObject.parseObject(user, UserBo.class);
        ObjectMapper objectMapper = new ObjectMapper();
        UserBo userBo1 = objectMapper.readValue(user, UserBo.class);
        System.out.println(userBo1);
    }
}

1.3 About @JSONField(name = “”)

1.3.1 Introduction

@JSONField(name = "") is an annotation in the Jackson library, used to map a field in a Java class to a field in a JSON object when serializing or deserializing JSON data. on a certain attribute.

The syntax format of @JSONField annotation is @JSONField(name = "property_name"), where name is the property name in the JSON object, that is The field name to be mapped to the Java class.

Use the @JSONField annotation to ensure that field names match between the Java class and the JSON data, resulting in correct serialization or deserialization. For example, if there is a field named “name” in the Java class, then there should be a property named “property_name” in the JSON data and annotated with @JSONField(name = "property_name") Mark it so that the Jackson library can correctly map the “name” field in the Java class to the “property_name” attribute in the JSON data.

In addition to specifying attribute names, @JSONField also supports some other options, such as setting the order of fields, whether they can be serialized, whether they can be deserialized, etc.

In short, @JSONField is one of the important annotations in the Jackson library for field mapping when serializing or deserializing JSON data.

1.3.2 Give an example

Note: Check the information, @JSONField can also map Chinese and English, but I have not succeeded in mapping Chinese, and I have not found the problem yet. Here is an example of mapping English.

import com.alibaba.fastjson.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserBo implements Serializable {

    @JSONField(name = "names")
// @JsonProperty("name")
    private String name;
    @JSONField(name = "phones")
// @JsonProperty("phone")
    private String phone;
    @JSONField(name = "citys")
// @JsonProperty("city")
    private String city;

}
/**
 * @Author ZhaoShuHao
 * @Date 2023/11/11 15:09
 */
public class UserController {
    public static void main(String[] args) throws IOException {
// String user = "{"Name":"Zhang San","City":"Beijing","Telephone number":"1212323"}";
        String user = "{"names":"Zhang San","citys":"Beijing","phones":"1212323"}";
        UserBo userBo1 = JSONObject.parseObject(user, UserBo.class);
     /* ObjectMapper objectMapper = new ObjectMapper();
        UserBo userBo1 = objectMapper.readValue(user, UserBo.class);*/
        System.out.println(userBo1);
    }
}

1.4 Solutions to the needs I encountered

I won’t go into details and just get to the point.

1.4.1 Structure

Take a look at my structure (it’s not just Chinese, there are some differences in the structure?):

(1)


0

Number of cases: 10,
Extremely expensive cases: 0,
Very low cost cases: 0,
Total medical expenses (yuan): 507753.35,
DRG payment standard (yuan): 457775.76,
Profit and loss (yuan):-15109.75,
Average profit and loss amount (yuan): -1510.98,
DRG payment fee (yuan): 182516.69,
CMI:1,
Total weight:42.8062,
Enrollment rate: 80.00%,
Number of DRG groups: 4,
Surplus disease group: 6,
Loss disease group: 4,
Average length of stay: 12.3,
Drug fee (yuan): 100457.29,
Drug proportion: 19.66%,
Consumables fee (yuan): 164819.55,
Consumption ratio: 32.46%,
Inspection fee (yuan): 37136,
Inspection fee proportion: 7.31%,
Inspection fee (yuan): 75670.5,
Inspection fee proportion: 14.90%,
Time consumption index: 1.06,
Cost consumption index: 1.11

(2) This is even more confusing. The key is not only in Chinese, but also has a few more words. After converting to Json, it needs to be intercepted (I didn’t notice it at first)


0

Last month: Number of people entering: 37,
Number of people completed: 37,
Number of people exiting: 0,
Number of discharged patients: 47,
Number of mutants: 0

1.4.2 Solution

(1) First parse the xml and obtain the data in the resultMessage node

(2) Splice the data in the node into a string and remove the newline characters

(3) Because the parsed data does not conform to the JSON format, we first use split to split it and reassemble it into a Map structure

(4) Convert Map structure into Json string

(5) Mapping Json strings with custom objects

(6) Because several interfaces need to parse xml, but the mapped objects are different and the return types are different, so I used generics and reflection here.

(7) Because the data structure in the xml returned by the interface is still different, we also need a type to determine whether special processing is needed.

You’re done, the code is as follows:

package com.lc.ibps.medical.utils;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lc.ibps.medical.enums.BizDataMethodEnums;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;

/**
 *Xml parsing tool class, dynamically returns different objects based on generics
 * @Author ZhaoShuHao
 * @Date 2023/11/10 15:52
 */
@Slf4j
public class ParseXmlUtils {

    /**
     * Parse xml into corresponding objects
     * @param clazz The class of the custom object
     * @param xmlString xml object to be parsed
     * @param code interface identifier (because the structures returned by individual interfaces are different, special structures are processed here)
     * @param <T> Custom object
     * @return
     * @throwsException
     */
    public static <T> T getData(Class<T> clazz,String xmlString,String code) throws Exception {
        //Dynamicly return different objects based on generics
        T obj = clazz.getDeclaredConstructor().newInstance();
        //Create a DocumentBuilderFactory instance
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        //Create DocumentBuilder instance
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        InputSource is = new InputSource(new StringReader(xmlString));
        //Use the parse method to parse the input source
        Document doc = dBuilder.parse(is);
        // Check whether parsing is successful
        if (doc != null) {
            log.info("Parse input source successfully: " + doc);
            // Get all name nodes
            NodeList nodes = doc.getElementsByTagName("resultMessage");
            StringBuilder stringBuilder = new StringBuilder();
            // Traverse all name nodes
            for (int i = 0; i < nodes.getLength(); i + + ) {
                Node node = nodes.item(i);
                // Get the text content of each node
                stringBuilder.append(node.getTextContent());
            }
            //Because the information obtained does not conform to the Json format, it cannot be directly converted to Josn, or converted to other formats through JSON to process the string.
            // Parse the string into Map
            String oldStr = String.valueOf(stringBuilder);
            String str = oldStr.replaceAll("\\
", "");
            //TODO (confirmation is required after the interface is adjusted) Because the structure of the personal clinical path data and personal electronic medical record data has changed a bit, so it is processed here to remove redundant characters.
            if(BizDataMethodEnums.MES0735.getCode().equals(code)||BizDataMethodEnums.MES0736.getCode().equals(code)){
                str = str.substring(4);
            }
            log.info("xml to string: " + str);
            Map<String, Object> map = new HashMap<>();
            String[] pairs = str.split(",");
            for (String pair : pairs) {
                String[] keyValue = pair.split(":");
                //To solve the situation where value does not exist, set it to null by default
                if(keyValue.length==1){
                    map.put(keyValue[0], null);
                }else {
                    map.put(keyValue[0], keyValue[1]);
                }
            }
            log.info("String to map: " + map);
            //Convert Map to JSON string
            String jsonString = JSON.toJSONString(map);
            log.info("map to Json: " + jsonString);
            ObjectMapper objectMapper = new ObjectMapper();
            //Return different objects according to different types
            obj = (T) objectMapper.readValue(jsonString, obj.getClass());
            log.info("Json mapping object: " + obj);
        }
        return obj;
    }
}
@ApiModel(value = "DRG Quality Data Object")
public class DrgYearTbl extends AbstractPo<String>{
@ApiModelProperty(value = "primary key")
@JsonProperty("primary key")
protected String id; /*primary key*/
@ApiModelProperty(value = "foreign key")
@JsonProperty("foreign key")
protected String parentId; /*foreign key*/
@ApiModelProperty(value = "Tenant ID")
@JsonProperty("Tenant ID")
protected String tenantId; /*tenant ID*/
@ApiModelProperty(value = "IP address")
@JsonProperty("IP address")
protected String ip; /*IP address*/
@ApiModelProperty(value = "Data deletion status")
@JsonProperty("Data deletion status")
protected String deleted; /*data deletion status*/
@ApiModelProperty(value = "version")
@JsonProperty("version")
protected Long version; /*version*/
@ApiModelProperty(value = "serial number")
@JsonProperty("serial number")
protected Long orderNo; /*serial number*/
@ApiModelProperty(value = "Process Status")
@JsonProperty("Process Status")
protected String flowStatus; /*process status*/
@ApiModelProperty(value = "Department")
@JsonProperty("Department")
protected String sysDeptId; /*department*/
@ApiModelProperty(value = "Company")
@JsonProperty("Company")
protected String sysOrgId; /*Company*/
@ApiModelProperty(value = "Name")
@JsonProperty("name")
protected String name; /*name*/
@ApiModelProperty(value = "employee number")
@JsonProperty("employee number")
protected String number; /*employee number*/
@ApiModelProperty(value = "Year")
@JsonProperty("Year")
protected String year; /*year*/
@ApiModelProperty(value = "CMI")
@JsonProperty("CMI")
protected String cmi; /*CMI*/
@ApiModelProperty(value = "Average hospitalization days")
@JsonProperty("Average hospitalization days")
protected String pjzyr; /*average hospitalization days*/
@ApiModelProperty(value = "Enrollment rate")
@JsonProperty("Enrollment rate")
protected String rzl; /*Enrollment rate*/
@ApiModelProperty(value = "drug proportion")
@JsonProperty("drug proportion")
protected String yzb; /*drug proportion*/
@ApiModelProperty(value = "Consumption ratio")
@JsonProperty("consumption ratio")
protected String hzb; /*consumption ratio*/
@ApiModelProperty(value = "average fee")
@JsonProperty("average fee")
protected String cjf; /*average fee*/
@ApiModelProperty(value = "Check proportion")
@JsonProperty("Check proportion")
protected String jczb; /*Check proportion*/
@ApiModelProperty(value = "Consumables fee (yuan)")
@JsonProperty("Consumables fee (yuan)")
protected String hcf; /*consumables fee (yuan)*/
@ApiModelProperty(value = "Inspection fee (yuan)")
@JsonProperty("Inspection fee (yuan)")
protected String jcf; /*Inspection fee (yuan)*/
@ApiModelProperty(value = "Inspection fee proportion")
@JsonProperty("Inspection fee proportion")
protected String jcfzb; /*Inspection fee ratio*/
@ApiModelProperty(value = "Inspection fee (yuan)")
@JsonProperty("Inspection fee (yuan)")
protected String jyf; /*Inspection fee (yuan)*/
@ApiModelProperty(value = "Inspection fee proportion")
@JsonProperty("Inspection fee proportion")
protected String jyfzb; /*Inspection fee ratio*/
@ApiModelProperty(value = "Time consumption index")
@JsonProperty("Time consumption index")
protected String sjxhzs; /*time consumption index*/
@ApiModelProperty(value = "Cost consumption index")
@JsonProperty("Cost consumption index")
protected String fyxhzs; /*cost consumption index*/
@ApiModelProperty(value = "Number of cases")
@JsonProperty("number of cases")
protected String bls; /*number of cases*/
@ApiModelProperty(value = "Extremely expensive cases")
@JsonProperty("Extremely expensive cases")
protected String fyjgbls; /*Extremely expensive cases*/
@ApiModelProperty(value = "Extremely low cost case")
@JsonProperty("Extremely low cost case")
protected String fyjdbls; /*Extremely low cost cases*/
@ApiModelProperty(value = "Total medical expenses (yuan)")
@JsonProperty("Total medical expenses (yuan)")
protected String ylzfy; /*Total medical expenses (yuan)*/
@ApiModelProperty(value = "DRG payment standard (yuan)")
@JsonProperty("DRG payment standard (yuan)")
protected String drgzfbz; /*DRG payment standard (yuan)*/
@ApiModelProperty(value = "Profit and loss amount (yuan)")
@JsonProperty("Profit and loss amount (yuan)")
protected String yke; /*Profit and loss amount (yuan)*/
@ApiModelProperty(value = "average profit and loss amount (yuan)")
@JsonProperty("Average profit and loss amount (yuan)")
protected String cjyke; /*average profit and loss amount (yuan)*/
@ApiModelProperty(value = "DRG payment fee (yuan)")
@JsonProperty("DRG payment fee (yuan)")
protected String drgzffy; /*DRG payment fee (yuan)*/
@ApiModelProperty(value = "Total weight")
@JsonProperty("Total weight")
protected String zqz; /*Total weight*/
@ApiModelProperty(value = "number of DRG groups")
@JsonProperty("DRG group number")
protected String drgzs; /*number of DRG groups*/
@ApiModelProperty(value = "surplus disease group")
@JsonProperty("surplus disease group")
protected String ykbz; /*surplus disease group*/
@ApiModelProperty(value = "Loss Sick Group")
@JsonProperty("Loss Disease Group")
protected String ksbz; /*loss sick group*/
@ApiModelProperty(value = "Drug fee (yuan)")
@JsonProperty("Drug fee (yuan)")
protected String ypf; /*Drug fee (yuan)*/
@ApiModelProperty(value = "monthly")
@JsonProperty("monthly")
protected String month; /*monthly*/

//Omit get and set methods

}
/**The code for calling this method, only paste the relevant content:**/
String result = "<Response>\
" +
" <resultCode>0</resultCode>\
" +
" <resultMessage>Number of cases: 10,\
" +
"Extremely expensive cases:0,\
" +
"Extremely low cost cases:0,\
" +
"Total medical expenses (yuan): 507753.35,\
" +
"DRG payment standard (yuan): 457775.76,\
" +
"Profit and loss (yuan):-15109.75,\
" +
"Average profit and loss amount (yuan):-1510.98,\
" +
"DRG payment fee (yuan): 182516.69,\
" +
"CMI:,\
" +
"Total weight:42.8062,\
" +
"Enrollment rate: 80.00%,\
" +
"Number of DRG groups: 4,\
" +
"surplus disease group:6,\
" +
"Loss-sick group:4,\
" +
"Average hospitalization days:12.3,\
" +
"Drug fee (yuan): 100457.29,\
" +
"Pharmaceutical proportion: 19.66%,\
" +
"Consumables fee (yuan): 164819.55,\
" +
"Consumption ratio: 32.46%,\
" +
"Inspection fee (yuan): 37136,\
" +
"Inspection fee proportion: 7.31%,\
" +
"Inspection fee (yuan):75670.5,\
" +
"Inspection fee proportion: 14.90%,\
" +
"Time consumption index:1.06,\
" +
"Cost consumption index: 1.11</resultMessage>\
" +
"</Response>";
                DrgYearTbl drgYearTbl = new DrgYearTbl();
try {
drgYearTbl=ParseXmlUtils.getData(DrgYearTbl.class,result,BizDataMethodEnums.MES0734.getCode());
} catch (Exception e) {
log.error("Exception occurred when converting xml object: " + e);
}

1.5 Extension (custom tool class)

public class ObjectConvertUtil {

    /**
     * @param sourceClass source object
     * @param targetClass target object class
     * */
    public static <T,U> U objectConvert(T sourceClass, Class<U> targetClass){
        String sourceStr= JSON.toJSONString(sourceClass);
        return JSONObject.parseObject(sourceStr,targetClass);
    }

}

Whatever object you want to transfer, just use the tool class to transfer it, which saves you a lot of trouble. For example:

<strong>UserPo userpo = new UserPo();
User user = ObjectConvertUtil.objectConvert(userpo, User.class);</strong>

DogVo dogvo= new DogVo();
Dog dog= ObjectConvertUtil.objectConvert(dogvo, Dog.class);