Remove Netty 5 support

Closes gh-34345
This commit is contained in:
rstoyanchev
2025-02-11 12:27:33 +00:00
parent bae12e739d
commit e9d16da633
51 changed files with 48 additions and 4052 deletions

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2002-2022 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.netty5.buffer.Buffer;
import io.netty5.buffer.DefaultBufferAllocators;
import org.jspecify.annotations.Nullable;
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.Netty5DataBuffer;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
/**
* Decoder for {@link Buffer Buffers}.
*
* @author Violeta Georgieva
* @since 6.0
*/
public class Netty5BufferDecoder extends AbstractDataBufferDecoder<Buffer> {
public Netty5BufferDecoder() {
super(MimeTypeUtils.ALL);
}
@Override
public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType) {
return (Buffer.class.isAssignableFrom(elementType.toClass()) &&
super.canDecode(elementType, mimeType));
}
@Override
public Buffer decode(DataBuffer dataBuffer, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
if (logger.isDebugEnabled()) {
logger.debug(Hints.getLogPrefix(hints) + "Read " + dataBuffer.readableByteCount() + " bytes");
}
if (dataBuffer instanceof Netty5DataBuffer netty5DataBuffer) {
return netty5DataBuffer.getNativeBuffer();
}
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
Buffer buffer = DefaultBufferAllocators.preferredAllocator().copyOf(bytes);
DataBufferUtils.release(dataBuffer);
return buffer;
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2002-2022 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.netty5.buffer.Buffer;
import org.jspecify.annotations.Nullable;
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.Netty5DataBufferFactory;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
/**
* Encoder for {@link Buffer Buffers}.
*
* @author Violeta Georgieva
* @since 6.0
*/
public class Netty5BufferEncoder extends AbstractEncoder<Buffer> {
public Netty5BufferEncoder() {
super(MimeTypeUtils.ALL);
}
@Override
public boolean canEncode(ResolvableType type, @Nullable MimeType mimeType) {
Class<?> clazz = type.toClass();
return super.canEncode(type, mimeType) && Buffer.class.isAssignableFrom(clazz);
}
@Override
public Flux<DataBuffer> encode(Publisher<? extends Buffer> inputStream,
DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable MimeType mimeType,
@Nullable Map<String, Object> hints) {
return Flux.from(inputStream).map(byteBuffer ->
encodeValue(byteBuffer, bufferFactory, elementType, mimeType, hints));
}
@Override
public DataBuffer encodeValue(Buffer buffer, DataBufferFactory bufferFactory, ResolvableType valueType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
String logPrefix = Hints.getLogPrefix(hints);
logger.debug(logPrefix + "Writing " + buffer.readableBytes() + " bytes");
}
if (bufferFactory instanceof Netty5DataBufferFactory netty5DataBufferFactory) {
return netty5DataBufferFactory.wrap(buffer);
}
byte[] bytes = new byte[buffer.readableBytes()];
buffer.readBytes(bytes, 0, bytes.length);
buffer.close();
return bufferFactory.wrap(bytes);
}
}

View File

@@ -1,401 +0,0 @@
/*
* Copyright 2002-2023 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.io.buffer;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.NoSuchElementException;
import java.util.function.IntPredicate;
import io.netty5.buffer.Buffer;
import io.netty5.buffer.BufferComponent;
import io.netty5.buffer.ComponentIterator;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Implementation of the {@code DataBuffer} interface that wraps a Netty 5
* {@link Buffer}. Typically constructed with {@link Netty5DataBufferFactory}.
*
* @author Violeta Georgieva
* @author Arjen Poutsma
* @since 6.0
*/
public final class Netty5DataBuffer implements CloseableDataBuffer, TouchableDataBuffer {
private final Buffer buffer;
private final Netty5DataBufferFactory dataBufferFactory;
/**
* Create a new {@code Netty5DataBuffer} based on the given {@code Buffer}.
* @param buffer the buffer to base this buffer on
*/
Netty5DataBuffer(Buffer buffer, Netty5DataBufferFactory dataBufferFactory) {
Assert.notNull(buffer, "Buffer must not be null");
Assert.notNull(dataBufferFactory, "Netty5DataBufferFactory must not be null");
this.buffer = buffer;
this.dataBufferFactory = dataBufferFactory;
}
/**
* Directly exposes the native {@code Buffer} that this buffer is based on.
* @return the wrapped buffer
*/
public Buffer getNativeBuffer() {
return this.buffer;
}
@Override
public DataBufferFactory factory() {
return this.dataBufferFactory;
}
@Override
public int indexOf(IntPredicate predicate, int fromIndex) {
Assert.notNull(predicate, "IntPredicate must not be null");
if (fromIndex < 0) {
fromIndex = 0;
}
else if (fromIndex >= this.buffer.writerOffset()) {
return -1;
}
int length = this.buffer.writerOffset() - fromIndex;
int bytes = this.buffer.openCursor(fromIndex, length).process(predicate.negate()::test);
return bytes == -1 ? -1 : fromIndex + bytes;
}
@Override
public int lastIndexOf(IntPredicate predicate, int fromIndex) {
Assert.notNull(predicate, "IntPredicate must not be null");
if (fromIndex < 0) {
return -1;
}
fromIndex = Math.min(fromIndex, this.buffer.writerOffset() - 1);
return this.buffer.openCursor(0, fromIndex + 1).process(predicate.negate()::test);
}
@Override
public int readableByteCount() {
return this.buffer.readableBytes();
}
@Override
public int writableByteCount() {
return this.buffer.writableBytes();
}
@Override
public int readPosition() {
return this.buffer.readerOffset();
}
@Override
public Netty5DataBuffer readPosition(int readPosition) {
this.buffer.readerOffset(readPosition);
return this;
}
@Override
public int writePosition() {
return this.buffer.writerOffset();
}
@Override
public Netty5DataBuffer writePosition(int writePosition) {
this.buffer.writerOffset(writePosition);
return this;
}
@Override
public byte getByte(int index) {
return this.buffer.getByte(index);
}
@Override
public int capacity() {
return this.buffer.capacity();
}
@Override
@Deprecated
public Netty5DataBuffer capacity(int capacity) {
if (capacity <= 0) {
throw new IllegalArgumentException(String.format("'newCapacity' %d must be higher than 0", capacity));
}
int diff = capacity - capacity();
if (diff > 0) {
this.buffer.ensureWritable(this.buffer.writableBytes() + diff);
}
return this;
}
@Override
public DataBuffer ensureWritable(int capacity) {
Assert.isTrue(capacity >= 0, "Capacity must be >= 0");
this.buffer.ensureWritable(capacity);
return this;
}
@Override
public byte read() {
return this.buffer.readByte();
}
@Override
public Netty5DataBuffer read(byte[] destination) {
return read(destination, 0, destination.length);
}
@Override
public Netty5DataBuffer read(byte[] destination, int offset, int length) {
this.buffer.readBytes(destination, offset, length);
return this;
}
@Override
public Netty5DataBuffer write(byte b) {
this.buffer.writeByte(b);
return this;
}
@Override
public Netty5DataBuffer write(byte[] source) {
this.buffer.writeBytes(source);
return this;
}
@Override
public Netty5DataBuffer write(byte[] source, int offset, int length) {
this.buffer.writeBytes(source, offset, length);
return this;
}
@Override
public Netty5DataBuffer write(DataBuffer... dataBuffers) {
if (!ObjectUtils.isEmpty(dataBuffers)) {
if (hasNetty5DataBuffers(dataBuffers)) {
Buffer[] nativeBuffers = new Buffer[dataBuffers.length];
for (int i = 0; i < dataBuffers.length; i++) {
nativeBuffers[i] = ((Netty5DataBuffer) dataBuffers[i]).getNativeBuffer();
}
return write(nativeBuffers);
}
else {
ByteBuffer[] byteBuffers = new ByteBuffer[dataBuffers.length];
for (int i = 0; i < dataBuffers.length; i++) {
byteBuffers[i] = ByteBuffer.allocate(dataBuffers[i].readableByteCount());
dataBuffers[i].toByteBuffer(byteBuffers[i]);
}
return write(byteBuffers);
}
}
return this;
}
private static boolean hasNetty5DataBuffers(DataBuffer[] buffers) {
for (DataBuffer buffer : buffers) {
if (!(buffer instanceof Netty5DataBuffer)) {
return false;
}
}
return true;
}
@Override
public Netty5DataBuffer write(ByteBuffer... buffers) {
if (!ObjectUtils.isEmpty(buffers)) {
for (ByteBuffer buffer : buffers) {
this.buffer.writeBytes(buffer);
}
}
return this;
}
/**
* Writes one or more Netty 5 {@link Buffer Buffers} to this buffer,
* starting at the current writing position.
* @param buffers the buffers to write into this buffer
* @return this buffer
*/
public Netty5DataBuffer write(Buffer... buffers) {
if (!ObjectUtils.isEmpty(buffers)) {
for (Buffer buffer : buffers) {
this.buffer.writeBytes(buffer);
}
}
return this;
}
@Override
public DataBuffer write(CharSequence charSequence, Charset charset) {
Assert.notNull(charSequence, "CharSequence must not be null");
Assert.notNull(charset, "Charset must not be null");
this.buffer.writeCharSequence(charSequence, charset);
return this;
}
/**
* {@inheritDoc}
* <p><strong>Note</strong> that due to the lack of a {@code slice} method
* in Netty 5's {@link Buffer}, this implementation returns a copy that
* does <strong>not</strong> share its contents with this buffer.
*/
@Override
@Deprecated
public DataBuffer slice(int index, int length) {
Buffer copy = this.buffer.copy(index, length);
return new Netty5DataBuffer(copy, this.dataBufferFactory);
}
@Override
public DataBuffer split(int index) {
Buffer split = this.buffer.split(index);
return new Netty5DataBuffer(split, this.dataBufferFactory);
}
@Override
@Deprecated
public ByteBuffer asByteBuffer() {
return toByteBuffer();
}
@Override
@Deprecated
public ByteBuffer asByteBuffer(int index, int length) {
return toByteBuffer(index, length);
}
@Override
@Deprecated
public ByteBuffer toByteBuffer(int index, int length) {
ByteBuffer copy = this.buffer.isDirect() ?
ByteBuffer.allocateDirect(length) :
ByteBuffer.allocate(length);
this.buffer.copyInto(index, copy, 0, length);
return copy;
}
@Override
public void toByteBuffer(int srcPos, ByteBuffer dest, int destPos, int length) {
this.buffer.copyInto(srcPos, dest, destPos, length);
}
@Override
public ByteBufferIterator readableByteBuffers() {
return new BufferComponentIterator<>(this.buffer.forEachComponent(), true);
}
@Override
public ByteBufferIterator writableByteBuffers() {
return new BufferComponentIterator<>(this.buffer.forEachComponent(), false);
}
@Override
public String toString(Charset charset) {
Assert.notNull(charset, "Charset must not be null");
return this.buffer.toString(charset);
}
@Override
public String toString(int index, int length, Charset charset) {
Assert.notNull(charset, "Charset must not be null");
byte[] data = new byte[length];
this.buffer.copyInto(index, data, 0, length);
return new String(data, 0, length, charset);
}
@Override
public Netty5DataBuffer touch(Object hint) {
this.buffer.touch(hint);
return this;
}
@Override
public void close() {
this.buffer.close();
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other || (other instanceof Netty5DataBuffer that && this.buffer.equals(that.buffer)));
}
@Override
public int hashCode() {
return this.buffer.hashCode();
}
@Override
public String toString() {
return this.buffer.toString();
}
private static final class BufferComponentIterator<T extends BufferComponent & ComponentIterator.Next>
implements ByteBufferIterator {
private final ComponentIterator<T> delegate;
private final boolean readable;
private @Nullable T next;
public BufferComponentIterator(ComponentIterator<T> delegate, boolean readable) {
Assert.notNull(delegate, "Delegate must not be null");
this.delegate = delegate;
this.readable = readable;
this.next = readable ? this.delegate.firstReadable() : this.delegate.firstWritable();
}
@Override
public boolean hasNext() {
return this.next != null;
}
@Override
public ByteBuffer next() {
if (this.next != null) {
ByteBuffer result;
if (this.readable) {
result = this.next.readableBuffer();
this.next = this.next.nextReadable();
}
else {
result = this.next.writableBuffer();
this.next = this.next.nextWritable();
}
return result;
}
else {
throw new NoSuchElementException();
}
}
@Override
public void close() {
this.delegate.close();
}
}
}

View File

@@ -1,141 +0,0 @@
/*
* Copyright 2002-2023 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.io.buffer;
import java.nio.ByteBuffer;
import java.util.List;
import io.netty5.buffer.Buffer;
import io.netty5.buffer.BufferAllocator;
import io.netty5.buffer.CompositeBuffer;
import io.netty5.buffer.DefaultBufferAllocators;
import org.springframework.util.Assert;
/**
* Implementation of the {@code DataBufferFactory} interface based on a
* Netty 5 {@link BufferAllocator}.
*
* @author Violeta Georgieva
* @author Arjen Poutsma
* @since 6.0
*/
public class Netty5DataBufferFactory implements DataBufferFactory {
private final BufferAllocator bufferAllocator;
/**
* Create a new {@code Netty5DataBufferFactory} based on the given factory.
* @param bufferAllocator the factory to use
*/
public Netty5DataBufferFactory(BufferAllocator bufferAllocator) {
Assert.notNull(bufferAllocator, "BufferAllocator must not be null");
this.bufferAllocator = bufferAllocator;
}
/**
* Return the {@code BufferAllocator} used by this factory.
*/
public BufferAllocator getBufferAllocator() {
return this.bufferAllocator;
}
@Override
@Deprecated
public Netty5DataBuffer allocateBuffer() {
Buffer buffer = this.bufferAllocator.allocate(256);
return new Netty5DataBuffer(buffer, this);
}
@Override
public Netty5DataBuffer allocateBuffer(int initialCapacity) {
Buffer buffer = this.bufferAllocator.allocate(initialCapacity);
return new Netty5DataBuffer(buffer, this);
}
@Override
public Netty5DataBuffer wrap(ByteBuffer byteBuffer) {
Buffer buffer = this.bufferAllocator.copyOf(byteBuffer);
return new Netty5DataBuffer(buffer, this);
}
@Override
public Netty5DataBuffer wrap(byte[] bytes) {
Buffer buffer = this.bufferAllocator.copyOf(bytes);
return new Netty5DataBuffer(buffer, this);
}
/**
* Wrap the given Netty {@link Buffer} in a {@code Netty5DataBuffer}.
* @param buffer the Netty buffer to wrap
* @return the wrapped buffer
*/
public Netty5DataBuffer wrap(Buffer buffer) {
buffer.touch("Wrap buffer");
return new Netty5DataBuffer(buffer, this);
}
/**
* {@inheritDoc}
* <p>This implementation uses Netty's {@link CompositeBuffer}.
*/
@Override
public DataBuffer join(List<? extends DataBuffer> dataBuffers) {
Assert.notEmpty(dataBuffers, "DataBuffer List must not be empty");
if (dataBuffers.size() == 1) {
return dataBuffers.get(0);
}
CompositeBuffer composite = this.bufferAllocator.compose();
for (DataBuffer dataBuffer : dataBuffers) {
Assert.isInstanceOf(Netty5DataBuffer.class, dataBuffer);
composite.extendWith(((Netty5DataBuffer) dataBuffer).getNativeBuffer().send());
}
return new Netty5DataBuffer(composite, this);
}
@Override
public boolean isDirect() {
return this.bufferAllocator.getAllocationType().isDirect();
}
/**
* Return the given Netty {@link DataBuffer} as a {@link Buffer}.
* <p>Returns the {@linkplain Netty5DataBuffer#getNativeBuffer() native buffer}
* if {@code buffer} is a {@link Netty5DataBuffer}; returns
* {@link BufferAllocator#copyOf(ByteBuffer)} otherwise.
* @param buffer the {@code DataBuffer} to return a {@code Buffer} for
* @return the netty {@code Buffer}
*/
public static Buffer toBuffer(DataBuffer buffer) {
if (buffer instanceof Netty5DataBuffer netty5DataBuffer) {
return netty5DataBuffer.getNativeBuffer();
}
else {
ByteBuffer byteBuffer = ByteBuffer.allocate(buffer.readableByteCount());
buffer.toByteBuffer(byteBuffer);
return DefaultBufferAllocators.preferredAllocator().copyOf(byteBuffer);
}
}
@Override
public String toString() {
return "Netty5DataBufferFactory (" + this.bufferAllocator + ")";
}
}

View File

@@ -1,97 +0,0 @@
/*
* Copyright 2002-2024 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.netty5.buffer.Buffer;
import io.netty5.buffer.DefaultBufferAllocators;
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 Arjen Poutsma
*/
class Netty5BufferDecoderTests extends AbstractDecoderTests<Netty5BufferDecoder> {
private final byte[] fooBytes = "foo".getBytes(StandardCharsets.UTF_8);
private final byte[] barBytes = "bar".getBytes(StandardCharsets.UTF_8);
Netty5BufferDecoderTests() {
super(new Netty5BufferDecoder());
}
@Override
@Test
protected void canDecode() {
assertThat(this.decoder.canDecode(ResolvableType.forClass(Buffer.class),
MimeTypeUtils.TEXT_PLAIN)).isTrue();
assertThat(this.decoder.canDecode(ResolvableType.forClass(Integer.class),
MimeTypeUtils.TEXT_PLAIN)).isFalse();
assertThat(this.decoder.canDecode(ResolvableType.forClass(Buffer.class),
MimeTypeUtils.APPLICATION_JSON)).isTrue();
}
@Override
@Test
protected void decode() {
Flux<DataBuffer> input = Flux.concat(
dataBuffer(this.fooBytes),
dataBuffer(this.barBytes));
testDecodeAll(input, Buffer.class, step -> step
.consumeNextWith(expectByteBuffer(DefaultBufferAllocators.preferredAllocator().copyOf(this.fooBytes)))
.consumeNextWith(expectByteBuffer(DefaultBufferAllocators.preferredAllocator().copyOf(this.barBytes)))
.verifyComplete());
}
@Override
@Test
protected void decodeToMono() {
Flux<DataBuffer> input = Flux.concat(
dataBuffer(this.fooBytes),
dataBuffer(this.barBytes));
Buffer expected = DefaultBufferAllocators.preferredAllocator().allocate(this.fooBytes.length + this.barBytes.length)
.writeBytes(this.fooBytes)
.writeBytes(this.barBytes)
.readerOffset(0);
testDecodeToMonoAll(input, Buffer.class, step -> step
.consumeNextWith(expectByteBuffer(expected))
.verifyComplete());
}
private Consumer<Buffer> expectByteBuffer(Buffer expected) {
return actual -> {
try (actual; expected) {
assertThat(actual).isEqualTo(expected);
}
};
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright 2002-2022 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.netty5.buffer.Buffer;
import io.netty5.buffer.DefaultBufferAllocators;
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 Arjen Poutsma
*/
class Netty5BufferEncoderTests extends AbstractEncoderTests<Netty5BufferEncoder> {
private final byte[] fooBytes = "foo".getBytes(StandardCharsets.UTF_8);
private final byte[] barBytes = "bar".getBytes(StandardCharsets.UTF_8);
Netty5BufferEncoderTests() {
super(new Netty5BufferEncoder());
}
@Test
@Override
public void canEncode() {
assertThat(this.encoder.canEncode(ResolvableType.forClass(Buffer.class),
MimeTypeUtils.TEXT_PLAIN)).isTrue();
assertThat(this.encoder.canEncode(ResolvableType.forClass(Integer.class),
MimeTypeUtils.TEXT_PLAIN)).isFalse();
assertThat(this.encoder.canEncode(ResolvableType.forClass(Buffer.class),
MimeTypeUtils.APPLICATION_JSON)).isTrue();
// gh-20024
assertThat(this.encoder.canEncode(ResolvableType.NONE, null)).isFalse();
}
@Test
@Override
@SuppressWarnings("resource")
public void encode() {
Flux<Buffer> input = Flux.just(this.fooBytes, this.barBytes)
.map(DefaultBufferAllocators.preferredAllocator()::copyOf);
testEncodeAll(input, Buffer.class, step -> step
.consumeNextWith(expectBytes(this.fooBytes))
.consumeNextWith(expectBytes(this.barBytes))
.verifyComplete());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@@ -28,7 +28,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatException;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
/**
* @author Arjen Poutsma
@@ -414,9 +413,6 @@ class DataBufferTests extends AbstractDataBufferAllocatingTests {
@ParameterizedDataBufferAllocatingTest
@SuppressWarnings("deprecation")
void decreaseCapacityLowReadPosition(DataBufferFactory bufferFactory) {
assumeFalse(bufferFactory instanceof Netty5DataBufferFactory,
"Netty 5 does not support decreasing the capacity");
super.bufferFactory = bufferFactory;
DataBuffer buffer = createDataBuffer(2);
@@ -430,9 +426,6 @@ class DataBufferTests extends AbstractDataBufferAllocatingTests {
@ParameterizedDataBufferAllocatingTest
@SuppressWarnings("deprecation")
void decreaseCapacityHighReadPosition(DataBufferFactory bufferFactory) {
assumeFalse(bufferFactory instanceof Netty5DataBufferFactory,
"Netty 5 does not support decreasing the capacity");
super.bufferFactory = bufferFactory;
DataBuffer buffer = createDataBuffer(2);
@@ -543,11 +536,6 @@ class DataBufferTests extends AbstractDataBufferAllocatingTests {
ByteBuffer result = buffer.asByteBuffer(1, 2);
assertThat(result.capacity()).isEqualTo(2);
assumeFalse(bufferFactory instanceof Netty5DataBufferFactory, () -> {
DataBufferUtils.release(buffer);
return "Netty 5 does share the internal buffer";
});
buffer.write((byte) 'c');
assertThat(result.remaining()).isEqualTo(2);
@@ -561,9 +549,6 @@ class DataBufferTests extends AbstractDataBufferAllocatingTests {
@ParameterizedDataBufferAllocatingTest
@SuppressWarnings("deprecation")
void byteBufferContainsDataBufferChanges(DataBufferFactory bufferFactory) {
assumeFalse(bufferFactory instanceof Netty5DataBufferFactory,
"Netty 5 does not support sharing data between buffers");
super.bufferFactory = bufferFactory;
DataBuffer dataBuffer = createDataBuffer(1);
@@ -581,9 +566,6 @@ class DataBufferTests extends AbstractDataBufferAllocatingTests {
@ParameterizedDataBufferAllocatingTest
@SuppressWarnings("deprecation")
void dataBufferContainsByteBufferChanges(DataBufferFactory bufferFactory) {
assumeFalse(bufferFactory instanceof Netty5DataBufferFactory,
"Netty 5 does not support sharing data between buffers");
super.bufferFactory = bufferFactory;
DataBuffer dataBuffer = createDataBuffer(1);
@@ -833,18 +815,13 @@ class DataBufferTests extends AbstractDataBufferAllocatingTests {
result = new byte[2];
slice.read(result);
if (!(bufferFactory instanceof Netty5DataBufferFactory)) {
assertThat(result).isEqualTo(new byte[]{'b', 'c'});
}
assertThat(result).isEqualTo(new byte[]{'b', 'c'});
release(buffer);
}
@ParameterizedDataBufferAllocatingTest
@SuppressWarnings("deprecation")
void retainedSlice(DataBufferFactory bufferFactory) {
assumeFalse(bufferFactory instanceof Netty5DataBufferFactory,
"Netty 5 does not support retainedSlice");
super.bufferFactory = bufferFactory;
DataBuffer buffer = createDataBuffer(3);
@@ -887,9 +864,7 @@ class DataBufferTests extends AbstractDataBufferAllocatingTests {
assertThat(result).isEqualTo(bytes);
if (bufferFactory instanceof Netty5DataBufferFactory) {
release(slice);
}
release(slice);
release(buffer);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@@ -20,7 +20,6 @@ import java.time.Duration;
import java.util.Map;
import java.util.function.Consumer;
import io.netty5.buffer.Buffer;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.reactivestreams.Publisher;
@@ -210,13 +209,7 @@ public abstract class AbstractDecoderTests<D extends Decoder<?>> extends Abstrac
Flux<DataBuffer> flux = Mono.from(input).concatWith(Flux.error(new InputException()));
assertThatExceptionOfType(InputException.class).isThrownBy(() ->
this.decoder.decode(flux, outputType, mimeType, hints)
.doOnNext(object -> {
if (object instanceof Buffer buffer) {
buffer.close();
}
})
.blockLast(Duration.ofSeconds(5)));
this.decoder.decode(flux, outputType, mimeType, hints).blockLast(Duration.ofSeconds(5)));
}
/**
@@ -233,12 +226,7 @@ public abstract class AbstractDecoderTests<D extends Decoder<?>> extends Abstrac
protected void testDecodeCancel(Publisher<DataBuffer> input, ResolvableType outputType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
Flux<?> result = this.decoder.decode(input, outputType, mimeType, hints)
.doOnNext(object -> {
if (object instanceof Buffer buffer) {
buffer.close();
}
});
Flux<?> result = this.decoder.decode(input, outputType, mimeType, hints);
StepVerifier.create(result).expectNextCount(1).thenCancel().verify();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 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.
@@ -34,8 +34,6 @@ import io.netty.buffer.PoolArenaMetric;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.PooledByteBufAllocatorMetric;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty5.buffer.BufferAllocator;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -48,7 +46,6 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.core.io.buffer.Netty5DataBufferFactory;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -65,14 +62,6 @@ import static org.junit.jupiter.params.provider.Arguments.argumentSet;
*/
public abstract class AbstractDataBufferAllocatingTests {
private static BufferAllocator netty5OnHeapUnpooled;
private static BufferAllocator netty5OffHeapUnpooled;
private static BufferAllocator netty5OffHeapPooled;
private static BufferAllocator netty5OnHeapPooled;
private static UnpooledByteBufAllocator netty4OffHeapUnpooled;
private static UnpooledByteBufAllocator netty4OnHeapUnpooled;
@@ -178,19 +167,6 @@ public abstract class AbstractDataBufferAllocatingTests {
netty4OffHeapUnpooled = new UnpooledByteBufAllocator(true);
netty4OnHeapPooled = new PooledByteBufAllocator(false, 1, 1, 4096, 4, 0, 0, 0, true);
netty4OffHeapPooled = new PooledByteBufAllocator(true, 1, 1, 4096, 4, 0, 0, 0, true);
netty5OnHeapUnpooled = BufferAllocator.onHeapUnpooled();
netty5OffHeapUnpooled = BufferAllocator.offHeapUnpooled();
netty5OnHeapPooled = BufferAllocator.onHeapPooled();
netty5OffHeapPooled = BufferAllocator.offHeapPooled();
}
@AfterAll
static void closeAllocators() {
netty5OnHeapUnpooled.close();
netty5OffHeapUnpooled.close();
netty5OnHeapPooled.close();
netty5OffHeapPooled.close();
}
@@ -212,15 +188,6 @@ public abstract class AbstractDataBufferAllocatingTests {
new NettyDataBufferFactory(netty4OffHeapPooled)),
argumentSet("NettyDataBufferFactory - PooledByteBufAllocator - preferDirect = false",
new NettyDataBufferFactory(netty4OnHeapPooled)),
// Netty 5
argumentSet("Netty5DataBufferFactory - BufferAllocator.onHeapUnpooled()",
new Netty5DataBufferFactory(netty5OnHeapUnpooled)),
argumentSet("Netty5DataBufferFactory - BufferAllocator.offHeapUnpooled()",
new Netty5DataBufferFactory(netty5OffHeapUnpooled)),
argumentSet("Netty5DataBufferFactory - BufferAllocator.onHeapPooled()",
new Netty5DataBufferFactory(netty5OnHeapPooled)),
argumentSet("Netty5DataBufferFactory - BufferAllocator.offHeapPooled()",
new Netty5DataBufferFactory(netty5OffHeapPooled)),
// Default
argumentSet("DefaultDataBufferFactory - preferDirect = true",
new DefaultDataBufferFactory(true)),