【问题标题】:Jackson ObjectMapper: Can java.util.Set be serialized to JSON array in ascending sorted order?Jackson ObjectMapper:java.util.Set 可以按升序序列化为 JSON 数组吗?
【发布时间】:2017-11-06 19:31:34
【问题描述】:

我有一个 Comparable 类型的 Java java.util.Set,我想按升序将其序列化为 JSON 数组。

有一个对象映射器功能可以序列化按映射键排序的映射,但没有关于 java 集合的任何说明。如果我将项目存储在 POJO 中的 java.util.Set 中,Jackson ObjectMapper 会以任何顺序将它们序列化为 JSON 数组吗?

如果没有,我正在考虑为此目的为该集合编写一个自定义序列化程序 - 有人可以建议更好的方法吗?


最终,目标是将唯一整数数组反序列化到“请求”pojo 中的某种容器中。然后处理请求并将该输入字段传递到“响应”对象中的相应输出字段(未更改)。

我想将 POJO 中的数据存储为 java.util.Set<Integer> 只是为了让所有用户满意(如果您尝试将其存储为 Set 的子类型,那么 POJO 界面的消费者可能会因为他们不能只获得Set,而必须期待HashSetTreeSet)。

这行得通吗?

  1. JSON 数组[5,4,3,2,1] 被反序列化为Set<Integer> 但是,我在setter 方法上使用@JsonDeserialize(as=TreeSet.class)。所以对象的运行时类型现在是 TreeSet(即使它在 POJO 中存储为 Set)。
  2. Set 通过服务器传递并最终存储在响应 POJO 中(运行时类型仍为 TreeSet,即使 POJO 字段类型为 Set)。
  3. ObjectMapperTreeSet 序列化为 JSON 数组 [1,2,3,4,5](因为 TreeSet 是自然排序的)。

上面的第 3 项是我想知道的——ObjectMapper 会使用 POJO 字段的运行时类型还是声明的类型?


如何确保我的Set 按排序顺序转换为 JSON 数组?

【问题讨论】:

标签: java json serialization jackson set


【解决方案1】:

JSON 数组是一个 有序 集合,就像 Java 数组一样:

数组是一个有序值的集合。数组以[(左括号)开头,以](右括号)结尾。值由,(逗号)分隔。

但是,有序并不意味着排序。它只是意味着它保留给定值的顺序

  • 如果Set被排序(例如TreeSet),那么JSON数组被排序,按照Set的排序顺序:

    TreeSet:元素使用它们的自然顺序或在集合创建时提供的Comparator 进行排序,具体取决于使用的构造函数。

  • 如果Set是无序的(例如HashSet),那么JSON数组就是Set返回的任意顺序。

    HashSet:不保证集合的迭代顺序;特别是,它不保证订单会随着时间的推移保持不变。

这不同于JSON 对象的字段

object 是一组 无序 名称/值对。对象以{(左大括号)开头,以}(右大括号)结尾。每个名称后跟:(冒号),名称/值对用,(逗号)分隔。

【讨论】:

  • 谢谢 - 其他人建议同时使用 TreeSet。听起来像一个计划!
【解决方案2】:

可以创建 Jackson Converter 以对 Set 进行排序,并将其转换为具有所需排序顺序的元素的 LinkedHashSet

public class OrderedSetConverter 
        extends StdConverter<Set<Integer>, Set< Integer >> {
    @Override
    public Set<DayOfWeek> convert(Set<Integer> value) {
        return value == null ? null : value.stream()
                .sorted(Comparator.nullsLast(Comparator.naturalOrder()))
                .collect(Collectors.toCollection(LinkedHashSet::new));
    }
}

public class MyType {
    @JsonSerialize(converter = OrderedSetConverter.class)
    private Set<Integer> myValues;
}

当使用JsonSerialize 应用于属性时,生成的 JSON 数组将按排序顺序排列。此外,这可以使用JsonDeserialize 应用于属性,确保读取 JSON 产生的对象将具有具有排序迭代顺序的LinkedHashSet


出于几个原因,我在我的项目中使用了这种方法,而不是使用TreeSet。首先,我想接受集合中的null 值(主要是这样我就可以使用我的标准空值处理来处理它们并带有适当的API 错误消息,而不是在创建TreeSet 时出现NullPointerException其次,TreeSet从标准集合契约改变了集合的语义,使用Comparable对象的compareTo方法来判断两个对象是否相等,而不是Objevt.equals()。最后,我希望我的客户Java API 能够使用对其应用程序有意义的任何有效Set 类型,而不是仅限于TreeSet

【讨论】:

    猜你喜欢
    • 2018-07-14
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 2015-02-28
    • 2021-06-22
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    相关资源
    最近更新 更多