【问题标题】:How can I serialize/deserialize java.util.stream.Stream using Jackson?如何使用 Jackson 序列化/反序列化 java.util.stream.Stream?
【发布时间】:2015-05-20 03:13:25
【问题描述】:

假设我有以下对象

public class DataObjectA {
    private Stream<DataObjectB> dataObjectBStream;
}

如何使用 Jackson 对它们进行序列化?

【问题讨论】:

  • 你必须写一个custom serializer/deserializer。但我认为该流不太适合 DTO,它们旨在在管道中执行计算。
  • 我知道有人会说流不适合这里,但我有理由在这里。我想知道为什么 Jackson 不将 Stream 的序列化器/反序列化器作为 jackson-JDK8 模块的一部分
  • 正是因为它们不合适。 Jackson 添加了对“数据类型”的支持,喜欢新的 Date API 和Optional

标签: jackson java-8


【解决方案1】:

下面的类有 2 个元素,其中一个是 Stream,必须用 @JsonSerializer 注释 getterStream 方法,然后重写 Serialize 方法,在我的响应 API 中生成 JSON 流:

公共类 DataSetResultBean 扩展 ResultBean { private static final long serialVersionUID = 1L;

private final List<ComponentBean> structure;
private final Stream<DataPoint> datapoints;

private static class DataPointSerializer extends JsonSerializer<Stream<DataPoint>> 
{
    @Override
    public void serialize(Stream<DataPoint> stream, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException
    {
        gen.writeStartArray();
        try
        {
            stream.forEach(dp -> serializeSingle(gen, dp));
        }
        catch (UncheckedIOException e)
        {
            throw (IOException) e.getCause();
        }
        finally
        {
            stream.close();
        }
        gen.writeEndArray();
    }
    
    public synchronized void serializeSingle(JsonGenerator gen, DataPoint dp) throws UncheckedIOException
    {
        try
        {
            gen.writeStartObject();
            
            for (Entry<DataStructureComponent<?, ?, ?>, ScalarValue<?, ?, ?>> entry: dp.entrySet())
            {
                gen.writeFieldName(entry.getKey().getName());
                gen.writeRawValue(entry.getValue().toString());
            }
            
            gen.writeEndObject();
        }
        catch (IOException e)
        {
            throw new UncheckedIOException(e);
        }
    }
}

public DataSetResultBean(DataSet dataset)
{
    super("DATASET");
    
    structure = dataset.getMetadata().stream().map(ComponentBean::new).collect(toList());
    datapoints = dataset.stream();
}

public List<ComponentBean> getStructure()
{
    return structure;
}

@JsonSerialize(using = DataPointSerializer.class)
public Stream<DataPoint> getDatapoints()
{
    return datapoints;
}

}

【讨论】:

    【解决方案2】:

    请参阅 https://github.com/FasterXML/jackson-modules-java8/issues/3 以获取未解决的问题,以向 Jackson 添加 java.util.Stream 支持。包含代码的初步版本。 (编辑:现在在 2.9.0 中合并和支持)。

    如果流是您正在(反)序列化的顶级对象,流支持感觉它会自然/安全地工作,例如从 JAX-RS 资源返回 java.util.stream.Stream&lt;T&gt;,或从 JAX 读取 Stream -RS 客户端。

    正如您在示例中所做的那样,作为(反)序列化对象的成员变量的 Stream 比较棘手,因为它是可变的且一次性使用:

    private Stream&lt;DataObjectB&gt; dataObjectBStream;

    假设它被支持,所有关于存储对流的引用的警告都将适用。您不能多次序列化对象,并且一旦您反序列化包装对象,大概它的流成员将通过 JAX-RS 客户端和 HTTP 连接保留实时连接,这可能会造成意外。

    【讨论】:

    • -1 否决票 我正在使用 Jackson 2.9.2 println new ObjectMapper().version() println new ObjectMapper().writeValueAsString([1, 2].stream( )) 并输出 2.9.2 {"parallel":false}
    • 尝试注册 JDK 8 模块?
    【解决方案3】:

    正如其他人指出的那样,您只能在流上迭代一次。如果这对您有用,您可以使用它来序列化:

    new ObjectMapper().writerFor(Iterator.class).writeValueAsString(dataObjectBStream.iterator())
    

    如果您使用的是 2.5 之前的 Jackson 版本,请使用 writerWithType() 而不是 writerFor()

    【讨论】:

      【解决方案4】:

      你没有。

      Stream 是一次性的操作链,绝不意味着持久。即使将其存储到您的问题中的实例字段中,也表明对其目的存在误解。一旦对流应用了终端操作,它就毫无用处,并且无法克隆流。这样的话,记住字段中不可用的流是没有意义的。

      由于Stream 提供的唯一操作是将更多操作链接到管道并最终对其进行评估,因此无法查询其状态以允许创建与其行为有关的等效流时间>。因此,没有任何持久化框架可以存储它。框架唯一能做的就是遍历流操作的结果元素并存储它们,但这意味着有效地存储一种对象集合而不是Stream。除此之外,Stream 的一次性使用性质还意味着遍历流以存储元素的存储框架具有同时使流不可用的副作用。

      如果要存储元素,请使用普通的Collection

      另一方面,如果你真的想存储行为,你最终会存储一个对象实例,它的实际类实现了该行为。这仍然适用于Streams,因为您可以存储一个类的实例,该实例具有产生所需流的工厂方法。当然,您存储的并不是真正的行为,而是对它的符号引用,但是当您使用 OO 存储框架来存储行为而不是数据时,情况总是如此。

      【讨论】:

      • 问题是关于序列化,而不是持久性或存储。
      • @Adrian Baker:序列化一种持久化机制。即使您使用它来将数据从一台机器传输到另一台机器,这里所说的一切都成立。存储流是没有意义的,您甚至在回答中承认了这一点。最后,您只是在传输 数据 并使其看起来像“流的序列化支持”是一种伪装。
      • “你不知道。”
      • @Adrian Baker:您将“流向/来自 JSON”与“序列化/反序列化流”混为一谈。使原始 Stream 不可用的序列化不是序列化。这个问题是关于序列化的。点。
      • 我只能猜你指的是java.io.Serializable的严格契约吧?我认为这个问题,通常是杰克逊,指的是更广泛和基本意义上的序列化,基于一些 Java 对象生成一些 JSON,这些对象不需要实现 java.io.SerializableHere's a really basic example.
      猜你喜欢
      • 2019-07-28
      • 2012-11-18
      • 2021-12-13
      • 1970-01-01
      • 2019-10-25
      • 1970-01-01
      • 1970-01-01
      • 2013-01-01
      • 2016-12-11
      相关资源
      最近更新 更多