Gson序列化中指定顺序的实现(按英文字段名升序)
需要输入的实体示例如下:

/**
* 云打印请求参数
*/
@Data
公共类 YiRuiPrintResParam 继承自 YiRuiCommonResParam 并实现了 Serializable 接口。
private String deviceName;
private String token;
private String transNo;
private Integer type;
private Nc nc;
private String pc;
}
/**
* 公共请求参数
*/
@Data
公共类 YiRuiCommonResParam 实现了 Serializable 接口。
private String productKey;
private Long timestamp;
private String signMethod;
private String sign;
}
@Data
public class Nc {
private Integer channel;
private String ct;
private String charset;
}
如果没有指定顺序,Gson 会依据实体类里的字段排列顺序进行序列化,并且这种序列化与字段设值顺序无关。同时,实体类里面的类 Nc 的输出字段顺序也是按照实体类里的字段排列顺序来的。
序列化输出代码:
Gson printGson = new Gson();
使用 printGson 将 printParam 转换为 JSON 字符串,得到的结果赋值给 String 类型的 printReq 。
System.out.printf("云打印的请求为:%s\n", printReq);
序列化输出结果:
{
"deviceName"为"8115210800100022"。
"token"为"E75x+wmRF3eyo1IZxnn+s2PrhtAYIhX1Kchk9eVtx1niQulJx4QgUwYoYCe7Fugv1634089348814"。
"transNo": "20211013141142",
"type": 0,
"nc": {
"channel": 1,
"ct": "12345",
"charset": "abcde"
},
"cn" 的值为 1。
"productKey"的值为"78d077bf960c477b"。
"timestamp": 1634105502,
"signMethod": "MD5",
"sign" 的值为 "394009CE36A0AD145D279AF84131E35D"
}
如果想要指定顺序,那该如何实现呢?我的需求是依据字段的英文名称进行升序排序。我参考了网络上的一些做法,这些做法大多倾向于通过继承 TypeAdapter 类来达成目的,具体的做法如下:
/**
* 打印适配器
*/
公共类 YiRuiPrintAdapter 继承自 TypeAdapter 。 {
@Override
公共的 void 方法 write 会将参数 out(JsonWriter 类型)和 param(YiRuiPrintResParam 类型)写入,并且在这个过程中不会抛出 IOException 异常。
// Class extends Nc>ncClazz 等于 param.getNc() 的类;
ncClazz 的声明字段被获取到,这些字段是 Field 类型的数组,记为 ncFields 。
out.beginObject();
// 按自定义顺序输出字段信息
使用 out.name 并传入 "deviceName" ,然后获取 param 的设备名称并赋值给它;或者让 out.name 指向 "deviceName" ,接着获取 param 的设备名称并将其赋予 out.name ;又或者通过 out.name("deviceName") 来获取 param 的设备名称并进行相应操作。
out.name("nc");
out.beginObject();
调用 out.name 方法并传入 "channel" 作为参数,然后获取 param.getNc().getChannel 的值并作为 out.name 的返回值
获取名为"charset"的内容,然后获取 param 的 nc 属性,再获取该 nc 属性的字符集,最后将获取到的字符集设置为 out 的 name 属性的值。
调用 out 的 name 方法并传入 "ct",然后获取 param 的 getNc 方法返回的对象的 ct 属性值。
设置写入(ncFields,out,param.getNc());
out.endObject();
调用 name 方法并传入 "pc",然后获取 param 的 pc 属性值。
调用 out.name 方法并传入 "productKey" 作为参数,获取其返回值,然后将 param 中的 getProductKey 方法的返回值作为 value 传入到前面获取的返回值中。
通过 name 为"sign"的方式,将 param.getSign()作为值进行传递。
调用 out.name 方法并传入参数 param.getSignMethod(),将其值赋给 signMethod 字段。
获取名为"timestamp"的名称。然后,使用 param 获取时间戳。最后,将获取到的时间戳设置为名为"timestamp"的值。
调用 out 的 name 方法并传入"token",然后获取 param 的 getToken 方法的值。
获取名为"transNo"的名称并将其值设置为参数 param 中的交易号 param.getTransNo()
调用 name("type") 方法并获取其返回值,然后将该返回值作为参数传递给 value 方法,参数为 param.getType() 的值。
out.endObject();
}
@Override
公共的 YiRuiPrintResParam 读取(JsonReader jsonReader)会引发 IOException。
return null;
}
// /**
// * 递归写入属性
// *
// * @param fields
// * @param out
// * @param object
// * @return void
作者是 liangzhaolinC。
在 2021 年 10 月 13 日 10 点 50 分这个时间点被标注为 @date。
// */
公共的方法用于设置写入操作,它接收字段数组、 JSON 写入器以及对象作为参数。该方法的作用是进行相关的写入设置操作。
// for (int i = 0; i < fields.length; i++) {
// Field field = fields[i];
// field.setAccessible(true);
// try {
// Object type = field.get(object);
// if (type == null) {
// continue;
// }
// if (!(type instanceof String)) {
// out.name(field.getName()).beginObject();
// Field[] subFields = type.getClass().getDeclaredFields();
// setWrite(subFields, out, type);
// out.endObject();
// } else {
// out.name(field.getName()).value(type.toString());
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// }
}
out.beginObject() 的含义是在 json 中添加左括号“{”。
out.endObject()的含义是在 json 中添加右括号 } 。
out.name("nc")的含义是在 json 中添加 key "nc"。
out.value(xxx)的含义是在 json 中添加 value"xxx"
可以看下对应里面的源码理解下。
代码中注释的部分,其目的是想自动打印出 Nc 类里的字段。然而,由于代码是参考网上的,在尝试过程中遇到了一些 bug。因为项目比较紧急,所以先将其注释掉,留待以后再进行研究。如果有小伙伴能够修复这个问题,也希望能分享一下。取而代之的是,通过写死的方式来控制 Nc 的字段序列化顺序。所以有第二次调用 out.beginObject(); ,以及与之对应的 out.endObject();
序列化代码:
Gson printGson 被创建出来,创建时使用了 new GsonBuilder(),并且在其中注册了类型适配器 YiRuiPrintResParam.class 对应的 YiRuiPrintAdapter(),最终通过 create()方法生成了这个 Gson 对象。
String printReq = printGson.toJson(printParam);
System.out.printf("云打印 request:%s\n", printReq);
序列化输出结果:
{
"deviceName": "8115210800100022",
"nc": {
"channel": 1,
"charset": "abcde",
"ct": "12345"
},
"pc": "{\"ct\":[{\"cols\":[{\"cv\":\"\"}],\"tp\":\"0\"},{\"tp\":\"3\"},{\"cols\":[{\"cv\":\"商户名称:\"},{\"cv\":\"测试商户\"}],\"tp\":\"1\"},{\"cols\":[{\"cv\":\"金额RMB:\"},{\"cv\":\"0.01元\"}],\"tp\":\"1\"}],\"cn\":1}",
"productKey": "78d077bf960c477b",
"sign" 的值为 "F6093E0B127D6B537D8BDD376C532097"。
"signMethod": "MD5",
"timestamp": 1634106351,
"token": "E75x+wmRF3eyo1IZxnn+s2PrhtAYIhX1Kchk9eVtx1niQulJx4QgUwYoYCe7Fugv1634089348814",
"transNo": "20211013142551",
"type": 0
}
参考资料:
java自定义Gson生成json字符串的顺序
gson改变输出字段的顺序
« 上一篇
占位符在编程中的应用:从熟悉到实践的过程
下一篇 »
宣城少儿编程加盟:选择机构需考虑多方面因素