Gson自定义映射


日常业务开发中我们有时候需要对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"
}

文章作者: Qing Fan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Qing Fan !
  目录