Gson如何自定义Calendar序列化/反序列化
直接开干吧,假设有这么一个类:
@Data @AllArgsConstructor class BeanSample { public Calendar birthday; @Override public String toString() { if (birthday == null) { return "birthday:null"; } SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); return sdf.format(birthday.getTime()); } }
默认情况下,Gson序列化出来的结果很难看:
Gson gson = new Gson(); BeanSample bean = new BeanSample(Calendar.getInstance()); System.out.println(gson.toJson(bean));
输出:
{"birthday":{"year":2022,"month":3,"dayOfMonth":20,"hourOfDay":21,"minute":18,"second":13}}
以我多年的搬砖经验,加个TypeAdapter应该就可以了吧:
Gson gson = new GsonBuilder().registerTypeAdapter(Calendar.class, new TypeAdapter() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); @Override public void write(JsonWriter out, Calendar value) throws IOException { if (value == null) { out.nullValue(); } else { out.value(sdf.format(value.getTime())); } } @Override public Calendar read(JsonReader in) throws IOException { //这是从json字符串反序列化的,先不管 return null; } }).create(); BeanSample bean = new BeanSample(Calendar.getInstance()); System.out.println(gson.toJson(bean));
运行一下,居然没生效,还是刚才的格式!于是,下个断点:
发现birthday最终实例化后,类型是 GregorianCalendar(即:抽象类Calendar的子类),然后把刚才的代码略改了下:
Gson gson = new GsonBuilder().registerTypeAdapter(GregorianCalendar.class, new TypeAdapter() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); @Override public void write(JsonWriter out, GregorianCalendar value) throws IOException { if (value == null) { out.nullValue(); } else { out.value(sdf.format(value.getTime())); } } @Override public GregorianCalendar read(JsonReader in) throws IOException { JsonToken token = in.peek(); switch (token) { case NUMBER: Date d = new Date(in.nextLong()); GregorianCalendar c = new GregorianCalendar(); c.setTime(d); return c; case STRING: String s = in.nextString(); try { Date parse = sdf.parse(s); GregorianCalendar instance = new GregorianCalendar(); instance.setTime(parse); return instance; } catch (ParseException e) { e.printStackTrace(); return null; } case NULL: default: return null; } } }).create(); BeanSample bean = new BeanSample(new GregorianCalendar()); //序列化 String json = gson.toJson(bean); System.out.println(json); //反序列化 System.out.println(gson.fromJson(json, BeanSample.class)); System.out.println("--------"); //换成时间戳格式 json = "{\"birthday\":" + System.currentTimeMillis() + "}"; System.out.println(json); System.out.println(gson.fromJson(json, BeanSample.class));
输出:
{"birthday":"2022-04-20 22:27:08.864"} 2022-04-20 22:27:08.864 -------- {"birthday":1650464828881} 2022-04-20 22:27:08.881
这样看起来好多了,而且json反序列化时,时间戳long型数字也一并做了兼容
注:gson的其它小技巧,可参考先前写的文章