Nullability refinements and related polishing
This commit is contained in:
parent
c5b3848357
commit
cdf51c3d51
|
|
@ -211,9 +211,8 @@ final class ConfigurationClass {
|
||||||
|
|
||||||
public void validate(ProblemReporter problemReporter) {
|
public void validate(ProblemReporter problemReporter) {
|
||||||
// A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
|
// A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
|
||||||
String annotationName = Configuration.class.getName();
|
Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
|
||||||
if (this.metadata.isAnnotated(annotationName) &&
|
if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
|
||||||
(Boolean) this.metadata.getAnnotationAttributes(annotationName).get("proxyBeanMethods")) {
|
|
||||||
if (this.metadata.isFinal()) {
|
if (this.metadata.isFinal()) {
|
||||||
problemReporter.error(new FinalConfigurationProblem());
|
problemReporter.error(new FinalConfigurationProblem());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ import org.springframework.util.MimeType;
|
||||||
* Base class for a return value handler that encodes return values to
|
* Base class for a return value handler that encodes return values to
|
||||||
* {@code Flux<DataBuffer>} through the configured {@link Encoder}s.
|
* {@code Flux<DataBuffer>} through the configured {@link Encoder}s.
|
||||||
*
|
*
|
||||||
* <p>Sub-classes must implement the abstract method
|
* <p>Subclasses must implement the abstract method
|
||||||
* {@link #handleEncodedContent} to handle the resulting encoded content.
|
* {@link #handleEncodedContent} to handle the resulting encoded content.
|
||||||
*
|
*
|
||||||
* <p>This handler should be ordered last since its {@link #supportsReturnType}
|
* <p>This handler should be ordered last since its {@link #supportsReturnType}
|
||||||
|
|
@ -69,7 +69,6 @@ public abstract class AbstractEncoderMethodReturnValueHandler implements Handler
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
|
||||||
private final List<Encoder<?>> encoders;
|
private final List<Encoder<?>> encoders;
|
||||||
|
|
||||||
private final ReactiveAdapterRegistry adapterRegistry;
|
private final ReactiveAdapterRegistry adapterRegistry;
|
||||||
|
|
@ -118,7 +117,6 @@ public abstract class AbstractEncoderMethodReturnValueHandler implements Handler
|
||||||
.getOrDefault(HandlerMethodReturnValueHandler.DATA_BUFFER_FACTORY_HEADER, this.defaultBufferFactory);
|
.getOrDefault(HandlerMethodReturnValueHandler.DATA_BUFFER_FACTORY_HEADER, this.defaultBufferFactory);
|
||||||
|
|
||||||
MimeType mimeType = (MimeType) message.getHeaders().get(MessageHeaders.CONTENT_TYPE);
|
MimeType mimeType = (MimeType) message.getHeaders().get(MessageHeaders.CONTENT_TYPE);
|
||||||
|
|
||||||
Flux<DataBuffer> encodedContent = encodeContent(
|
Flux<DataBuffer> encodedContent = encodeContent(
|
||||||
returnValue, returnType, bufferFactory, mimeType, Collections.emptyMap());
|
returnValue, returnType, bufferFactory, mimeType, Collections.emptyMap());
|
||||||
|
|
||||||
|
|
@ -147,8 +145,8 @@ public abstract class AbstractEncoderMethodReturnValueHandler implements Handler
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
publisher = Mono.justOrEmpty(content);
|
publisher = Mono.justOrEmpty(content);
|
||||||
elementType = returnValueType.toClass() == Object.class && content != null ?
|
elementType = (returnValueType.toClass() == Object.class && content != null ?
|
||||||
ResolvableType.forInstance(content) : returnValueType;
|
ResolvableType.forInstance(content) : returnValueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elementType.resolve() == void.class || elementType.resolve() == Void.class) {
|
if (elementType.resolve() == void.class || elementType.resolve() == Void.class) {
|
||||||
|
|
@ -156,7 +154,6 @@ public abstract class AbstractEncoderMethodReturnValueHandler implements Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
Encoder<?> encoder = getEncoder(elementType, mimeType);
|
Encoder<?> encoder = getEncoder(elementType, mimeType);
|
||||||
|
|
||||||
return Flux.from((Publisher) publisher).map(value ->
|
return Flux.from((Publisher) publisher).map(value ->
|
||||||
encodeValue(value, elementType, encoder, bufferFactory, mimeType, hints));
|
encodeValue(value, elementType, encoder, bufferFactory, mimeType, hints));
|
||||||
}
|
}
|
||||||
|
|
@ -201,9 +198,8 @@ public abstract class AbstractEncoderMethodReturnValueHandler implements Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sub-classes implement this method to handle encoded values in some way
|
* Subclasses implement this method to handle encoded values in some way
|
||||||
* such as creating and sending messages.
|
* such as creating and sending messages.
|
||||||
*
|
|
||||||
* @param encodedContent the encoded content; each {@code DataBuffer}
|
* @param encodedContent the encoded content; each {@code DataBuffer}
|
||||||
* represents the fully-aggregated, encoded content for one value
|
* represents the fully-aggregated, encoded content for one value
|
||||||
* (i.e. payload) returned from the HandlerMethod.
|
* (i.e. payload) returned from the HandlerMethod.
|
||||||
|
|
@ -229,9 +225,12 @@ public abstract class AbstractEncoderMethodReturnValueHandler implements Handler
|
||||||
*/
|
*/
|
||||||
private static class KotlinDelegate {
|
private static class KotlinDelegate {
|
||||||
|
|
||||||
static private boolean isSuspend(Method method) {
|
static private boolean isSuspend(@Nullable Method method) {
|
||||||
|
if (method == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method);
|
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method);
|
||||||
return function != null && function.isSuspend();
|
return (function != null && function.isSuspend());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ import org.springframework.http.ReactiveHttpInputMessage;
|
||||||
import org.springframework.http.codec.HttpMessageReader;
|
import org.springframework.http.codec.HttpMessageReader;
|
||||||
import org.springframework.http.codec.LoggingCodecSupport;
|
import org.springframework.http.codec.LoggingCodecSupport;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -57,8 +58,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
* @see MultipartHttpMessageReader
|
* @see MultipartHttpMessageReader
|
||||||
*/
|
*/
|
||||||
public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
public class DefaultMultipartMessageReader extends LoggingCodecSupport implements HttpMessageReader<Part> {
|
||||||
implements HttpMessageReader<Part> {
|
|
||||||
|
|
||||||
private static final byte CR = '\r';
|
private static final byte CR = '\r';
|
||||||
|
|
||||||
|
|
@ -74,8 +74,7 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
|
|
||||||
private static final String HEADER_SEPARATOR = "\\r\\n";
|
private static final String HEADER_SEPARATOR = "\\r\\n";
|
||||||
|
|
||||||
private static final DataBufferUtils.Matcher HEADER_MATCHER =
|
private static final DataBufferUtils.Matcher HEADER_MATCHER = DataBufferUtils.matcher(HEADER_BODY_SEPARATOR);
|
||||||
DataBufferUtils.matcher(HEADER_BODY_SEPARATOR);
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -85,14 +84,12 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canRead(ResolvableType elementType, @Nullable MediaType mediaType) {
|
public boolean canRead(ResolvableType elementType, @Nullable MediaType mediaType) {
|
||||||
return Part.class.equals(elementType.toClass()) &&
|
return (Part.class.equals(elementType.toClass()) &&
|
||||||
(mediaType == null || MediaType.MULTIPART_FORM_DATA.isCompatibleWith(mediaType));
|
(mediaType == null || MediaType.MULTIPART_FORM_DATA.isCompatibleWith(mediaType)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<Part> read(ResolvableType elementType, ReactiveHttpInputMessage message,
|
public Flux<Part> read(ResolvableType elementType, ReactiveHttpInputMessage message, Map<String, Object> hints) {
|
||||||
Map<String, Object> hints) {
|
|
||||||
|
|
||||||
byte[] boundary = boundary(message);
|
byte[] boundary = boundary(message);
|
||||||
if (boundary == null) {
|
if (boundary == null) {
|
||||||
return Flux.error(new CodecException("No multipart boundary found in Content-Type: \"" +
|
return Flux.error(new CodecException("No multipart boundary found in Content-Type: \"" +
|
||||||
|
|
@ -126,12 +123,9 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
* all data until then. Note that the first boundary of a multipart message does not contain
|
* all data until then. Note that the first boundary of a multipart message does not contain
|
||||||
* the initial \r\n, hence the need for a special boundary matcher.
|
* the initial \r\n, hence the need for a special boundary matcher.
|
||||||
*/
|
*/
|
||||||
private static Flux<DataBuffer> skipUntilFirstBoundary(Flux<DataBuffer> dataBuffers,
|
private static Flux<DataBuffer> skipUntilFirstBoundary(Flux<DataBuffer> dataBuffers, byte[] boundary) {
|
||||||
byte[] boundary) {
|
|
||||||
|
|
||||||
byte[] needle = concat(FIRST_BOUNDARY_PREFIX, boundary);
|
byte[] needle = concat(FIRST_BOUNDARY_PREFIX, boundary);
|
||||||
DataBufferUtils.Matcher matcher = DataBufferUtils.matcher(needle);
|
DataBufferUtils.Matcher matcher = DataBufferUtils.matcher(needle);
|
||||||
|
|
||||||
AtomicBoolean found = new AtomicBoolean();
|
AtomicBoolean found = new AtomicBoolean();
|
||||||
|
|
||||||
return dataBuffers.concatMap(dataBuffer -> {
|
return dataBuffers.concatMap(dataBuffer -> {
|
||||||
|
|
@ -152,7 +146,6 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,8 +156,7 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
private static boolean notLastBoundary(DataBuffer dataBuffer) {
|
private static boolean notLastBoundary(DataBuffer dataBuffer) {
|
||||||
if (dataBuffer.readableByteCount() >= 2) {
|
if (dataBuffer.readableByteCount() >= 2) {
|
||||||
int readPosition = dataBuffer.readPosition();
|
int readPosition = dataBuffer.readPosition();
|
||||||
if ((dataBuffer.getByte(readPosition) == HYPHEN) &&
|
if (dataBuffer.getByte(readPosition) == HYPHEN && dataBuffer.getByte(readPosition + 1) == HYPHEN) {
|
||||||
(dataBuffer.getByte(readPosition + 1) == HYPHEN)) {
|
|
||||||
DataBufferUtils.release(dataBuffer);
|
DataBufferUtils.release(dataBuffer);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -180,8 +172,7 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
private static Part toPart(DataBuffer dataBuffer) {
|
private static Part toPart(DataBuffer dataBuffer) {
|
||||||
int readPosition = dataBuffer.readPosition();
|
int readPosition = dataBuffer.readPosition();
|
||||||
if (dataBuffer.readableByteCount() >= 2) {
|
if (dataBuffer.readableByteCount() >= 2) {
|
||||||
if ( (dataBuffer.getByte(readPosition) == CR) &&
|
if (dataBuffer.getByte(readPosition) == CR && dataBuffer.getByte(readPosition + 1) == LF) {
|
||||||
(dataBuffer.getByte(readPosition + 1) == LF)) {
|
|
||||||
dataBuffer.readPosition(readPosition + 2);
|
dataBuffer.readPosition(readPosition + 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -191,8 +182,7 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
DataBuffer body;
|
DataBuffer body;
|
||||||
if (endIdx > 0) {
|
if (endIdx > 0) {
|
||||||
readPosition = dataBuffer.readPosition();
|
readPosition = dataBuffer.readPosition();
|
||||||
int headersLength =
|
int headersLength = endIdx + 1 - (readPosition + HEADER_BODY_SEPARATOR.length);
|
||||||
endIdx + 1 - (readPosition + HEADER_BODY_SEPARATOR.length);
|
|
||||||
DataBuffer headersBuffer = dataBuffer.retainedSlice(readPosition, headersLength);
|
DataBuffer headersBuffer = dataBuffer.retainedSlice(readPosition, headersLength);
|
||||||
int bodyLength = dataBuffer.writePosition() - (1 + endIdx);
|
int bodyLength = dataBuffer.writePosition() - (1 + endIdx);
|
||||||
body = dataBuffer.retainedSlice(endIdx + 1, bodyLength);
|
body = dataBuffer.retainedSlice(endIdx + 1, bodyLength);
|
||||||
|
|
@ -275,7 +265,6 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
|
|
||||||
protected final DataBuffer body;
|
protected final DataBuffer body;
|
||||||
|
|
||||||
|
|
||||||
public DefaultPart(HttpHeaders headers, DataBuffer body) {
|
public DefaultPart(HttpHeaders headers, DataBuffer body) {
|
||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
|
|
@ -283,7 +272,9 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String name() {
|
public String name() {
|
||||||
return headers().getContentDisposition().getName();
|
String name = headers().getContentDisposition().getName();
|
||||||
|
Assert.state(name != null, "No name available");
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -295,7 +286,6 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
public Flux<DataBuffer> content() {
|
public Flux<DataBuffer> content() {
|
||||||
return Flux.just(this.body);
|
return Flux.just(this.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -342,14 +332,15 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String filename() {
|
public String filename() {
|
||||||
return headers().getContentDisposition().getFilename();
|
String filename = headers().getContentDisposition().getFilename();
|
||||||
|
Assert.state(filename != null, "No filename available");
|
||||||
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> transferTo(Path dest) {
|
public Mono<Void> transferTo(Path dest) {
|
||||||
return Mono.using(() -> AsynchronousFileChannel.open(dest, StandardOpenOption.WRITE),
|
return Mono.using(() -> AsynchronousFileChannel.open(dest, StandardOpenOption.WRITE),
|
||||||
this::writeBody,
|
this::writeBody, this::close);
|
||||||
this::close);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<Void> writeBody(AsynchronousFileChannel channel) {
|
private Mono<Void> writeBody(AsynchronousFileChannel channel) {
|
||||||
|
|
@ -366,4 +357,5 @@ public class DefaultMultipartMessageReader extends LoggingCodecSupport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue