Nullability refinements and related polishing

This commit is contained in:
Juergen Hoeller 2019-05-08 00:27:56 +02:00
parent c5b3848357
commit cdf51c3d51
3 changed files with 29 additions and 39 deletions

View File

@ -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());
} }

View File

@ -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());
} }
} }

View File

@ -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
} }
} }
} }
} }