日常业务开发中我们有时候需要对json字符串转换成实体时做一些自对应的映射,今天我们使用Gson的TypeAdapter来实现
1、背景
最近在做考勤系统的时候,有一个页面展示需要根据每天考勤类型显示不同的显示符号,比如:
事假:△
调休:*
年假:□
正常:V
早退:#
加班:☆
原始数据格式:
{
"01": "3",
"02": "3",
"06": "4",
"07": "3",
"08": "3",
"11": "0",
"12": "3",
"13": "3",
"14": "3",
"15": "3",
"18": "3",
"19": "3",
"20": "3",
"21": "4",
"22": "0",
"24": "0",
"25": "3",
"26": "4",
"27": "4",
"28": "3",
"29": "3",
"30": "1",
"31": "7"
}
对应的实体类:
public class CheckReport {
private String day_1;
private String day_2;
private String day_3;
private String day_4;
private String day_5;
private String day_6;
private String day_7;
private String day_8;
private String day_9;
private String day_10;
private String day_11;
private String day_12;
private String day_13;
private String day_14;
private String day_15;
private String day_16;
private String day_17;
private String day_18;
private String day_19;
private String day_20;
private String day_21;
private String day_22;
private String day_23;
private String day_24;
private String day_25;
private String day_26;
private String day_27;
private String day_28;
private String day_29;
private String day_30;
private String day_31;
}
我们需要将json格式转换如下数据格式:
{
"day_1": "正常出勤",
"day_2": "正常出勤",
"day_6": "早退",
"day_7": "正常出勤",
"day_8": "正常出勤",
"day_11": "事假",
"day_12": "正常出勤",
"day_13": "正常出勤",
"day_14": "正常出勤",
"day_15": "正常出勤",
"day_18": "正常出勤",
"day_19": "正常出勤",
"day_20": "正常出勤",
"day_21": "早退",
"day_22": "事假",
"day_24": "事假",
"day_25": "正常出勤",
"day_26": "早退",
"day_27": "早退",
"day_28": "正常出勤",
"day_29": "正常出勤",
"day_30": "调休",
"day_31": "加班"
}
那么传统的方式就无法实现了
2、实现步骤
2.1、引入依赖
这里使用Gson的依赖:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${latest.version}</version>
</dependency>
2.2、自定义TypeAdapter
public class CheckResultTypeAdapter extends TypeAdapter<CheckReport> {
// 这个是对象转成json字符串的时候使用的写出的方法
@Override
public void write(JsonWriter out, CheckReport value) throws IOException {
out.beginObject();
writeData(out, value);
out.endObject();
}
private void writeData(JsonWriter out, CheckReport report) {
final Field[] fields = report.getClass().getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
String filedName = field.getName();
Object resultVal = field.get(report);
if (resultVal == null) {
continue;
}
String value = String.valueOf(resultVal);
CheckResultEnum resultEnum = CheckResultEnum.fromDesc(value);
value = String.valueOf(resultEnum.getCode());
if (filedName.contains("day_")) {
filedName = filedName.replace("day_", "");
filedName = String.format("%02d", Integer.parseInt(filedName));
}
out.name(filedName).value(value);
} catch (Exception e) {
//ignore
}
}
}
// 从字符串中读取数据将其转换成对象
@Override
public CheckReport read(JsonReader reader) throws IOException {
reader.beginObject();
String fieldName = "";
CheckReport detail = new CheckReport();
while (reader.hasNext()) {
JsonToken token = reader.peek();
if (token.equals(JsonToken.NAME)) {
fieldName = reader.nextName();
}
token = reader.peek();
setData(detail, fieldName, reader.nextString());
}
reader.endObject();
return detail;
}
private void setData(CheckReport detail, String fieldName, String nextString) {
try {
// 通过反射的方式将数据赋值
Class<?> clazz = detail.getClass();
String actualName = "day_" + Integer.parseInt(fieldName);
Field field = clazz.getDeclaredField(actualName);
field.setAccessible(true);
StringBuilder sb = new StringBuilder();
if (nextString.contains(",")) {
String[] split = nextString.split(",");
for (String data : split) {
CheckResultEnum resultTypeEnum = CheckResultEnum.fromCode(Integer.parseInt(data));
if (resultTypeEnum != null) {
sb.append(resultTypeEnum.getDesc());
}
}
} else {
CheckResultEnum resultTypeEnum = CheckResultEnum.fromCode(Integer.parseInt(nextString));
if (resultTypeEnum != null) {
sb.append(resultTypeEnum.getDesc());
}
}
field.set(detail, sb.toString());
} catch (Exception e) {
}
}
}
2.3、使用
public static void main(String[] args) {
GsonBuilder builder = new GsonBuilder();
// 通过GsonBuilder将自定义的adapter注册进去
builder.registerTypeAdapter(CheckReport.class, new CheckResultTypeAdapter());
builder.setPrettyPrinting();
Gson gson = builder.create();
String json = "{\n"
+ " \"01\":\"3\",\n"
+ " \"02\":\"3\",\n"
+ " \"06\":\"4\",\n"
+ " \"07\":\"3\",\n"
+ " \"08\":\"3\",\n"
+ " \"11\":\"0\",\n"
+ " \"12\":\"3\",\n"
+ " \"13\":\"3\",\n"
+ " \"14\":\"3\",\n"
+ " \"15\":\"3\",\n"
+ " \"18\":\"3\",\n"
+ " \"19\":\"3\",\n"
+ " \"20\":\"3\",\n"
+ " \"21\":\"4\",\n"
+ " \"22\":\"0\",\n"
+ " \"24\":\"0\",\n"
+ " \"25\":\"3\",\n"
+ " \"26\":\"4\",\n"
+ " \"27\":\"4\",\n"
+ " \"28\":\"3\",\n"
+ " \"29\":\"3\",\n"
+ " \"30\":\"1\",\n"
+ " \"31\":\"7\"\n"
+ "}";
final CheckReport report = gson.fromJson(json, CheckReport.class);
System.out.println(JSON.toJSONString(report));
System.out.println(gson.toJson(report));
}
输出结果:
// 输出的是正常对象转换成json
{"day_1":"正常出勤","day_11":"事假","day_12":"正常出勤","day_13":"正常出勤","day_14":"正常出勤","day_15":"正常出勤","day_18":"正常出勤","day_19":"正常出勤","day_2":"正常出勤","day_20":"正常出勤","day_21":"早退","day_22":"事假","day_24":"事假","day_25":"正常出勤","day_26":"早退","day_27":"早退","day_28":"正常出勤","day_29":"正常出勤","day_30":"调休","day_31":"加班","day_6":"早退","day_7":"正常出勤","day_8":"正常出勤"}
// 通过Gson将对象还原成了原始json字符串
{
"01": "3",
"02": "3",
"06": "4",
"07": "3",
"08": "3",
"11": "0",
"12": "3",
"13": "3",
"14": "3",
"15": "3",
"18": "3",
"19": "3",
"20": "3",
"21": "4",
"22": "0",
"24": "0",
"25": "3",
"26": "4",
"27": "4",
"28": "3",
"29": "3",
"30": "1",
"31": "7"
}