diff --git a/spring-core/src/main/java/org/springframework/core/codec/NettyByteBufDecoder.java b/spring-core/src/main/java/org/springframework/core/codec/NettyByteBufDecoder.java new file mode 100644 index 00000000000..ebd9f8d86b0 --- /dev/null +++ b/spring-core/src/main/java/org/springframework/core/codec/NettyByteBufDecoder.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2020 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 + * + * https://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; + +import java.util.Map; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import org.springframework.core.ResolvableType; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.core.io.buffer.NettyDataBuffer; +import org.springframework.lang.Nullable; +import org.springframework.util.MimeType; +import org.springframework.util.MimeTypeUtils; + +/** + * Decoder for {@link ByteBuf ByteBufs}. + * + * @author Vladislav Kisel + * @since 5.3 + */ +public class NettyByteBufDecoder extends AbstractDataBufferDecoder { + + public NettyByteBufDecoder() { + super(MimeTypeUtils.ALL); + } + + + @Override + public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) { + return (ByteBuf.class.isAssignableFrom(elementType.toClass()) && + super.canDecode(elementType, mimeType)); + } + + @Override + public ByteBuf decode(DataBuffer dataBuffer, ResolvableType elementType, + @Nullable MimeType mimeType, @Nullable Map hints) { + + if (logger.isDebugEnabled()) { + logger.debug(Hints.getLogPrefix(hints) + "Read " + dataBuffer.readableByteCount() + " bytes"); + } + if (dataBuffer instanceof NettyDataBuffer) { + return ((NettyDataBuffer) dataBuffer).getNativeBuffer(); + } + ByteBuf byteBuf; + byte[] bytes = new byte[dataBuffer.readableByteCount()]; + dataBuffer.read(bytes); + byteBuf = Unpooled.wrappedBuffer(bytes); + DataBufferUtils.release(dataBuffer); + return byteBuf; + } + +} diff --git a/spring-core/src/main/java/org/springframework/core/codec/NettyByteBufEncoder.java b/spring-core/src/main/java/org/springframework/core/codec/NettyByteBufEncoder.java new file mode 100644 index 00000000000..dca9002dd5c --- /dev/null +++ b/spring-core/src/main/java/org/springframework/core/codec/NettyByteBufEncoder.java @@ -0,0 +1,77 @@ +/* + * Copyright 2002-2020 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 + * + * https://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; + +import java.util.Map; + +import io.netty.buffer.ByteBuf; +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.DataBufferFactory; +import org.springframework.core.io.buffer.NettyDataBufferFactory; +import org.springframework.lang.Nullable; +import org.springframework.util.MimeType; +import org.springframework.util.MimeTypeUtils; + +/** + * Encoder for {@link ByteBuf ByteBufs}. + * + * @author Vladislav Kisel + * @since 5.3 + */ +public class NettyByteBufEncoder extends AbstractEncoder { + + public NettyByteBufEncoder() { + super(MimeTypeUtils.ALL); + } + + + @Override + public boolean canEncode(ResolvableType type, @Nullable MimeType mimeType) { + Class clazz = type.toClass(); + return super.canEncode(type, mimeType) && ByteBuf.class.isAssignableFrom(clazz); + } + + @Override + public Flux encode(Publisher inputStream, + DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable MimeType mimeType, + @Nullable Map hints) { + + return Flux.from(inputStream).map(byteBuffer -> + encodeValue(byteBuffer, bufferFactory, elementType, mimeType, hints)); + } + + @Override + public DataBuffer encodeValue(ByteBuf byteBuf, DataBufferFactory bufferFactory, + ResolvableType valueType, @Nullable MimeType mimeType, @Nullable Map hints) { + + if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) { + String logPrefix = Hints.getLogPrefix(hints); + logger.debug(logPrefix + "Writing " + byteBuf.readableBytes() + " bytes"); + } + if (bufferFactory instanceof NettyDataBufferFactory) { + return ((NettyDataBufferFactory) bufferFactory).wrap(byteBuf); + } + byte[] bytes = new byte[byteBuf.readableBytes()]; + byteBuf.readBytes(bytes); + byteBuf.release(); + return bufferFactory.wrap(bytes); + } +} diff --git a/spring-core/src/test/java/org/springframework/core/codec/NettyByteBufDecoderTests.java b/spring-core/src/test/java/org/springframework/core/codec/NettyByteBufDecoderTests.java new file mode 100644 index 00000000000..7249fdcb750 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/codec/NettyByteBufDecoderTests.java @@ -0,0 +1,93 @@ +/* + * Copyright 2002-2020 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 + * + * https://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; + +import java.nio.charset.StandardCharsets; +import java.util.function.Consumer; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Flux; + +import org.springframework.core.ResolvableType; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.testfixture.codec.AbstractDecoderTests; +import org.springframework.util.MimeTypeUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Vladislav Kisel + */ +class NettyByteBufDecoderTests extends AbstractDecoderTests { + + private final byte[] fooBytes = "foo".getBytes(StandardCharsets.UTF_8); + + private final byte[] barBytes = "bar".getBytes(StandardCharsets.UTF_8); + + + NettyByteBufDecoderTests() { + super(new NettyByteBufDecoder()); + } + + @Override + @Test + public void canDecode() { + assertThat(this.decoder.canDecode(ResolvableType.forClass(ByteBuf.class), + MimeTypeUtils.TEXT_PLAIN)).isTrue(); + assertThat(this.decoder.canDecode(ResolvableType.forClass(Integer.class), + MimeTypeUtils.TEXT_PLAIN)).isFalse(); + assertThat(this.decoder.canDecode(ResolvableType.forClass(ByteBuf.class), + MimeTypeUtils.APPLICATION_JSON)).isTrue(); + } + + @Override + @Test + public void decode() { + Flux input = Flux.concat( + dataBuffer(this.fooBytes), + dataBuffer(this.barBytes)); + + testDecodeAll(input, ByteBuf.class, step -> step + .consumeNextWith(expectByteBuffer(Unpooled.copiedBuffer(this.fooBytes))) + .consumeNextWith(expectByteBuffer(Unpooled.copiedBuffer(this.barBytes))) + .verifyComplete()); + } + + @Override + @Test + public void decodeToMono() { + Flux input = Flux.concat( + dataBuffer(this.fooBytes), + dataBuffer(this.barBytes)); + + ByteBuf expected = Unpooled.buffer(this.fooBytes.length + this.barBytes.length) + .writeBytes(this.fooBytes) + .writeBytes(this.barBytes) + .readerIndex(0); + + testDecodeToMonoAll(input, ByteBuf.class, step -> step + .consumeNextWith(expectByteBuffer(expected)) + .verifyComplete()); + } + + private Consumer expectByteBuffer(ByteBuf expected) { + return actual -> assertThat(actual).isEqualTo(expected); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/codec/NettyByteBufEncoderTests.java b/spring-core/src/test/java/org/springframework/core/codec/NettyByteBufEncoderTests.java new file mode 100644 index 00000000000..0c6bff3792f --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/codec/NettyByteBufEncoderTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2020 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 + * + * https://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; + +import java.nio.charset.StandardCharsets; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Flux; + +import org.springframework.core.ResolvableType; +import org.springframework.core.testfixture.codec.AbstractEncoderTests; +import org.springframework.util.MimeTypeUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Vladislav Kisel + */ +class NettyByteBufEncoderTests extends AbstractEncoderTests { + + private final byte[] fooBytes = "foo".getBytes(StandardCharsets.UTF_8); + + private final byte[] barBytes = "bar".getBytes(StandardCharsets.UTF_8); + + NettyByteBufEncoderTests() { + super(new NettyByteBufEncoder()); + } + + @Override + @Test + public void canEncode() { + assertThat(this.encoder.canEncode(ResolvableType.forClass(ByteBuf.class), + MimeTypeUtils.TEXT_PLAIN)).isTrue(); + assertThat(this.encoder.canEncode(ResolvableType.forClass(Integer.class), + MimeTypeUtils.TEXT_PLAIN)).isFalse(); + assertThat(this.encoder.canEncode(ResolvableType.forClass(ByteBuf.class), + MimeTypeUtils.APPLICATION_JSON)).isTrue(); + + // gh-20024 + assertThat(this.encoder.canEncode(ResolvableType.NONE, null)).isFalse(); + } + + @Override + @Test + public void encode() { + Flux input = Flux.just(this.fooBytes, this.barBytes).map(Unpooled::copiedBuffer); + + testEncodeAll(input, ByteBuf.class, step -> step + .consumeNextWith(expectBytes(this.fooBytes)) + .consumeNextWith(expectBytes(this.barBytes)) + .verifyComplete()); + } +} diff --git a/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java b/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java index 64a2634f90a..fe771319055 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java +++ b/spring-web/src/main/java/org/springframework/http/codec/support/BaseDefaultCodecs.java @@ -31,6 +31,8 @@ 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.NettyByteBufDecoder; +import org.springframework.core.codec.NettyByteBufEncoder; import org.springframework.core.codec.ResourceDecoder; import org.springframework.core.codec.StringDecoder; import org.springframework.http.codec.CodecConfigurer; @@ -78,6 +80,8 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure static final boolean synchronossMultipartPresent; + static final boolean nettyByteBufPresent; + static { ClassLoader classLoader = BaseCodecConfigurer.class.getClassLoader(); jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && @@ -86,6 +90,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader); protobufPresent = ClassUtils.isPresent("com.google.protobuf.Message", classLoader); synchronossMultipartPresent = ClassUtils.isPresent("org.synchronoss.cloud.nio.multipart.NioMultipartParser", classLoader); + nettyByteBufPresent = ClassUtils.isPresent("io.netty.buffer.ByteBuf", classLoader); } @@ -223,6 +228,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure addCodec(readers, new DecoderHttpMessageReader<>(new ByteArrayDecoder())); addCodec(readers, new DecoderHttpMessageReader<>(new ByteBufferDecoder())); addCodec(readers, new DecoderHttpMessageReader<>(new DataBufferDecoder())); + if (nettyByteBufPresent) { + addCodec(readers, new DecoderHttpMessageReader<>(new NettyByteBufDecoder())); + } addCodec(readers, new ResourceHttpMessageReader(new ResourceDecoder())); addCodec(readers, new DecoderHttpMessageReader<>(StringDecoder.textPlainOnly())); if (protobufPresent) { @@ -399,6 +407,9 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure writers.add(new EncoderHttpMessageWriter<>(new ByteArrayEncoder())); writers.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder())); writers.add(new EncoderHttpMessageWriter<>(new DataBufferEncoder())); + if (nettyByteBufPresent) { + writers.add(new EncoderHttpMessageWriter<>(new NettyByteBufEncoder())); + } writers.add(new ResourceHttpMessageWriter()); writers.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly())); if (protobufPresent) { diff --git a/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java index fce509efbb8..3fef68f472c 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/ClientCodecConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -36,6 +36,8 @@ 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.NettyByteBufDecoder; +import org.springframework.core.codec.NettyByteBufEncoder; import org.springframework.core.codec.ResourceDecoder; import org.springframework.core.codec.StringDecoder; import org.springframework.core.io.buffer.DefaultDataBufferFactory; @@ -79,10 +81,11 @@ public class ClientCodecConfigurerTests { @Test public void defaultReaders() { List> readers = this.configurer.getReaders(); - assertThat(readers.size()).isEqualTo(12); + assertThat(readers.size()).isEqualTo(13); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(NettyByteBufDecoder.class); assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageReader.class); assertStringDecoder(getNextDecoder(readers), true); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class); @@ -98,10 +101,11 @@ public class ClientCodecConfigurerTests { @Test public void defaultWriters() { List> writers = this.configurer.getWriters(); - assertThat(writers.size()).isEqualTo(11); + assertThat(writers.size()).isEqualTo(12); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(NettyByteBufEncoder.class); assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageWriter.class); assertStringEncoder(getNextEncoder(writers), true); assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class); @@ -126,10 +130,11 @@ public class ClientCodecConfigurerTests { int size = 99; this.configurer.defaultCodecs().maxInMemorySize(size); List> readers = this.configurer.getReaders(); - assertThat(readers.size()).isEqualTo(12); + assertThat(readers.size()).isEqualTo(13); assertThat(((ByteArrayDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((ByteBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((DataBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((NettyByteBufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((ResourceDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((StringDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((ProtobufDecoder) getNextDecoder(readers)).getMaxMessageSize()).isEqualTo(size); @@ -182,7 +187,7 @@ public class ClientCodecConfigurerTests { writers = findCodec(this.configurer.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); assertThat(sseDecoder).isNotSameAs(jackson2Decoder); - assertThat(writers).hasSize(10); + assertThat(writers).hasSize(11); } @Test // gh-24194 @@ -192,7 +197,7 @@ public class ClientCodecConfigurerTests { List> writers = findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); - assertThat(writers).hasSize(10); + assertThat(writers).hasSize(11); } @Test @@ -206,7 +211,7 @@ public class ClientCodecConfigurerTests { List> writers = findCodec(clone.getWriters(), MultipartHttpMessageWriter.class).getPartWriters(); - assertThat(writers).hasSize(10); + assertThat(writers).hasSize(11); } private Decoder getNextDecoder(List> readers) { diff --git a/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java index 71a1d7a8483..e26cc7a4357 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/CodecConfigurerTests.java @@ -34,6 +34,8 @@ 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.NettyByteBufDecoder; +import org.springframework.core.codec.NettyByteBufEncoder; import org.springframework.core.codec.StringDecoder; import org.springframework.http.MediaType; import org.springframework.http.codec.CodecConfigurer; @@ -77,10 +79,11 @@ public class CodecConfigurerTests { @Test public void defaultReaders() { List> readers = this.configurer.getReaders(); - assertThat(readers.size()).isEqualTo(11); + assertThat(readers.size()).isEqualTo(12); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(NettyByteBufDecoder.class); assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageReader.class); assertStringDecoder(getNextDecoder(readers), true); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class); @@ -94,10 +97,11 @@ public class CodecConfigurerTests { @Test public void defaultWriters() { List> writers = this.configurer.getWriters(); - assertThat(writers.size()).isEqualTo(10); + assertThat(writers.size()).isEqualTo(11); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(NettyByteBufEncoder.class); assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageWriter.class); assertStringEncoder(getNextEncoder(writers), true); assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class); @@ -129,12 +133,13 @@ public class CodecConfigurerTests { List> readers = this.configurer.getReaders(); - assertThat(readers.size()).isEqualTo(15); + assertThat(readers.size()).isEqualTo(16); assertThat(getNextDecoder(readers)).isSameAs(customDecoder1); assertThat(readers.get(this.index.getAndIncrement())).isSameAs(customReader1); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(NettyByteBufDecoder.class); assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageReader.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(StringDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class); @@ -169,12 +174,13 @@ public class CodecConfigurerTests { List> writers = this.configurer.getWriters(); - assertThat(writers.size()).isEqualTo(14); + assertThat(writers.size()).isEqualTo(15); assertThat(getNextEncoder(writers)).isSameAs(customEncoder1); assertThat(writers.get(this.index.getAndIncrement())).isSameAs(customWriter1); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(NettyByteBufEncoder.class); assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageWriter.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(CharSequenceEncoder.class); assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class); diff --git a/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java b/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java index ed18f6f8edf..3a3ab56515a 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/support/ServerCodecConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -36,6 +36,8 @@ 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.NettyByteBufDecoder; +import org.springframework.core.codec.NettyByteBufEncoder; import org.springframework.core.codec.ResourceDecoder; import org.springframework.core.codec.StringDecoder; import org.springframework.core.io.buffer.DefaultDataBufferFactory; @@ -80,10 +82,11 @@ public class ServerCodecConfigurerTests { @Test public void defaultReaders() { List> readers = this.configurer.getReaders(); - assertThat(readers.size()).isEqualTo(13); + assertThat(readers.size()).isEqualTo(14); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteArrayDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ByteBufferDecoder.class); assertThat(getNextDecoder(readers).getClass()).isEqualTo(DataBufferDecoder.class); + assertThat(getNextDecoder(readers).getClass()).isEqualTo(NettyByteBufDecoder.class); assertThat(readers.get(this.index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageReader.class); assertStringDecoder(getNextDecoder(readers), true); assertThat(getNextDecoder(readers).getClass()).isEqualTo(ProtobufDecoder.class); @@ -99,10 +102,11 @@ public class ServerCodecConfigurerTests { @Test public void defaultWriters() { List> writers = this.configurer.getWriters(); - assertThat(writers.size()).isEqualTo(11); + assertThat(writers.size()).isEqualTo(12); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteArrayEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(ByteBufferEncoder.class); assertThat(getNextEncoder(writers).getClass()).isEqualTo(DataBufferEncoder.class); + assertThat(getNextEncoder(writers).getClass()).isEqualTo(NettyByteBufEncoder.class); assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ResourceHttpMessageWriter.class); assertStringEncoder(getNextEncoder(writers), true); assertThat(writers.get(index.getAndIncrement()).getClass()).isEqualTo(ProtobufHttpMessageWriter.class); @@ -135,6 +139,7 @@ public class ServerCodecConfigurerTests { assertThat(((ByteArrayDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((ByteBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((DataBufferDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); + assertThat(((NettyByteBufDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((ResourceDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((StringDecoder) getNextDecoder(readers)).getMaxInMemorySize()).isEqualTo(size); assertThat(((ProtobufDecoder) getNextDecoder(readers)).getMaxMessageSize()).isEqualTo(size); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java index 0069be07401..d5515616b30 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -77,7 +77,7 @@ public class DelegatingWebFluxConfigurationTests { @Test - public void requestMappingHandlerMapping() throws Exception { + public void requestMappingHandlerMapping() { delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer)); delegatingConfig.requestMappingHandlerMapping(delegatingConfig.webFluxContentTypeResolver()); @@ -87,7 +87,7 @@ public class DelegatingWebFluxConfigurationTests { } @Test - public void requestMappingHandlerAdapter() throws Exception { + public void requestMappingHandlerAdapter() { delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer)); ReactiveAdapterRegistry reactiveAdapterRegistry = delegatingConfig.webFluxAdapterRegistry(); ServerCodecConfigurer serverCodecConfigurer = delegatingConfig.serverCodecConfigurer(); @@ -108,11 +108,11 @@ public class DelegatingWebFluxConfigurationTests { boolean condition = initializer.getValidator() instanceof LocalValidatorFactoryBean; assertThat(condition).isTrue(); assertThat(initializer.getConversionService()).isSameAs(formatterRegistry.getValue()); - assertThat(codecsConfigurer.getValue().getReaders().size()).isEqualTo(13); + assertThat(codecsConfigurer.getValue().getReaders().size()).isEqualTo(14); } @Test - public void resourceHandlerMapping() throws Exception { + public void resourceHandlerMapping() { delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer)); willAnswer(invocation -> { ResourceHandlerRegistry registry = invocation.getArgument(0); @@ -126,7 +126,7 @@ public class DelegatingWebFluxConfigurationTests { } @Test - public void responseBodyResultHandler() throws Exception { + public void responseBodyResultHandler() { delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer)); delegatingConfig.responseBodyResultHandler( delegatingConfig.webFluxAdapterRegistry(), @@ -138,7 +138,7 @@ public class DelegatingWebFluxConfigurationTests { } @Test - public void viewResolutionResultHandler() throws Exception { + public void viewResolutionResultHandler() { delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer)); delegatingConfig.viewResolutionResultHandler(delegatingConfig.webFluxAdapterRegistry(), delegatingConfig.webFluxContentTypeResolver()); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java index 5956a9391d4..5ed8aa49cc6 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -97,7 +97,7 @@ import static org.springframework.web.testfixture.http.server.reactive.MockServe public class WebFluxConfigurationSupportTests { @Test - public void requestMappingHandlerMapping() throws Exception { + public void requestMappingHandlerMapping() { ApplicationContext context = loadConfig(WebFluxConfig.class); final Field field = ReflectionUtils.findField(PathPatternParser.class, "matchOptionalTrailingSeparator"); ReflectionUtils.makeAccessible(field); @@ -118,7 +118,8 @@ public class WebFluxConfigurationSupportTests { assertThat(mapping.getContentTypeResolver()).isSameAs(resolver); ServerWebExchange exchange = MockServerWebExchange.from(get("/path").accept(MediaType.APPLICATION_JSON)); - assertThat(resolver.resolveMediaTypes(exchange)).isEqualTo(Collections.singletonList(MediaType.APPLICATION_JSON)); + assertThat(resolver.resolveMediaTypes(exchange)) + .isEqualTo(Collections.singletonList(MediaType.APPLICATION_JSON)); } @Test @@ -138,11 +139,12 @@ public class WebFluxConfigurationSupportTests { Map map = mapping.getHandlerMethods(); assertThat(map.size()).isEqualTo(1); - assertThat(map.keySet().iterator().next().getPatternsCondition().getPatterns()).isEqualTo(Collections.singleton(new PathPatternParser().parse("/api/user/{id}"))); + assertThat(map.keySet().iterator().next().getPatternsCondition().getPatterns()) + .isEqualTo(Collections.singleton(new PathPatternParser().parse("/api/user/{id}"))); } @Test - public void requestMappingHandlerAdapter() throws Exception { + public void requestMappingHandlerAdapter() { ApplicationContext context = loadConfig(WebFluxConfig.class); String name = "requestMappingHandlerAdapter"; @@ -150,7 +152,7 @@ public class WebFluxConfigurationSupportTests { assertThat(adapter).isNotNull(); List> readers = adapter.getMessageReaders(); - assertThat(readers.size()).isEqualTo(13); + assertThat(readers.size()).isEqualTo(14); ResolvableType multiValueMapType = forClassWithGenerics(MultiValueMap.class, String.class, String.class); @@ -180,7 +182,7 @@ public class WebFluxConfigurationSupportTests { } @Test - public void customMessageConverterConfig() throws Exception { + public void customMessageConverterConfig() { ApplicationContext context = loadConfig(CustomMessageConverterConfig.class); String name = "requestMappingHandlerAdapter"; @@ -195,7 +197,7 @@ public class WebFluxConfigurationSupportTests { } @Test - public void responseEntityResultHandler() throws Exception { + public void responseEntityResultHandler() { ApplicationContext context = loadConfig(WebFluxConfig.class); String name = "responseEntityResultHandler"; @@ -205,7 +207,7 @@ public class WebFluxConfigurationSupportTests { assertThat(handler.getOrder()).isEqualTo(0); List> writers = handler.getMessageWriters(); - assertThat(writers.size()).isEqualTo(11); + assertThat(writers.size()).isEqualTo(12); assertHasMessageWriter(writers, forClass(byte[].class), APPLICATION_OCTET_STREAM); assertHasMessageWriter(writers, forClass(ByteBuffer.class), APPLICATION_OCTET_STREAM); @@ -223,7 +225,7 @@ public class WebFluxConfigurationSupportTests { } @Test - public void responseBodyResultHandler() throws Exception { + public void responseBodyResultHandler() { ApplicationContext context = loadConfig(WebFluxConfig.class); String name = "responseBodyResultHandler"; @@ -233,7 +235,7 @@ public class WebFluxConfigurationSupportTests { assertThat(handler.getOrder()).isEqualTo(100); List> writers = handler.getMessageWriters(); - assertThat(writers.size()).isEqualTo(11); + assertThat(writers.size()).isEqualTo(12); assertHasMessageWriter(writers, forClass(byte[].class), APPLICATION_OCTET_STREAM); assertHasMessageWriter(writers, forClass(ByteBuffer.class), APPLICATION_OCTET_STREAM); @@ -251,7 +253,7 @@ public class WebFluxConfigurationSupportTests { } @Test - public void viewResolutionResultHandler() throws Exception { + public void viewResolutionResultHandler() { ApplicationContext context = loadConfig(CustomViewResolverConfig.class); String name = "viewResolutionResultHandler"; @@ -272,7 +274,7 @@ public class WebFluxConfigurationSupportTests { } @Test - public void resourceHandler() throws Exception { + public void resourceHandler() { ApplicationContext context = loadConfig(CustomResourceHandlingConfig.class); String name = "resourceHandlerMapping";