这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战
Json 属性排序
今天我们公司突然需要根据对象的Json字符串,生成md5密钥。所以同一对象获得的Json字符串一定是相同的。我们就需要对属性进行排序。最先想到的是fastjson 自带属性排序
fastjson
bean
@JSONType(orders={"d4","e5","c3","a1","b2"})
public class Base implements Serializable {
private String A1;
private String B2;
private Integer C3;
private List<Base> D4;
private Base[] E5;
}
toJson
Base base1 = new Base("a1", "b1", 1, null, null);
Base base2 = new Base("a2", "b2", 2, null, null);
Base base3 = new Base("a3", "b3", 3, null, null);
Base base4 = new Base("a4", "b4", 4, null, null);
Base base = new Base("A1", "B1", 100, null, null);
ArrayList<Base> bases = new ArrayList<>(2);
bases.add(base1);
bases.add(base2);
base.setD4(bases);
base.setE5(new Base[]{base3, base4});
System.out.println(JSON.toJSON(base));
//{"d4":[{"c3":1,"a1":"a1","b2":"b1"},{"c3":2,"a1":"a2","b2":"b2"}],"e5":[{"c3":3,"a1":"a3","b2":"b3"},{"c3":4,"a1":"a4","b2":"b4"}],"c3":100,"a1":"A1","b2":"B1"}
但很遗憾的是我们公司项目没有引入fastjson包,而是Gson谷歌Json解析包,于是分析了fastjson排序的原理,使用Gson实现了属性排序
以下是Gson属性排序demo
Gson
首先定义注解
annotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Order {
String[] orders() default {};
}
bean
@Order(orders={"d4","c3","e5","a1","b2"})
public class Base2 implements Serializable {
private String A1;
private String B2;
private Integer C3;
private List<Base2> D4;
private Base2[] E5;
}
toJson
Base2 base1 = new Base2("a1", "b1", 1, null, null);
Base2 base2 = new Base2("a2", "b2", 2, null, null);
Base2 base3 = new Base2("a3", "b3", 3, null, null);
Base2 base4 = new Base2("a4", "b4", 4, null, null);
Base2 base = new Base2("A1", "B1", 100, null, null);
ArrayList<Base2> bases = new ArrayList<>(2);
bases.add(base1);
bases.add(base2);
base.setD4(bases);
base.setE5(new Base2[]{base3, base4});
JsonElement jsonElement = new Gson().newBuilder().registerTypeAdapter(Base2.class, new JsonSerializer<Base2>() {
/**
* 原理: 向Gson注册该类型,和类型解析器。
* 根据Order注解依次使用jsonSerializationContext递归解析对象属性,并一次放入到JsonObject对象中
* 返回生成的JsonObject
*/
@Override
public JsonElement serialize(Base2 o, Type type, JsonSerializationContext jsonSerializationContext) {
JsonObject jsonObject = null;
try {
Class<Base2> aClass = (Class<Base2>) Class.<Base2>forName(type.getTypeName());
Order order = aClass.getDeclaredAnnotation(Order.class);
jsonObject = new JsonObject();
for (String s : order.orders()) {
Field field = aClass.getDeclaredField(s.toUpperCase(Locale.ROOT));
field.setAccessible(true);
Object o1 = field.get(o);
JsonElement jsonElement1 = jsonSerializationContext.serialize(o1);
jsonObject.add(s, jsonElement1);
}
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
// new JsonPrimitive()
return jsonObject;
}
}).create().toJsonTree(base);
JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonElement a1 = jsonObject.get("A1");
JsonElement b2 = jsonObject.get("B2");
JsonElement e5 = jsonObject.get("E5");
System.out.println(a1);
System.out.println(b2);
System.out.println(e5);
System.out.println(jsonObject);
上述方法有个问题就是如果需要属性排序的Json对象很多,那么每个对象类型都需要进行注册?
我们可以通过声明接口来避免大量注册,且逻辑一样的情况发生即使用registerTypeHierarchyAdapter
interface
public interface Sort {
}
bean
@Order(orders={"d4","c3","e5","a1","b2"})
public class Base3 implements Serializable, Sort {
private String A1;
private String B2;
private Integer C3;
private List<Base3> D4;
private Base3[] E5;
}
toJson
Base3 base1 = new Base3("a1", "b1", 1, null, null);
Base3 base2 = new Base3("a2", "b2", 2, null, null);
Base3 base3 = new Base3("a3", "b3", 3, null, null);
Base3 base4 = new Base3("a4", "b4", 4, null, null);
Base3 base = new Base3("A1", "B1", 100, null, null);
ArrayList<Base3> bases = new ArrayList<>(2);
bases.add(base1);
bases.add(base2);
base.setD4(bases);
base.setE5(new Base3[]{base3, base4});
JsonElement jsonElement = new Gson().newBuilder().registerTypeHierarchyAdapter(Sort.class, new JsonSerializer<Sort>() {
@Override
public JsonElement serialize(Sort o, Type type, JsonSerializationContext jsonSerializationContext) {
JsonObject jsonObject = null;
try {
Class<Sort> aClass = (Class<Sort>) Class.<Sort>forName(type.getTypeName());
Order order = aClass.getDeclaredAnnotation(Order.class);
jsonObject = new JsonObject();
for (String s : order.orders()) {
Field field = aClass.getDeclaredField(s.toUpperCase(Locale.ROOT));
field.setAccessible(true);
Object o1 = field.get(o);
JsonElement jsonElement1 = jsonSerializationContext.serialize(o1);
jsonObject.add(s, jsonElement1);
}
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
// new JsonPrimitive()
return jsonObject;
}
}).create().toJsonTree(base);
JsonObject jsonObject = jsonElement.getAsJsonObject();
System.out.println(jsonObject);
map的序列化
使用map进行序列化时,如果要对map顺序进行变化,如果不复杂最简单的是硬编码,复杂情况可以考虑转换成Dto对象
HashMap<String, String> stringStringHashMap = new HashMap<>();
stringStringHashMap.put("a1","A1");
stringStringHashMap.put("b2","B2");
stringStringHashMap.put("c3","C3");
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("c3",stringStringHashMap.get("c3"));
jsonObject.addProperty("a1",stringStringHashMap.get("a1"));
jsonObject.addProperty("b2",stringStringHashMap.get("b2"));
System.out.println(jsonObject);
//{"c3":"C3","a1":"A1","b2":"B2"}
如果只是简单的让map中的元素不会变化可以使用LinkedHashMap