Jackson--反序列化的解析
项目中经常需要调用指定服务的接口,并且对返回的json结果数据,进行反序列化生成java类。
若是返回的数据格式固定,那么直接按照固定的格式进行反序列化生成java类便可。但是由于
返回的结果数据格式不固定,需要自己编写反序列化类进行分析。
下面我讲展示下项目中遇到的情况。
{ "status": "200", "Goal": { "userId": "17090016", "templateId": "26", "templateName": "测试-营销通用目标模板", "performance": [ { "id": "8022", "indexCode": "", "name": "执行绩效综合达成率", "category": "New Category", "categoryName": "执行绩效", "start": "2019-10-01T00:00:00.000", "due": "2019-10-31T00:00:00.000", "bizxTarget": "", "bizxActual": "", "done": "0.0", "higedone": "", "stateLabel": "重大延迟", "weight": "", "dataSource": "", "lastModified": "2019-12-11T08:45:47.000", "modifier": "17090016", "children": "" }, { "id": "8015", "indexCode": "", "name": "协访达成率", "category": "Goals", "categoryName": "先决条件", "start": "2019-10-01T00:00:00.000", "due": "2019-10-31T00:00:00.000", "bizxTarget": "47.0", "bizxActual": "73.0", "done": "0.0", "higedone": "100.0", "stateLabel": "重大延迟", "weight": "", "dataSource": "手持", "lastModified": "2019-12-11T13:57:09.000", "modifier": "17090016", "children": { "childDescription": "CS协访", "childTarget": "15", "childActual": "18", "childDone": "100.0" } }, { "id": "8017", "indexCode": "", "name": "分销达成率", "category": "New Category", "categoryName": "执行绩效", "start": "2019-10-01T00:00:00.000", "due": "2019-10-31T00:00:00.000", "bizxTarget": "100.0", "bizxActual": "23.39", "done": "23.39", "higedone": "100.0", "stateLabel": "重大延迟", "weight": "20.0", "dataSource": "订单管理", "lastModified": "2019-12-11T14:09:32.000", "modifier": "17090016", "children": [ { "childDescription": "门店数", "childTarget": "", "childActual": "23", "childDone": "" }, { "childDescription": "门店品类数", "childTarget": "", "childActual": "31", "childDone": "" }, { "childDescription": "门店SKU", "childTarget": "", "childActual": "25", "childDone": "" } ] }
}
上面的json格式数据中,其余的字段格式都是比较的固定,但是可以看到children的数据内容出现了3种:
1、字符串内容
2、对象
3、数组
由于children的内容格式不固定,则直接利用jackson进行反序列化会失败,所以需要我们自己编写反序列化的实现类。
但是只是children的内容格式不固定,我们只是需要对children编写反序列化的实现类。
代码如下;
整个json对应的javabean
package com.shinho.plrs.front.pojo; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.List; @Data @ApiModel("指标") @JsonIgnoreProperties(ignoreUnknown = true) public class Target { @ApiModelProperty("id") String id; @ApiModelProperty("指标编码") String code; @JsonGetter("code") public String getCode() { return this.code; } @JsonSetter(value = "indexCode") public void setCode(String code) { this.code = code; } @ApiModelProperty("指标名称") String purpose; @ApiModelProperty("指标类型编码") String category; @ApiModelProperty("指标类型名称") String categoryName; @JsonProperty("start") @ApiModelProperty("开始日期") String startDate; @JsonProperty("due") @ApiModelProperty("结束日期") String endDate; @ApiModelProperty("目标") String aim; @ApiModelProperty("实际") String acture; @ApiModelProperty("达成率") String done; @ApiModelProperty("达成率封顶值") String higedone; @ApiModelProperty("状态(文本)") String stateLabel; @ApiModelProperty("权重") String weight; @ApiModelProperty("数据来源") String dataSource; @ApiModelProperty("最近修改时间") String lastModified; @ApiModelProperty("修改人") String modifier; // @ApiModelProperty("子指标数据") // List<Child> childs = new ArrayList<>(); @ApiModelProperty("子指标数据") @JsonDeserialize(using = ChildrenDeserializer.class) List<Child> children; }
package com.shinho.plrs.front.pojo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.experimental.Accessors; @Data @ApiModel("子指标") @Accessors(chain = true) public class Child { @ApiModelProperty("子指标描述") String childDescription; @ApiModelProperty("子指标目标") String childTarget; @ApiModelProperty("子指标完成值") String childActual; @ApiModelProperty("子指标达成率") String childDone; }
反序列化类的实现:
package com.shinho.plrs.front.pojo; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.util.StringUtils; import java.io.IOException; import java.util.ArrayList; import java.util.List; @Slf4j public class ChildrenDeserializer extends StdDeserializer<List<Child>> { public ChildrenDeserializer() { super(List.class); } public ChildrenDeserializer(Class<?> vc) { super(vc); } @Override public List<Child> deserialize(JsonParser parser, DeserializationContext deserializer) throws IOException { List<Child> list = new ArrayList<>(); if (StringUtils.isEmpty(parser.getText())) return list; if (JsonToken.START_ARRAY.equals(parser.getCurrentToken())) { while (!JsonToken.END_ARRAY.equals(parser.getCurrentToken())) { list.add(parseJsonObjectToChild(parser)); parser.nextToken(); } } else if (JsonToken.START_OBJECT.equals(parser.getCurrentToken())) { list.add(parseJsonObjectToChild(parser)); } return list; } /** * 将json数据分析成java对象 * * @param parser * @return */ private Child parseJsonObjectToChild(JsonParser parser) throws IOException { Child child = new Child(); JsonToken token = parser.getCurrentToken(); String fieldName = null; while (!JsonToken.END_OBJECT.equals(token)) { if (!JsonToken.FIELD_NAME.equals(token)) { token = parser.nextToken(); continue; } fieldName = parser.getCurrentName(); token = parser.nextToken(); try { BeanUtils.getPropertyDescriptor(Child.class, fieldName).getWriteMethod().invoke(child, parser.getText()); token = parser.nextToken(); } catch (Exception e) { log.error("反序列化child过程中,出现异常:", e); } } return child; } }