序列化Java 8 Streams [英] Serializing Java 8 Streams

查看:131
本文介绍了序列化Java 8 Streams的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Jackson来序列化流的输出。 Jackson没有对序列化 java.util.stream.Stream 的内在支持,但它能够序列化 java.util.Iterator

I would like to use Jackson to serialize the output from a stream. Jackson does not have intrinsic support for serializing java.util.stream.Stream, but it is capable of serializing java.util.Iterator.

为了说明问题,我想序列化这个简单的界面:

To illustrate the problem, I would like to serialize this trivial interface:

public interface SerializeMe {
    Iterator<Integer> getMyNumbers();
}

我将比较序列化列表的输出。 iterator() vs. Stream.iterator()

I will be comparing the output from serializing List.iterator() vs. Stream.iterator():

public class SerializeViaList implements SerializeMe {
    @Override
    public Iterator<Integer> getMyNumbers() {
        return Arrays.asList(1, 2, 3).iterator();
    }
}

public class SerializeViaStream implements SerializeMe {
    @Override
    public Iterator<Integer> getMyNumbers() {
        return Arrays.asList(1, 2, 3).stream().iterator();
    }
}

以下方法将演示这两个类的输出:

The following method will demonstrate the output from these two classes:

public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();

    System.out.println("via list: " + mapper.writeValueAsString(new SerializeViaList()));
    System.out.println("via stream: " + mapper.writeValueAsString(new SerializeViaStream()));
}

此输出为:

via list: {"myNumbers":[1,2,3]}
via stream: {"myNumbers":{}}

这表明流迭代器未正确序列化。

This demonstrates that the stream iterator is not correctly serialized.

有趣的是,如果我添加 @JsonSerialize(as = Iterator.class), 会工作 $ c>:

Interestingly, it does work if i add @JsonSerialize(as=Iterator.class):

@JsonSerialize(as=Iterator.class)
public Iterator<Integer> getMyNumbers() {
    // ....
}

我不喜欢我不想为流可以创建的每个类型迭代器编写自定义 JsonSerializer 。我的替代方案是什么?

I don't want to have to write a custom JsonSerializer for every type iterator that a stream can create. What are my alternatives?

推荐答案

Iterator只被识别为附加接口,即只有在没有bean时才使用它序列化程序可以为对象构建。不幸的是,spliterator适配器确实得到了一个虚拟bean序列化器,因为类有一个注释...这不是很好,甚至看起来都不是预期的(这不是检查员使用的注释) afaik)

Iterator is only recognised as an "add-on" interface, i.e. it's only used if no bean serializer was buildable for an object. Unfortunately, the spliterator adaptor does get a dummy bean serializer built since the class has an annotation... this isn't great, and doesn't even seem to be quite what was intended (that isn't an annotation that the inspector uses afaik)

当你指定 @JsonSerialize(as = Iterator.class)时,你强迫解释为Iterator和IteratorSerializer工作正常。

When you specify @JsonSerialize(as=Iterator.class) you're forcing the interpretation as an Iterator, and the IteratorSerializer works fine.

这是我之前编写的Jackson模块,它允许通过顺序序列化其内容来序列化Stream(也是LongStream,IntStream或DoubleStream):

This is a Jackson module I wrote previously to allow serializing a Stream (also LongStream, IntStream or DoubleStream) by serializing its contents sequentially:

public class StreamModule extends SimpleModule {
    public StreamModule() {
        super(StreamModule.class.getSimpleName());
        addSerializer(LongStream.class, new LongStreamSerializer());
        addSerializer(IntStream.class, new IntStreamSerializer());
        addSerializer(DoubleStream.class, new DoubleStreamSerializer());
    }

    @Override
    public void setupModule(SetupContext context) {
        context.addSerializers(new StreamSerializers());
        super.setupModule(context);
    }

    public static class StreamSerializers extends Serializers.Base {
        @Override
        public JsonSerializer<?> findSerializer(SerializationConfig config, JavaType type, BeanDescription beanDesc) {
            Class<?> raw = type.getRawClass();
            if (Stream.class.isAssignableFrom(raw)) {
                JavaType[] params = config.getTypeFactory().findTypeParameters(type, Stream.class);
                JavaType vt = (params == null || params.length != 1) ? TypeFactory.unknownType() : params[0];
                return new StreamSerializer<Object>(config.getTypeFactory().constructParametrizedType(Stream.class, Stream.class, vt), vt);
            }
            return super.findSerializer(config, type, beanDesc);
        }
    }

    static class StreamSerializer<T> extends StdSerializer<Stream<T>> implements ContextualSerializer {
        private final JavaType streamType;
        private final JavaType elemType;

        public StreamSerializer(JavaType streamType, JavaType elemType) {
            super(streamType);
            this.streamType = streamType;
            this.elemType = elemType;
        }

        @Override
        public JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property) throws JsonMappingException {
            if (!elemType.hasRawClass(Object.class) && (provider.isEnabled(MapperFeature.USE_STATIC_TYPING) || elemType.isFinal())) {
                JsonSerializer<Object> elemSerializer = provider.findPrimaryPropertySerializer(elemType, property);
                return new TypedStreamSerializer<T>(streamType, elemSerializer);
            }
            return this;
        }

        @Override
        public void serialize(Stream<T> stream, JsonGenerator jgen, SerializerProvider provider) throws IOException,
                JsonGenerationException {
            jgen.writeStartArray();
            try {
                stream.forEachOrdered(elem -> {
                    try {
                        provider.defaultSerializeValue(elem, jgen);
                    } catch (IOException e) {
                        throw new WrappedIOException(e);
                    }
                });
            } catch (WrappedIOException e) {
                throw (IOException) e.getCause();
            }
            jgen.writeEndArray();
        }
    }

    static class TypedStreamSerializer<T> extends StdSerializer<Stream<T>> {
        private final JsonSerializer<T> elemSerializer;

        @SuppressWarnings("unchecked")
        public TypedStreamSerializer(JavaType streamType, JsonSerializer<?> elemSerializer) {
            super(streamType);
            this.elemSerializer = (JsonSerializer<T>) elemSerializer;
        }

        @Override
        public void serialize(Stream<T> stream, JsonGenerator jgen, SerializerProvider provider) throws IOException,
                JsonGenerationException {
            jgen.writeStartArray();
            try {
                stream.forEachOrdered(elem -> {
                    try {
                        elemSerializer.serialize(elem, jgen, provider);
                    } catch (IOException e) {
                        throw new WrappedIOException(e);
                    }
                });
            } catch (WrappedIOException e) {
                throw (IOException) e.getCause();
            }
            jgen.writeEndArray();
        }
    }

    static class IntStreamSerializer extends StdSerializer<IntStream> {
        public IntStreamSerializer() {
            super(IntStream.class);
        }

        @Override
        public void serialize(IntStream stream, JsonGenerator jgen, SerializerProvider provider) throws IOException,
                JsonGenerationException {
            jgen.writeStartArray();
            try {
                stream.forEachOrdered(value -> {
                    try {
                        jgen.writeNumber(value);
                    } catch (IOException e) {
                        throw new WrappedIOException(e);
                    }
                });
            } catch (WrappedIOException e) {
                throw (IOException) e.getCause();
            }
            jgen.writeEndArray();
        }
    }

    static class LongStreamSerializer extends StdSerializer<LongStream> {
        public LongStreamSerializer() {
            super(LongStream.class);
        }

        @Override
        public void serialize(LongStream stream, JsonGenerator jgen, SerializerProvider provider) throws IOException,
                JsonGenerationException {
            jgen.writeStartArray();
            try {
                stream.forEachOrdered(value -> {
                    try {
                        jgen.writeNumber(value);
                    } catch (IOException e) {
                        throw new WrappedIOException(e);
                    }
                });
            } catch (WrappedIOException e) {
                throw (IOException) e.getCause();
            }
            jgen.writeEndArray();
        }
    }

    static class DoubleStreamSerializer extends StdSerializer<DoubleStream> {
        public DoubleStreamSerializer() {
            super(DoubleStream.class);
        }

        @Override
        public void serialize(DoubleStream stream, JsonGenerator jgen, SerializerProvider provider) throws IOException,
                JsonGenerationException {
            jgen.writeStartArray();
            try {
                stream.forEachOrdered(value -> {
                    try {
                        jgen.writeNumber(value);
                    } catch (IOException e) {
                        throw new WrappedIOException(e);
                    }
                });
            } catch (WrappedIOException e) {
                throw (IOException) e.getCause();
            }
            jgen.writeEndArray();
        }
    }

    public static final class WrappedIOException extends RuntimeException {
        private WrappedIOException(IOException e) {
            super(e);
        }
    }
}

这篇关于序列化Java 8 Streams的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆