我怎样才能让杰克逊按排序顺序序列化一个未排序的集合?

The*_*33k 6 java serialization json set jackson

我有一个 Java 对象,其中包含一组未排序的可比较对象。有没有办法让杰克逊在将它序列化为 JSON 列表之前对它进行排序?

我想要这种行为,以便在 Java 中表示时相等的对象确定性地生成相同的 JSON。

杰克逊有什么设置可以做到这一点吗?还是编写自定义序列化程序的最佳选择?

单个自定义序列化程序可以在所有Set<T>地方工作T implements Comparable吗?

这个问题不是jackson to sort the response by using the field name only的副本,它询问如何对 Map 中的键进行排序。这个问题是关于对 Set 中的元素进行排序。

Mic*_*ber 6

即使您使用接口的HashSet实现,Set当两个集合包含相同的对象时,它也会产生相同的结果。因此,您不需要对集合进行排序来为两个不同但相等(包含相同对象)的集合生成相同的 JSON。

但是如果你想强制 Jackson 在序列化之前对集合进行排序,你需要实现自定义序列化器。

我们只能为其注册序列化器Set,它将用于包含Comparable对象的集合和不包含对象的集合,因此必须在自定义实现中进行检查。

示例实现可能如下所示:

class SortedSetJsonSerializer extends JsonSerializer<Set> {

    @Override
    public void serialize(Set set, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (set == null) {
            gen.writeNull();
            return;
        }

        gen.writeStartArray();
        if (!set.isEmpty()) {
            // create sorted set only if it itself is not already SortedSet
            if (!SortedSet.class.isAssignableFrom(set.getClass())) {
                Object item = set.iterator().next();
                if (Comparable.class.isAssignableFrom(item.getClass())) {
                    // and only if items are Comparable
                    set = new TreeSet(set);
                }
            }
            for (Object item : set) {
                gen.writeObject(item);
            }
        }
        gen.writeEndArray();
    }
} 
Run Code Online (Sandbox Code Playgroud)

和示例用法:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.IntStream;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        Set<Integer> ints = newSet();

        SimpleModule module = new SimpleModule();
        module.addSerializer(Set.class, new SortedSetJsonSerializer());
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(module);

        System.out.println(mapper.writeValueAsString(new MyModel(ints)));
    }

    private static Set<Integer> newSet() {
        Set<Integer> ints = new HashSet<>();
        IntStream.range(10, 20).forEach(ints::add);

        return ints;
    }
}

class MyModel {
    private Set<Integer> integers;

    public MyModel(Set<Integer> integers) {
        this.integers = integers;
    }

    public Set<Integer> getIntegers() {
        return integers;
    }

    public void setIntegers(Set<Integer> integers) {
        this.integers = integers;
    }
}
Run Code Online (Sandbox Code Playgroud)

印刷:

{"integers":[10,11,12,13,14,15,16,17,18,19]}
Run Code Online (Sandbox Code Playgroud)