5 changed files with 717 additions and 469 deletions
@ -0,0 +1,400 @@
@@ -0,0 +1,400 @@
|
||||
/* |
||||
* Copyright 2002-2017 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.http.codec; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.function.Supplier; |
||||
|
||||
import org.springframework.core.ResolvableType; |
||||
import org.springframework.core.codec.ByteArrayDecoder; |
||||
import org.springframework.core.codec.ByteArrayEncoder; |
||||
import org.springframework.core.codec.ByteBufferDecoder; |
||||
import org.springframework.core.codec.ByteBufferEncoder; |
||||
import org.springframework.core.codec.CharSequenceEncoder; |
||||
import org.springframework.core.codec.DataBufferDecoder; |
||||
import org.springframework.core.codec.DataBufferEncoder; |
||||
import org.springframework.core.codec.Decoder; |
||||
import org.springframework.core.codec.Encoder; |
||||
import org.springframework.core.codec.ResourceDecoder; |
||||
import org.springframework.core.codec.StringDecoder; |
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder; |
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder; |
||||
import org.springframework.http.codec.xml.Jaxb2XmlDecoder; |
||||
import org.springframework.http.codec.xml.Jaxb2XmlEncoder; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.ClassUtils; |
||||
|
||||
/** |
||||
* Base class for client or server codec configurers. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 5.0 |
||||
*/ |
||||
public abstract class AbstractCodecConfigurer { |
||||
|
||||
public static final boolean jackson2Present = |
||||
ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", |
||||
ServerCodecConfigurer.class.getClassLoader()) && |
||||
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", |
||||
ServerCodecConfigurer.class.getClassLoader()); |
||||
|
||||
public static final boolean jaxb2Present = |
||||
ClassUtils.isPresent("javax.xml.bind.Binder", ServerCodecConfigurer.class.getClassLoader()); |
||||
|
||||
|
||||
private final DefaultCodecConfigurer defaultCodecs; |
||||
|
||||
private final CustomCodecConfigurer customCodecs = new CustomCodecConfigurer(); |
||||
|
||||
|
||||
/** |
||||
* Protected constructor with the configurer for default readers and writers. |
||||
*/ |
||||
protected AbstractCodecConfigurer(DefaultCodecConfigurer defaultCodecConfigurer) { |
||||
Assert.notNull(defaultCodecConfigurer, "DefaultCodecConfigurer is required."); |
||||
this.defaultCodecs = defaultCodecConfigurer; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Provide overrides for built-in HTTP message readers or writers. |
||||
*/ |
||||
public DefaultCodecConfigurer defaultCodec() { |
||||
return this.defaultCodecs; |
||||
} |
||||
|
||||
/** |
||||
* Whether to make default HTTP message reader and writer registrations. |
||||
* <p>By default this is set to {@code "true"}. |
||||
*/ |
||||
public void registerDefaults(boolean registerDefaults) { |
||||
this.defaultCodec().setSuppressed(!registerDefaults); |
||||
} |
||||
|
||||
/** |
||||
* Register a custom encoder or decoder. |
||||
*/ |
||||
public CustomCodecConfigurer customCodec() { |
||||
return this.customCodecs; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Prepare a list of HTTP message readers. |
||||
*/ |
||||
public List<HttpMessageReader<?>> getReaders() { |
||||
|
||||
List<HttpMessageReader<?>> result = new ArrayList<>(); |
||||
|
||||
addDefaultTypedReaders(result); |
||||
addCustomTypedReaders(result); |
||||
|
||||
addDefaultObjectReaders(result); |
||||
addCustomObjectReaders(result); |
||||
|
||||
defaultCodec().addStringReaderTo(result); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Add built-in, concrete, Java type readers. |
||||
*/ |
||||
protected void addDefaultTypedReaders(List<HttpMessageReader<?>> result) { |
||||
defaultCodec().addReaderTo(result, ByteArrayDecoder.class, ByteArrayDecoder::new); |
||||
defaultCodec().addReaderTo(result, ByteBufferDecoder.class, ByteBufferDecoder::new); |
||||
defaultCodec().addReaderTo(result, DataBufferDecoder.class, DataBufferDecoder::new); |
||||
defaultCodec().addReaderTo(result, ResourceDecoder.class, ResourceDecoder::new); |
||||
defaultCodec().addStringReaderTextOnlyTo(result); |
||||
} |
||||
|
||||
/** |
||||
* Add custom, concrete, Java type readers. |
||||
*/ |
||||
protected void addCustomTypedReaders(List<HttpMessageReader<?>> result) { |
||||
customCodec().addTypedReadersTo(result); |
||||
} |
||||
|
||||
/** |
||||
* Add built-in, Object-based readers. |
||||
*/ |
||||
protected void addDefaultObjectReaders(List<HttpMessageReader<?>> result) { |
||||
if (jaxb2Present) { |
||||
defaultCodec().addReaderTo(result, Jaxb2XmlDecoder.class, Jaxb2XmlDecoder::new); |
||||
} |
||||
if (jackson2Present) { |
||||
defaultCodec().addReaderTo(result, Jackson2JsonDecoder.class, Jackson2JsonDecoder::new); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Add custom, Object-based readers. |
||||
*/ |
||||
protected void addCustomObjectReaders(List<HttpMessageReader<?>> result) { |
||||
customCodec().addObjectReadersTo(result); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Prepare a list of HTTP message writers. |
||||
*/ |
||||
public List<HttpMessageWriter<?>> getWriters() { |
||||
|
||||
List<HttpMessageWriter<?>> result = new ArrayList<>(); |
||||
|
||||
addDefaultTypedWriter(result); |
||||
addCustomTypedWriter(result); |
||||
|
||||
addDefaultObjectWriters(result); |
||||
addCustomObjectWriters(result); |
||||
|
||||
// String + "*/*"
|
||||
defaultCodec().addStringWriterTo(result); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Add built-in, concrete, Java type readers. |
||||
*/ |
||||
protected void addDefaultTypedWriter(List<HttpMessageWriter<?>> result) { |
||||
defaultCodec().addWriterTo(result, ByteArrayEncoder.class, ByteArrayEncoder::new); |
||||
defaultCodec().addWriterTo(result, ByteBufferEncoder.class, ByteBufferEncoder::new); |
||||
defaultCodec().addWriterTo(result, DataBufferEncoder.class, DataBufferEncoder::new); |
||||
defaultCodec().addWriterTo(result, ResourceHttpMessageWriter::new); |
||||
defaultCodec().addStringWriterTextPlainOnlyTo(result); |
||||
} |
||||
|
||||
/** |
||||
* Add custom, concrete, Java type readers. |
||||
*/ |
||||
protected void addCustomTypedWriter(List<HttpMessageWriter<?>> result) { |
||||
customCodec().addTypedWritersTo(result); |
||||
} |
||||
|
||||
/** |
||||
* Add built-in, Object-based readers. |
||||
*/ |
||||
protected void addDefaultObjectWriters(List<HttpMessageWriter<?>> result) { |
||||
if (jaxb2Present) { |
||||
defaultCodec().addWriterTo(result, Jaxb2XmlEncoder.class, Jaxb2XmlEncoder::new); |
||||
} |
||||
if (jackson2Present) { |
||||
defaultCodec().addWriterTo(result, Jackson2JsonEncoder.class, Jackson2JsonEncoder::new); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Add custom, Object-based readers. |
||||
*/ |
||||
protected void addCustomObjectWriters(List<HttpMessageWriter<?>> result) { |
||||
customCodec().addObjectWritersTo(result); |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* A registry and a factory for built-in HTTP message readers and writers. |
||||
*/ |
||||
public static class DefaultCodecConfigurer { |
||||
|
||||
private boolean suppressed = false; |
||||
|
||||
private final Map<Class<?>, HttpMessageReader<?>> readers = new HashMap<>(); |
||||
|
||||
private final Map<Class<?>, HttpMessageWriter<?>> writers = new HashMap<>(); |
||||
|
||||
|
||||
/** |
||||
* Override the default Jackson {@code Decoder}. |
||||
* @param decoder the decoder to use |
||||
*/ |
||||
public void jackson2Decoder(Jackson2JsonDecoder decoder) { |
||||
this.readers.put(Jackson2JsonDecoder.class, new DecoderHttpMessageReader<>(decoder)); |
||||
} |
||||
|
||||
/** |
||||
* Override the default Jackson {@code Encoder} for JSON. |
||||
* @param encoder the encoder to use |
||||
*/ |
||||
public void jackson2Encoder(Jackson2JsonEncoder encoder) { |
||||
this.writers.put(Jackson2JsonEncoder.class, new EncoderHttpMessageWriter<>(encoder)); |
||||
} |
||||
|
||||
|
||||
// Accessors for internal use...
|
||||
|
||||
|
||||
protected Map<Class<?>, HttpMessageReader<?>> getReaders() { |
||||
return this.readers; |
||||
} |
||||
|
||||
protected Map<Class<?>, HttpMessageWriter<?>> getWriters() { |
||||
return this.writers; |
||||
} |
||||
|
||||
private void setSuppressed(boolean suppressed) { |
||||
this.suppressed = suppressed; |
||||
} |
||||
|
||||
|
||||
// Protected methods for building a list of default readers or writers...
|
||||
|
||||
|
||||
protected <T, D extends Decoder<T>> void addReaderTo(List<HttpMessageReader<?>> result, |
||||
Class<D> key, Supplier<D> fallback) { |
||||
|
||||
addReaderTo(result, () -> findDecoderReader(key, fallback)); |
||||
} |
||||
|
||||
protected void addReaderTo(List<HttpMessageReader<?>> result, |
||||
Supplier<HttpMessageReader<?>> reader) { |
||||
|
||||
if (!this.suppressed) { |
||||
result.add(reader.get()); |
||||
} |
||||
} |
||||
|
||||
protected <T, D extends Decoder<T>> DecoderHttpMessageReader<?> findDecoderReader( |
||||
Class<D> decoderType, Supplier<D> fallback) { |
||||
|
||||
DecoderHttpMessageReader<?> reader = (DecoderHttpMessageReader<?>) this.readers.get(decoderType); |
||||
return reader != null ? reader : new DecoderHttpMessageReader<>(fallback.get()); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
protected HttpMessageReader<?> findReader(Class<?> key, Supplier<HttpMessageReader<?>> fallback) { |
||||
return this.readers.containsKey(key) ? this.readers.get(key) : fallback.get(); |
||||
} |
||||
|
||||
|
||||
protected <T, E extends Encoder<T>> void addWriterTo(List<HttpMessageWriter<?>> result, |
||||
Class<E> key, Supplier<E> fallback) { |
||||
|
||||
addWriterTo(result, () -> findEncoderWriter(key, fallback)); |
||||
} |
||||
|
||||
protected void addWriterTo(List<HttpMessageWriter<?>> result, |
||||
Supplier<HttpMessageWriter<?>> writer) { |
||||
|
||||
if (!this.suppressed) { |
||||
result.add(writer.get()); |
||||
} |
||||
} |
||||
|
||||
protected <T, E extends Encoder<T>> EncoderHttpMessageWriter<?> findEncoderWriter( |
||||
Class<E> encoderType, Supplier<E> fallback) { |
||||
|
||||
EncoderHttpMessageWriter<?> writer = (EncoderHttpMessageWriter<?>) this.writers.get(encoderType); |
||||
return writer != null ? writer : new EncoderHttpMessageWriter<>(fallback.get()); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
protected HttpMessageWriter<?> findWriter(Class<?> key, Supplier<HttpMessageWriter<?>> fallback) { |
||||
return this.writers.containsKey(key) ? this.writers.get(key) : fallback.get(); |
||||
} |
||||
|
||||
|
||||
protected void addStringReaderTextOnlyTo(List<HttpMessageReader<?>> result) { |
||||
addReaderTo(result, () -> new DecoderHttpMessageReader<>(StringDecoder.textPlainOnly(true))); |
||||
} |
||||
|
||||
protected void addStringReaderTo(List<HttpMessageReader<?>> result) { |
||||
addReaderTo(result, () -> new DecoderHttpMessageReader<>(StringDecoder.allMimeTypes(true))); |
||||
} |
||||
|
||||
protected void addStringWriterTextPlainOnlyTo(List<HttpMessageWriter<?>> result) { |
||||
addWriterTo(result, () -> new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly())); |
||||
} |
||||
|
||||
protected void addStringWriterTo(List<HttpMessageWriter<?>> result) { |
||||
addWriterTo(result, () -> new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes())); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Registry and container for custom HTTP message readers and writers. |
||||
*/ |
||||
public static class CustomCodecConfigurer { |
||||
|
||||
private final List<HttpMessageReader<?>> typedReaders = new ArrayList<>(); |
||||
|
||||
private final List<HttpMessageWriter<?>> typedWriters = new ArrayList<>(); |
||||
|
||||
private final List<HttpMessageReader<?>> objectReaders = new ArrayList<>(); |
||||
|
||||
private final List<HttpMessageWriter<?>> objectWriters = new ArrayList<>(); |
||||
|
||||
|
||||
/** |
||||
* Add a custom {@code Decoder} internally wrapped with |
||||
* {@link DecoderHttpMessageReader}). |
||||
*/ |
||||
public void decoder(Decoder<?> decoder) { |
||||
reader(new DecoderHttpMessageReader<>(decoder)); |
||||
} |
||||
|
||||
/** |
||||
* Add a custom {@code Encoder}, internally wrapped with |
||||
* {@link EncoderHttpMessageWriter}. |
||||
*/ |
||||
public void encoder(Encoder<?> encoder) { |
||||
writer(new EncoderHttpMessageWriter<>(encoder)); |
||||
} |
||||
|
||||
/** |
||||
* Add a custom {@link HttpMessageReader}. For readers of type |
||||
* {@link DecoderHttpMessageReader} consider using the shortcut |
||||
* {@link #decoder(Decoder)} instead. |
||||
*/ |
||||
public void reader(HttpMessageReader<?> reader) { |
||||
boolean canReadToObject = reader.canRead(ResolvableType.forClass(Object.class), null); |
||||
(canReadToObject ? this.objectReaders : this.typedReaders).add(reader); |
||||
} |
||||
|
||||
/** |
||||
* Add a custom {@link HttpMessageWriter}. For readers of type |
||||
* {@link EncoderHttpMessageWriter} consider using the shortcut |
||||
* {@link #encoder(Encoder)} instead. |
||||
*/ |
||||
public void writer(HttpMessageWriter<?> writer) { |
||||
boolean canWriteObject = writer.canWrite(ResolvableType.forClass(Object.class), null); |
||||
(canWriteObject ? this.objectWriters : this.typedWriters).add(writer); |
||||
} |
||||
|
||||
|
||||
// Internal methods for building a list of custom readers or writers...
|
||||
|
||||
protected void addTypedReadersTo(List<HttpMessageReader<?>> result) { |
||||
result.addAll(this.typedReaders); |
||||
} |
||||
|
||||
protected void addObjectReadersTo(List<HttpMessageReader<?>> result) { |
||||
result.addAll(this.objectReaders); |
||||
} |
||||
|
||||
protected void addTypedWritersTo(List<HttpMessageWriter<?>> result) { |
||||
result.addAll(this.typedWriters); |
||||
} |
||||
|
||||
protected void addObjectWritersTo(List<HttpMessageWriter<?>> result) { |
||||
result.addAll(this.objectWriters); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,289 @@
@@ -0,0 +1,289 @@
|
||||
/* |
||||
* Copyright 2002-2017 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.http.codec; |
||||
|
||||
import java.util.List; |
||||
import java.util.concurrent.atomic.AtomicInteger; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.core.ResolvableType; |
||||
import org.springframework.core.codec.ByteArrayDecoder; |
||||
import org.springframework.core.codec.ByteArrayEncoder; |
||||
import org.springframework.core.codec.ByteBufferDecoder; |
||||
import org.springframework.core.codec.ByteBufferEncoder; |
||||
import org.springframework.core.codec.CharSequenceEncoder; |
||||
import org.springframework.core.codec.DataBufferDecoder; |
||||
import org.springframework.core.codec.DataBufferEncoder; |
||||
import org.springframework.core.codec.Decoder; |
||||
import org.springframework.core.codec.Encoder; |
||||
import org.springframework.core.codec.ResourceDecoder; |
||||
import org.springframework.core.codec.StringDecoder; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder; |
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder; |
||||
import org.springframework.http.codec.xml.Jaxb2XmlDecoder; |
||||
import org.springframework.http.codec.xml.Jaxb2XmlEncoder; |
||||
import org.springframework.util.MimeTypeUtils; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertSame; |
||||
import static org.junit.Assert.assertTrue; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.when; |
||||
import static org.springframework.core.ResolvableType.forClass; |
||||
|
||||
/** |
||||
* Unit tests for {@link ServerCodecConfigurer}. |
||||
* @author Rossen Stoyanchev |
||||
*/ |
||||
public class CodecConfigurerTests { |
||||
|
||||
private final TestCodecConfigurer configurer = new TestCodecConfigurer(); |
||||
|
||||
private final AtomicInteger index = new AtomicInteger(0); |
||||
|
||||
|
||||
@Test |
||||
public void defaultReaders() throws Exception { |
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders(); |
||||
assertEquals(8, readers.size()); |
||||
assertEquals(ByteArrayDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertEquals(ByteBufferDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertEquals(DataBufferDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertEquals(ResourceDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertStringDecoder(getNextDecoder(readers), true); |
||||
assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertStringDecoder(getNextDecoder(readers), false); |
||||
} |
||||
|
||||
@Test |
||||
public void defaultWriters() throws Exception { |
||||
List<HttpMessageWriter<?>> writers = this.configurer.getWriters(); |
||||
assertEquals(8, writers.size()); |
||||
assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass()); |
||||
assertStringEncoder(getNextEncoder(writers), true); |
||||
assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertStringEncoder(getNextEncoder(writers), false); |
||||
} |
||||
|
||||
@Test |
||||
public void defaultAndCustomReaders() throws Exception { |
||||
|
||||
Decoder<?> customDecoder1 = mock(Decoder.class); |
||||
Decoder<?> customDecoder2 = mock(Decoder.class); |
||||
|
||||
when(customDecoder1.canDecode(ResolvableType.forClass(Object.class), null)).thenReturn(false); |
||||
when(customDecoder2.canDecode(ResolvableType.forClass(Object.class), null)).thenReturn(true); |
||||
|
||||
HttpMessageReader<?> customReader1 = mock(HttpMessageReader.class); |
||||
HttpMessageReader<?> customReader2 = mock(HttpMessageReader.class); |
||||
|
||||
when(customReader1.canRead(ResolvableType.forClass(Object.class), null)).thenReturn(false); |
||||
when(customReader2.canRead(ResolvableType.forClass(Object.class), null)).thenReturn(true); |
||||
|
||||
this.configurer.customCodec().decoder(customDecoder1); |
||||
this.configurer.customCodec().decoder(customDecoder2); |
||||
|
||||
this.configurer.customCodec().reader(customReader1); |
||||
this.configurer.customCodec().reader(customReader2); |
||||
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders(); |
||||
|
||||
assertEquals(12, readers.size()); |
||||
assertEquals(ByteArrayDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertEquals(ByteBufferDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertEquals(DataBufferDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertEquals(ResourceDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertEquals(StringDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertSame(customDecoder1, getNextDecoder(readers)); |
||||
assertSame(customReader1, readers.get(this.index.getAndIncrement())); |
||||
assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass()); |
||||
assertSame(customDecoder2, getNextDecoder(readers)); |
||||
assertSame(customReader2, readers.get(this.index.getAndIncrement())); |
||||
assertEquals(StringDecoder.class, getNextDecoder(readers).getClass()); |
||||
} |
||||
|
||||
@Test |
||||
public void defaultAndCustomWriters() throws Exception { |
||||
|
||||
Encoder<?> customEncoder1 = mock(Encoder.class); |
||||
Encoder<?> customEncoder2 = mock(Encoder.class); |
||||
|
||||
when(customEncoder1.canEncode(ResolvableType.forClass(Object.class), null)).thenReturn(false); |
||||
when(customEncoder2.canEncode(ResolvableType.forClass(Object.class), null)).thenReturn(true); |
||||
|
||||
HttpMessageWriter<?> customWriter1 = mock(HttpMessageWriter.class); |
||||
HttpMessageWriter<?> customWriter2 = mock(HttpMessageWriter.class); |
||||
|
||||
when(customWriter1.canWrite(ResolvableType.forClass(Object.class), null)).thenReturn(false); |
||||
when(customWriter2.canWrite(ResolvableType.forClass(Object.class), null)).thenReturn(true); |
||||
|
||||
this.configurer.customCodec().encoder(customEncoder1); |
||||
this.configurer.customCodec().encoder(customEncoder2); |
||||
|
||||
this.configurer.customCodec().writer(customWriter1); |
||||
this.configurer.customCodec().writer(customWriter2); |
||||
|
||||
List<HttpMessageWriter<?>> writers = this.configurer.getWriters(); |
||||
|
||||
assertEquals(12, writers.size()); |
||||
assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass()); |
||||
assertEquals(CharSequenceEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertSame(customEncoder1, getNextEncoder(writers)); |
||||
assertSame(customWriter1, writers.get(this.index.getAndIncrement())); |
||||
assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass()); |
||||
assertSame(customEncoder2, getNextEncoder(writers)); |
||||
assertSame(customWriter2, writers.get(this.index.getAndIncrement())); |
||||
assertEquals(CharSequenceEncoder.class, getNextEncoder(writers).getClass()); |
||||
} |
||||
|
||||
@Test |
||||
public void defaultsOffCustomReaders() throws Exception { |
||||
|
||||
Decoder<?> customDecoder1 = mock(Decoder.class); |
||||
Decoder<?> customDecoder2 = mock(Decoder.class); |
||||
|
||||
when(customDecoder1.canDecode(ResolvableType.forClass(Object.class), null)).thenReturn(false); |
||||
when(customDecoder2.canDecode(ResolvableType.forClass(Object.class), null)).thenReturn(true); |
||||
|
||||
HttpMessageReader<?> customReader1 = mock(HttpMessageReader.class); |
||||
HttpMessageReader<?> customReader2 = mock(HttpMessageReader.class); |
||||
|
||||
when(customReader1.canRead(ResolvableType.forClass(Object.class), null)).thenReturn(false); |
||||
when(customReader2.canRead(ResolvableType.forClass(Object.class), null)).thenReturn(true); |
||||
|
||||
this.configurer.customCodec().decoder(customDecoder1); |
||||
this.configurer.customCodec().decoder(customDecoder2); |
||||
|
||||
this.configurer.customCodec().reader(customReader1); |
||||
this.configurer.customCodec().reader(customReader2); |
||||
|
||||
this.configurer.registerDefaults(false); |
||||
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders(); |
||||
|
||||
assertEquals(4, readers.size()); |
||||
assertSame(customDecoder1, getNextDecoder(readers)); |
||||
assertSame(customReader1, readers.get(this.index.getAndIncrement())); |
||||
assertSame(customDecoder2, getNextDecoder(readers)); |
||||
assertSame(customReader2, readers.get(this.index.getAndIncrement())); |
||||
} |
||||
|
||||
@Test |
||||
public void defaultsOffWithCustomWriters() throws Exception { |
||||
|
||||
Encoder<?> customEncoder1 = mock(Encoder.class); |
||||
Encoder<?> customEncoder2 = mock(Encoder.class); |
||||
|
||||
when(customEncoder1.canEncode(ResolvableType.forClass(Object.class), null)).thenReturn(false); |
||||
when(customEncoder2.canEncode(ResolvableType.forClass(Object.class), null)).thenReturn(true); |
||||
|
||||
HttpMessageWriter<?> customWriter1 = mock(HttpMessageWriter.class); |
||||
HttpMessageWriter<?> customWriter2 = mock(HttpMessageWriter.class); |
||||
|
||||
when(customWriter1.canWrite(ResolvableType.forClass(Object.class), null)).thenReturn(false); |
||||
when(customWriter2.canWrite(ResolvableType.forClass(Object.class), null)).thenReturn(true); |
||||
|
||||
this.configurer.customCodec().encoder(customEncoder1); |
||||
this.configurer.customCodec().encoder(customEncoder2); |
||||
|
||||
this.configurer.customCodec().writer(customWriter1); |
||||
this.configurer.customCodec().writer(customWriter2); |
||||
|
||||
this.configurer.registerDefaults(false); |
||||
|
||||
List<HttpMessageWriter<?>> writers = this.configurer.getWriters(); |
||||
|
||||
assertEquals(4, writers.size()); |
||||
assertSame(customEncoder1, getNextEncoder(writers)); |
||||
assertSame(customWriter1, writers.get(this.index.getAndIncrement())); |
||||
assertSame(customEncoder2, getNextEncoder(writers)); |
||||
assertSame(customWriter2, writers.get(this.index.getAndIncrement())); |
||||
} |
||||
|
||||
@Test |
||||
public void jackson2DecoderOverride() throws Exception { |
||||
|
||||
Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(); |
||||
this.configurer.defaultCodec().jackson2Decoder(decoder); |
||||
|
||||
assertSame(decoder, this.configurer.getReaders().stream() |
||||
.filter(writer -> writer instanceof DecoderHttpMessageReader) |
||||
.map(writer -> ((DecoderHttpMessageReader<?>) writer).getDecoder()) |
||||
.filter(e -> Jackson2JsonDecoder.class.equals(e.getClass())) |
||||
.findFirst() |
||||
.filter(e -> e == decoder).orElse(null)); |
||||
} |
||||
|
||||
@Test |
||||
public void jackson2EncoderOverride() throws Exception { |
||||
|
||||
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder(); |
||||
this.configurer.defaultCodec().jackson2Encoder(encoder); |
||||
|
||||
assertSame(encoder, this.configurer.getWriters().stream() |
||||
.filter(writer -> writer instanceof EncoderHttpMessageWriter) |
||||
.map(writer -> ((EncoderHttpMessageWriter<?>) writer).getEncoder()) |
||||
.filter(e -> Jackson2JsonEncoder.class.equals(e.getClass())) |
||||
.findFirst() |
||||
.filter(e -> e == encoder).orElse(null)); |
||||
} |
||||
|
||||
|
||||
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) { |
||||
HttpMessageReader<?> reader = readers.get(this.index.getAndIncrement()); |
||||
assertEquals(DecoderHttpMessageReader.class, reader.getClass()); |
||||
return ((DecoderHttpMessageReader) reader).getDecoder(); |
||||
} |
||||
|
||||
private Encoder<?> getNextEncoder(List<HttpMessageWriter<?>> writers) { |
||||
HttpMessageWriter<?> writer = writers.get(this.index.getAndIncrement()); |
||||
assertEquals(EncoderHttpMessageWriter.class, writer.getClass()); |
||||
return ((EncoderHttpMessageWriter) writer).getEncoder(); |
||||
} |
||||
|
||||
private void assertStringDecoder(Decoder<?> decoder, boolean textOnly) { |
||||
assertEquals(StringDecoder.class, decoder.getClass()); |
||||
assertTrue(decoder.canDecode(forClass(String.class), MimeTypeUtils.TEXT_PLAIN)); |
||||
assertEquals(!textOnly, decoder.canDecode(forClass(String.class), MediaType.TEXT_EVENT_STREAM)); |
||||
} |
||||
|
||||
private void assertStringEncoder(Encoder<?> encoder, boolean textOnly) { |
||||
assertEquals(CharSequenceEncoder.class, encoder.getClass()); |
||||
assertTrue(encoder.canEncode(forClass(String.class), MimeTypeUtils.TEXT_PLAIN)); |
||||
assertEquals(!textOnly, encoder.canEncode(forClass(String.class), MediaType.TEXT_EVENT_STREAM)); |
||||
} |
||||
|
||||
|
||||
private static class TestCodecConfigurer extends AbstractCodecConfigurer { |
||||
|
||||
private TestCodecConfigurer() { |
||||
super(new DefaultCodecConfigurer()); |
||||
} |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue