From ad0a4e0cf8d424d8b81cf5da3f0b0e3078710797 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Fri, 22 Apr 2016 13:02:23 +0200 Subject: [PATCH] Introduce AbstractSingleValueEncoder This commit introduces the AbstractSingleValueEncoder, an abstract base class for encoders that only handle a single value. --- .../core/codec/support/AbstractDecoder.java | 5 +- .../core/codec/support/AbstractEncoder.java | 5 +- .../support/AbstractSingleValueEncoder.java | 68 +++++++++++++++++++ .../core/codec/support/Jaxb2Encoder.java | 43 +++++------- .../core/codec/support/ResourceEncoder.java | 22 ++---- 5 files changed, 94 insertions(+), 49 deletions(-) create mode 100644 spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractSingleValueEncoder.java diff --git a/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractDecoder.java b/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractDecoder.java index fb00faab0cb..fa1b0102b5d 100644 --- a/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractDecoder.java +++ b/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,8 +31,7 @@ public abstract class AbstractDecoder implements Decoder { private List supportedMimeTypes = Collections.emptyList(); - - public AbstractDecoder(MimeType... supportedMimeTypes) { + protected AbstractDecoder(MimeType... supportedMimeTypes) { this.supportedMimeTypes = Arrays.asList(supportedMimeTypes); } diff --git a/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractEncoder.java b/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractEncoder.java index d0d1920194b..98d1c022a49 100644 --- a/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractEncoder.java +++ b/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,8 +31,7 @@ public abstract class AbstractEncoder implements Encoder { private List supportedMimeTypes = Collections.emptyList(); - - public AbstractEncoder(MimeType... supportedMimeTypes) { + protected AbstractEncoder(MimeType... supportedMimeTypes) { this.supportedMimeTypes = Arrays.asList(supportedMimeTypes); } diff --git a/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractSingleValueEncoder.java b/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractSingleValueEncoder.java new file mode 100644 index 00000000000..15c8ffcc423 --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/core/codec/support/AbstractSingleValueEncoder.java @@ -0,0 +1,68 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.codec.support; + +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; + +import org.springframework.core.ResolvableType; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferAllocator; +import org.springframework.util.MimeType; + +/** + * Abstract base class for {@link org.springframework.core.codec.Encoder} classes that + * can only deal with a single value. + * @author Arjen Poutsma + */ +public abstract class AbstractSingleValueEncoder extends AbstractEncoder { + + public AbstractSingleValueEncoder(MimeType... supportedMimeTypes) { + super(supportedMimeTypes); + } + + @Override + public final Flux encode(Publisher inputStream, + DataBufferAllocator allocator, ResolvableType type, MimeType mimeType, + Object... hints) { + return Flux.from(inputStream). + take(1). + concatMap(t -> { + try { + return encode(t, allocator, type, mimeType); + } + catch (Exception ex) { + return Flux.error(ex); + } + }); + } + + /** + * Encodes {@code T} to an output {@link DataBuffer} stream. + * @param t the value to process + * @param allocator a buffer allocator used to create the output + * @param type the stream element type to process + * @param mimeType the mime type to process + * @param hints Additional information about how to do decode, optional + * @return the output stream + * @throws Exception in case of errors + */ + protected abstract Flux encode(T t, DataBufferAllocator allocator, + ResolvableType type, MimeType mimeType, Object... hints) throws Exception; + + +} diff --git a/spring-web-reactive/src/main/java/org/springframework/core/codec/support/Jaxb2Encoder.java b/spring-web-reactive/src/main/java/org/springframework/core/codec/support/Jaxb2Encoder.java index d2997223423..9674c8b79b4 100644 --- a/spring-web-reactive/src/main/java/org/springframework/core/codec/support/Jaxb2Encoder.java +++ b/spring-web-reactive/src/main/java/org/springframework/core/codec/support/Jaxb2Encoder.java @@ -19,16 +19,13 @@ package org.springframework.core.codec.support; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import javax.xml.bind.JAXBException; -import javax.xml.bind.MarshalException; import javax.xml.bind.Marshaller; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; -import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import org.springframework.core.ResolvableType; -import org.springframework.core.codec.CodecException; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferAllocator; import org.springframework.util.ClassUtils; @@ -42,7 +39,7 @@ import org.springframework.util.MimeTypeUtils; * @author Arjen Poutsma * @see Jaxb2Decoder */ -public class Jaxb2Encoder extends AbstractEncoder { +public class Jaxb2Encoder extends AbstractSingleValueEncoder { private final JaxbContextContainer jaxbContexts = new JaxbContextContainer(); @@ -64,29 +61,21 @@ public class Jaxb2Encoder extends AbstractEncoder { } @Override - public Flux encode(Publisher inputStream, - DataBufferAllocator allocator, ResolvableType type, MimeType mimeType, - Object... hints) { - - return Flux.from(inputStream). - take(1). // only map 1 value to ensure valid XML output - map(value -> { - try { - DataBuffer buffer = allocator.allocateBuffer(1024); - OutputStream outputStream = buffer.asOutputStream(); - Class clazz = ClassUtils.getUserClass(value); - Marshaller marshaller = jaxbContexts.createMarshaller(clazz); - marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name()); - marshaller.marshal(value, outputStream); - return buffer; - } - catch (MarshalException ex) { - throw new CodecException("Could not marshal [" + value + "]: " + ex.getMessage(), ex); - } - catch (JAXBException ex) { - throw new CodecException("Could not instantiate JAXBContext: " + ex.getMessage(), ex); - } - }); + protected Flux encode(Object value, DataBufferAllocator allocator, + ResolvableType type, MimeType mimeType, Object... hints) { + try { + DataBuffer buffer = allocator.allocateBuffer(1024); + OutputStream outputStream = buffer.asOutputStream(); + Class clazz = ClassUtils.getUserClass(value); + Marshaller marshaller = jaxbContexts.createMarshaller(clazz); + marshaller + .setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name()); + marshaller.marshal(value, outputStream); + return Flux.just(buffer); + } + catch (JAXBException ex) { + return Flux.error(ex); + } } diff --git a/spring-web-reactive/src/main/java/org/springframework/core/codec/support/ResourceEncoder.java b/spring-web-reactive/src/main/java/org/springframework/core/codec/support/ResourceEncoder.java index 2451ecf9a84..497b79efd83 100644 --- a/spring-web-reactive/src/main/java/org/springframework/core/codec/support/ResourceEncoder.java +++ b/spring-web-reactive/src/main/java/org/springframework/core/codec/support/ResourceEncoder.java @@ -19,9 +19,7 @@ package org.springframework.core.codec.support; import java.io.IOException; import java.io.InputStream; -import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; import org.springframework.core.ResolvableType; import org.springframework.core.io.Resource; @@ -37,7 +35,7 @@ import org.springframework.util.StreamUtils; * An encoder for {@link Resource}s. * @author Arjen Poutsma */ -public class ResourceEncoder extends AbstractEncoder { +public class ResourceEncoder extends AbstractSingleValueEncoder { public static final int DEFAULT_BUFFER_SIZE = StreamUtils.BUFFER_SIZE; @@ -61,18 +59,10 @@ public class ResourceEncoder extends AbstractEncoder { } @Override - public Flux encode(Publisher inputStream, - DataBufferAllocator allocator, ResolvableType type, MimeType mimeType, - Object... hints) { - return Flux.from(inputStream). - concatMap(resource -> { - try { - InputStream is = resource.getInputStream(); - return DataBufferUtils.read(is, allocator, this.bufferSize); - } - catch (IOException ex) { - return Mono.error(ex); - } - }); + protected Flux encode(Resource resource, DataBufferAllocator allocator, + ResolvableType type, MimeType mimeType, Object... hints) throws IOException { + InputStream is = resource.getInputStream(); + return DataBufferUtils.read(is, allocator, bufferSize); } + }