2016-01-12 2 views
2

Я хотел бы использовать Jackson для сериализации вывода из потока. У Jackson нет встроенной поддержки для сериализации java.util.stream.Stream, но он способен сериализовать java.util.Iterator.Сериализация Java 8 потоков

Чтобы проиллюстрировать эту проблему, я хотел бы сериализовать этот тривиальный интерфейс:

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

я буду сравнения выходных от сериализации 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(); 
    } 
} 

Следующий метод продемонстрирует выход из этих двух классов:

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":{}} 

Это свидетельствует о том, что поток итератор не правильно сериализованная.

Интересно, что делает работу, если я добавить @JsonSerialize(as=Iterator.class):

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

Я не хочу, чтобы написать пользовательский JsonSerializer для каждого типа итератора, что поток может создать. Каковы мои альтернативы?

+0

дубликата http://stackoverflow.com/questions/29103372/how-can-i-serialize-deserialize-java-util-stream-stream-using-jackson? –

+0

Почему вы не применили '.collect (Collectors.toList());'? Вам нужно потоковое содержимое потока? –

ответ

5

Итератор распознается только как «дополнительный» интерфейс, т. Е. Он используется только в том случае, если для объекта не был создан универсальный сериализатор. К сожалению, адаптер spliterator действительно получает фиктивный сериализатор фаз, построенный, поскольку класс имеет аннотацию ... это не очень удобно и даже не кажется совершенно то, что было предназначено (это не аннотация, который использует инспектор afaik)

Когда вы укажете @JsonSerialize(as=Iterator.class), вы вынуждаете интерпретацию как Итератор, а IteratorSerializer отлично работает.

Это модуль Джексон я написал ранее, чтобы сериализации поток (также LongStream, IntStream или DoubleStream) по сериализации его содержимое последовательно:

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); 
     } 
    } 
} 
Смежные вопросы