java将对象内的属性按字符排序,依次到最底层

场景:
将对象内的属性按属性名称先后排序,如果属性依然是对象,继续按照这个规则对这个对象内的属性进行排序
错误示例:
只将首层对象进行排序了
下面是示例对象

@Test
    public void test() {
        List<Ab> list = new ArrayList<>();
        list.add(new Ab("1", "4", "7"));
        list.add(new Ab("2", "5", "7"));
        list.add(new Ab("3", "6", "7"));
        List<String> strings = new ArrayList<>();
        strings.add("111");
        strings.add("222");
        Aa a = new Aa("aa", "man", list, strings);
        String str1 =  DataUtils.marshal(a);
        System.out.println(str1);
    }

    public class Aa{
        String name;

        String sex;

        List<Ab> list;

        List<String> listStr;

        public Aa(String name, String sex, List<Ab> list, List<String> listStr) {
            this.name = name;
            this.sex = sex;
            this.list = list;
            this.listStr = listStr;
        }
    }
    public class Ab{
        String nameDebug;

        String sexDebug;

        String address;

        public Ab(String nameDebug, String sexDebug, String address) {
            this.nameDebug = nameDebug;
            this.sexDebug = sexDebug;
            this.address = address;
        }
    }

得到的错误结果是
{“list”:[{“nameDebug”:“1”,“sexDebug”:“4”,“address”:“7”},{“nameDebug”:“2”,“sexDebug”:“5”,“address”:“7”,},{“nameDebug”:“3”,“sexDebug”:“6”,“address”:“7”}],“listStr”:[“111”,“222”],“name”:“aa”,“sex”:“man”}
这个结果内的list属性对象内并未做出排序

以下是排序代码

// 序列化参数
// 这一步看上去冗余,实际很重要。如果要自己实现,则必须保证这三点:
// 1、保证JSON所有层级上Key的有序性
// 2、保证JSON的所有数值不带多余的小数点
// 3、保证转义逻辑与这段代码一致
    public static String marshal(Object o) {
        String raw = CustomGson.toJson(o);
        Map<?, ?> m = CustomGson.fromJson(raw, LinkedTreeMap.class); // 执行反序列化,把所有JSON对象转换成LinkedTreeMap
        return CustomGson.toJson(m); // 重新序列化,保证JSON所有层级上Key的有序性
    }

    private static final Gson CustomGson = new GsonBuilder()
            .registerTypeAdapter(LinkedTreeMap.class, newMapSerializer()) // 定制LinkedTreeMap序列化,确保所有key按字典序排序
            .registerTypeAdapter(Integer.class, newNumberSerializer()) // 定制数值类型的序列化,确保整数输出不带小数点
            .registerTypeAdapter(Long.class, newNumberSerializer()) // 同上
            .registerTypeAdapter(Double.class, newNumberSerializer()) // 同上
            .disableHtmlEscaping() // 禁用Html Escape,确保符号不转义:&<>='
            .create();

    // 为LinkedTreeMap定制的序列化器
    public static JsonSerializer<LinkedTreeMap<?, ?>> newMapSerializer() {
        return new JsonSerializer<LinkedTreeMap<?,?>>() {
            @Override
            public JsonElement serialize(LinkedTreeMap<?, ?> src, Type typeOfSrc, JsonSerializationContext context) {
                List<String> keys = src.keySet().stream().map(Object::toString).sorted().collect(Collectors.toList());
                JsonObject o = new JsonObject();
                for (String k : keys) {
                    o.add(k, context.serialize(src.get(k)));
                }
                return o;
            }
        };
    }

    // 为Number定制化的序列化器
    private static <T extends Number> JsonSerializer<T> newNumberSerializer() {
        return new JsonSerializer<T>() {
            @Override
            public JsonElement serialize(T number, Type type, JsonSerializationContext context) {
                if (number instanceof Integer) {
                    return new JsonPrimitive(number.intValue());
                }
                if (number instanceof Long) {
                    return new JsonPrimitive(number.longValue());
                }
                if (number instanceof Double) {
                    long longValue = number.longValue();
                    double doubleValue = number.doubleValue();
                    if (longValue == doubleValue) {
                        return new JsonPrimitive(longValue);
                    }
                }
                return new JsonPrimitive(number);
            }
        };
    }

正确输出的结果是:
{“list”:[{“address”:“7”,“nameDebug”:“1”,“sexDebug”:“4”},{“address”:“7”,“nameDebug”:“2”,“sexDebug”:“5”},{“address”:“7”,“nameDebug”:“3”,“sexDebug”:“6”}],“listStr”:[“111”,“222”],“name”:“aa”,“sex”:“man”}
主要调用方法

DataUtils.marshal(a);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值