Introduce null-safety of Spring Framework API

This commit introduces 2 new @Nullable and @NonNullApi
annotations that leverage JSR 305 (dormant but available via
Findbugs jsr305 dependency and already used by libraries
like OkHttp) meta-annotations to specify explicitly
null-safety of Spring Framework parameters and return values.

In order to avoid adding too much annotations, the
default is set at package level with @NonNullApi and
@Nullable annotations are added when needed at parameter or
return value level. These annotations are intended to be used
on Spring Framework itself but also by other Spring projects.

@Nullable annotations have been introduced based on Javadoc
and search of patterns like "return null;". It is expected that
nullability of Spring Framework API will be polished with
complementary commits.

In practice, this will make the whole Spring Framework API
null-safe for Kotlin projects (when KT-10942 will be fixed)
since Kotlin will be able to leverage these annotations to
know if a parameter or a return value is nullable or not. But
this is also useful for Java developers as well since IntelliJ
IDEA, for example, also understands these annotations to
generate warnings when unsafe nullable usages are detected.

Issue: SPR-15540
This commit is contained in:
Sebastien Deleuze
2017-05-27 08:14:59 +02:00
parent 2d37c966b2
commit 87598f48e4
1315 changed files with 4831 additions and 963 deletions

View File

@@ -31,6 +31,7 @@ import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.AlternativeJdkIdGenerator;
import org.springframework.util.IdGenerator;
@@ -164,24 +165,29 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
return (idGenerator != null ? idGenerator : defaultIdGenerator);
}
@Nullable
public UUID getId() {
return get(ID, UUID.class);
}
@Nullable
public Long getTimestamp() {
return get(TIMESTAMP, Long.class);
}
@Nullable
public Object getReplyChannel() {
return get(REPLY_CHANNEL);
}
@Nullable
public Object getErrorChannel() {
return get(ERROR_CHANNEL);
}
@SuppressWarnings("unchecked")
@Nullable
public <T> T get(Object key, Class<T> type) {
Object value = this.headers.get(key);
if (value == null) {
@@ -209,6 +215,7 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
return Collections.unmodifiableMap(this.headers).entrySet();
}
@Nullable
public Object get(Object key) {
return this.headers.get(key);
}

View File

@@ -16,6 +16,8 @@
package org.springframework.messaging;
import org.springframework.lang.Nullable;
/**
* A {@link MessageChannel} from which messages may be actively received through polling.
*
@@ -28,6 +30,7 @@ public interface PollableChannel extends MessageChannel {
* Receive a message from this channel, blocking indefinitely if necessary.
* @return the next available {@link Message} or {@code null} if interrupted
*/
@Nullable
Message<?> receive();
/**
@@ -37,6 +40,7 @@ public interface PollableChannel extends MessageChannel {
* @return the next available {@link Message} or {@code null} if the specified timeout
* period elapses or the message reception is interrupted
*/
@Nullable
Message<?> receive(long timeout);
}

View File

@@ -24,6 +24,7 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
@@ -157,6 +158,7 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
* @param payload the payload being converted to message
* @return the content type, or {@code null} if not known
*/
@Nullable
protected MimeType getDefaultContentType(Object payload) {
List<MimeType> mimeTypes = getSupportedMimeTypes();
return (!mimeTypes.isEmpty() ? mimeTypes.get(0) : null);
@@ -255,7 +257,8 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
* perform the conversion
* @since 4.2
*/
protected Object convertFromInternal(Message<?> message, Class<?> targetClass, Object conversionHint) {
@Nullable
protected Object convertFromInternal(Message<?> message, Class<?> targetClass, @Nullable Object conversionHint) {
return null;
}
@@ -269,7 +272,8 @@ public abstract class AbstractMessageConverter implements SmartMessageConverter
* cannot perform the conversion
* @since 4.2
*/
protected Object convertToInternal(Object payload, MessageHeaders headers, Object conversionHint) {
@Nullable
protected Object convertToInternal(Object payload, @Nullable MessageHeaders headers, @Nullable Object conversionHint) {
return null;
}

View File

@@ -16,6 +16,7 @@
package org.springframework.messaging.converter;
import org.springframework.lang.Nullable;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.MimeType;
@@ -32,13 +33,14 @@ public interface ContentTypeResolver {
* Determine the {@link MimeType} of a message from the given MessageHeaders.
*
* @param headers the headers to use for the resolution
* @return the resolved {@code MimeType} of {@code null} if none found
* @return the resolved {@code MimeType} or {@code null} if none found
*
* @throws org.springframework.util.InvalidMimeTypeException if the content type
* is a String that cannot be parsed
* @throws java.lang.IllegalArgumentException if there is a content type but
* its type is unknown
*/
@Nullable
MimeType resolve(MessageHeaders headers);
}

View File

@@ -38,6 +38,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.Assert;
@@ -266,6 +267,7 @@ public class MappingJackson2MessageConverter extends AbstractMessageConverter {
* @return the serialization view class, or {@code null} if none
* @since 4.2
*/
@Nullable
protected Class<?> getSerializationView(Object conversionHint) {
if (conversionHint instanceof MethodParameter) {
MethodParameter param = (MethodParameter) conversionHint;

View File

@@ -16,6 +16,7 @@
package org.springframework.messaging.converter;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
@@ -41,6 +42,7 @@ public interface MessageConverter {
* @return the result of the conversion, or {@code null} if the converter cannot
* perform the conversion
*/
@Nullable
Object fromMessage(Message<?> message, Class<?> targetClass);
/**
@@ -56,6 +58,7 @@ public interface MessageConverter {
* @return the new message, or {@code null} if the converter does not support the
* Object type or the target media type
*/
Message<?> toMessage(Object payload, MessageHeaders headers);
@Nullable
Message<?> toMessage(Object payload, @Nullable MessageHeaders headers);
}

View File

@@ -16,6 +16,7 @@
package org.springframework.messaging.converter;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
@@ -43,7 +44,8 @@ public interface SmartMessageConverter extends MessageConverter {
* perform the conversion
* @see #fromMessage(Message, Class)
*/
Object fromMessage(Message<?> message, Class<?> targetClass, Object conversionHint);
@Nullable
Object fromMessage(Message<?> message, Class<?> targetClass, @Nullable Object conversionHint);
/**
* A variant of {@link #toMessage(Object, MessageHeaders)} which takes an extra
@@ -57,6 +59,7 @@ public interface SmartMessageConverter extends MessageConverter {
* Object type or the target media type
* @see #toMessage(Object, MessageHeaders)
*/
Message<?> toMessage(Object payload, MessageHeaders headers, Object conversionHint);
@Nullable
Message<?> toMessage(Object payload, @Nullable MessageHeaders headers, @Nullable Object conversionHint);
}

View File

@@ -1,4 +1,7 @@
/**
* Provides support for message conversion.
*/
@NonNullApi
package org.springframework.messaging.converter;
import org.springframework.lang.NonNullApi;

View File

@@ -16,6 +16,7 @@
package org.springframework.messaging.core;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.messaging.converter.MessageConverter;
@@ -48,6 +49,7 @@ public abstract class AbstractMessageReceivingTemplate<D> extends AbstractMessag
* @return the received message, possibly {@code null} if the message could not
* be received, for example due to a timeout
*/
@Nullable
protected abstract Message<?> doReceive(D destination);
@@ -74,6 +76,7 @@ public abstract class AbstractMessageReceivingTemplate<D> extends AbstractMessag
* @return the converted payload of the reply message (never {@code null})
*/
@SuppressWarnings("unchecked")
@Nullable
protected <T> T doConvert(Message<?> message, Class<T> targetClass) {
MessageConverter messageConverter = getMessageConverter();
T value = (T) messageConverter.fromMessage(message, targetClass);

View File

@@ -21,6 +21,7 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
@@ -189,7 +190,8 @@ public abstract class AbstractMessageSendingTemplate<D> implements MessageSendin
* @param headers the headers to send (or {@code null} if none)
* @return the actual headers to send (or {@code null} if none)
*/
protected Map<String, Object> processHeadersToSend(Map<String, Object> headers) {
@Nullable
protected Map<String, Object> processHeadersToSend(@Nullable Map<String, Object> headers) {
return headers;
}

View File

@@ -18,6 +18,7 @@ package org.springframework.messaging.core;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
@@ -40,6 +41,7 @@ public interface DestinationResolvingMessageRequestReplyOperations<D> extends Me
* @return the received message, possibly {@code null} if the message could not
* be received, for example due to a timeout
*/
@Nullable
Message<?> sendAndReceive(String destinationName, Message<?> requestMessage) throws MessagingException;
/**
@@ -54,6 +56,7 @@ public interface DestinationResolvingMessageRequestReplyOperations<D> extends Me
* @return the converted payload of the reply message, possibly {@code null} if
* the message could not be received, for example due to a timeout
*/
@Nullable
<T> T convertSendAndReceive(String destinationName, Object request, Class<T> targetClass)
throws MessagingException;
@@ -70,6 +73,7 @@ public interface DestinationResolvingMessageRequestReplyOperations<D> extends Me
* @return the converted payload of the reply message, possibly {@code null} if
* the message could not be received, for example due to a timeout
*/
@Nullable
<T> T convertSendAndReceive(String destinationName, Object request, Map<String, Object> headers,
Class<T> targetClass) throws MessagingException;
@@ -87,6 +91,7 @@ public interface DestinationResolvingMessageRequestReplyOperations<D> extends Me
* @return the converted payload of the reply message, possibly {@code null} if
* the message could not be received, for example due to a timeout
*/
@Nullable
<T> T convertSendAndReceive(String destinationName, Object request,
Class<T> targetClass, MessagePostProcessor requestPostProcessor) throws MessagingException;
@@ -105,6 +110,7 @@ public interface DestinationResolvingMessageRequestReplyOperations<D> extends Me
* @return the converted payload of the reply message, possibly {@code null} if
* the message could not be received, for example due to a timeout
*/
@Nullable
<T> T convertSendAndReceive(String destinationName, Object request, Map<String, Object> headers,
Class<T> targetClass, MessagePostProcessor requestPostProcessor) throws MessagingException;

View File

@@ -16,6 +16,7 @@
package org.springframework.messaging.core;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
@@ -35,6 +36,7 @@ public interface MessageReceivingOperations<D> {
* @return the received message, possibly {@code null} if the message could not
* be received, for example due to a timeout
*/
@Nullable
Message<?> receive() throws MessagingException;
/**
@@ -43,6 +45,7 @@ public interface MessageReceivingOperations<D> {
* @return the received message, possibly {@code null} if the message could not
* be received, for example due to a timeout
*/
@Nullable
Message<?> receive(D destination) throws MessagingException;
/**
@@ -52,6 +55,7 @@ public interface MessageReceivingOperations<D> {
* @return the converted payload of the reply message, possibly {@code null} if
* the message could not be received, for example due to a timeout
*/
@Nullable
<T> T receiveAndConvert(Class<T> targetClass) throws MessagingException;
/**
@@ -62,6 +66,7 @@ public interface MessageReceivingOperations<D> {
* @return the converted payload of the reply message, possibly {@code null} if
* the message could not be received, for example due to a timeout
*/
@Nullable
<T> T receiveAndConvert(D destination, Class<T> targetClass) throws MessagingException;
}

View File

@@ -18,6 +18,7 @@ package org.springframework.messaging.core;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
@@ -38,6 +39,7 @@ public interface MessageRequestReplyOperations<D> {
* @return the reply, possibly {@code null} if the message could not be received,
* for example due to a timeout
*/
@Nullable
Message<?> sendAndReceive(Message<?> requestMessage) throws MessagingException;
/**
@@ -47,6 +49,7 @@ public interface MessageRequestReplyOperations<D> {
* @return the reply, possibly {@code null} if the message could not be received,
* for example due to a timeout
*/
@Nullable
Message<?> sendAndReceive(D destination, Message<?> requestMessage) throws MessagingException;
/**
@@ -59,6 +62,7 @@ public interface MessageRequestReplyOperations<D> {
* @return the payload of the reply message, possibly {@code null} if the message
* could not be received, for example due to a timeout
*/
@Nullable
<T> T convertSendAndReceive(Object request, Class<T> targetClass) throws MessagingException;
/**
@@ -72,6 +76,7 @@ public interface MessageRequestReplyOperations<D> {
* @return the payload of the reply message, possibly {@code null} if the message
* could not be received, for example due to a timeout
*/
@Nullable
<T> T convertSendAndReceive(D destination, Object request, Class<T> targetClass) throws MessagingException;
/**
@@ -86,6 +91,7 @@ public interface MessageRequestReplyOperations<D> {
* @return the payload of the reply message, possibly {@code null} if the message
* could not be received, for example due to a timeout
*/
@Nullable
<T> T convertSendAndReceive(D destination, Object request, Map<String, Object> headers, Class<T> targetClass)
throws MessagingException;
@@ -101,6 +107,7 @@ public interface MessageRequestReplyOperations<D> {
* @return the payload of the reply message, possibly {@code null} if the message
* could not be received, for example due to a timeout
*/
@Nullable
<T> T convertSendAndReceive(Object request, Class<T> targetClass, MessagePostProcessor requestPostProcessor)
throws MessagingException;
@@ -117,6 +124,7 @@ public interface MessageRequestReplyOperations<D> {
* @return the payload of the reply message, possibly {@code null} if the message
* could not be received, for example due to a timeout
*/
@Nullable
<T> T convertSendAndReceive(D destination, Object request, Class<T> targetClass,
MessagePostProcessor requestPostProcessor) throws MessagingException;
@@ -133,6 +141,7 @@ public interface MessageRequestReplyOperations<D> {
* @return the payload of the reply message, possibly {@code null} if the message
* could not be received, for example due to a timeout
*/
@Nullable
<T> T convertSendAndReceive(D destination, Object request, Map<String, Object> headers,
Class<T> targetClass, MessagePostProcessor requestPostProcessor) throws MessagingException;

View File

@@ -1,4 +1,7 @@
/**
* Defines interfaces and implementation classes for messaging templates.
*/
@NonNullApi
package org.springframework.messaging.core;
import org.springframework.lang.NonNullApi;

View File

@@ -16,6 +16,7 @@
package org.springframework.messaging.handler;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
/**
@@ -46,6 +47,7 @@ public interface MessageCondition<T> {
* condition with sorted, matching patterns only.
* @return a condition instance in case of a match; or {@code null} if there is no match.
*/
@Nullable
T getMatchingCondition(Message<?> message);
/**

View File

@@ -1,4 +1,7 @@
/**
* Annotations and support classes for handling messages.
*/
@NonNullApi
package org.springframework.messaging.handler.annotation;
import org.springframework.lang.NonNullApi;

View File

@@ -27,6 +27,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.annotation.ValueConstants;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
@@ -75,7 +76,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
* and {@code #{...}} SpEL expressions in default values, or {@code null} if default
* values are not expected to contain expressions
*/
protected AbstractNamedValueMethodArgumentResolver(ConversionService cs, ConfigurableBeanFactory beanFactory) {
protected AbstractNamedValueMethodArgumentResolver(ConversionService cs, @Nullable ConfigurableBeanFactory beanFactory) {
this.conversionService = (cs != null ? cs : DefaultConversionService.getSharedInstance());
this.configurableBeanFactory = beanFactory;
this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, null) : null);
@@ -177,6 +178,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
* @return the resolved argument. May be {@code null}
* @throws Exception in case of errors
*/
@Nullable
protected abstract Object resolveArgumentInternal(MethodParameter parameter, Message<?> message, String name)
throws Exception;
@@ -194,7 +196,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
* A {@code null} results in a {@code false} value for {@code boolean}s or an
* exception for other primitives.
*/
private Object handleNullValue(String name, Object value, Class<?> paramType) {
private Object handleNullValue(String name, @Nullable Object value, Class<?> paramType) {
if (value == null) {
if (Boolean.TYPE.equals(paramType)) {
return Boolean.FALSE;

View File

@@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.handler.annotation.Header;
@@ -76,6 +77,7 @@ public class HeaderMethodArgumentResolver extends AbstractNamedValueMethodArgume
return (headerValue != null ? headerValue : nativeHeaderValue);
}
@Nullable
private Object getNativeHeaderValue(Message<?> message, String name) {
Map<String, List<String>> nativeHeaders = getNativeHeaders(message);
if (name.startsWith("nativeHeaders.")) {

View File

@@ -20,6 +20,7 @@ import java.lang.reflect.Type;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.messaging.converter.MessageConverter;
@@ -57,7 +58,7 @@ public class MessageMethodArgumentResolver implements HandlerMethodArgumentResol
* @param converter the MessageConverter to use (may be {@code null})
* @since 4.3
*/
public MessageMethodArgumentResolver(MessageConverter converter) {
public MessageMethodArgumentResolver(@Nullable MessageConverter converter) {
this.converter = converter;
}
@@ -103,7 +104,7 @@ public class MessageMethodArgumentResolver implements HandlerMethodArgumentResol
* Check if the given {@code payload} is empty.
* @param payload the payload to check (can be {@code null})
*/
protected boolean isEmptyPayload(Object payload) {
protected boolean isEmptyPayload(@Nullable Object payload) {
if (payload == null) {
return true;
}

View File

@@ -17,6 +17,7 @@
package org.springframework.messaging.handler.annotation.support;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.invocation.MethodArgumentResolutionException;
import org.springframework.validation.BindingResult;
@@ -57,6 +58,7 @@ public class MethodArgumentNotValidException extends MethodArgumentResolutionExc
* Return the BindingResult if the failure is validation-related,
* or {@code null} if none.
*/
@Nullable
public final BindingResult getBindingResult() {
return this.bindingResult;
}

View File

@@ -20,6 +20,7 @@ import java.lang.annotation.Annotation;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.messaging.converter.MessageConverter;
@@ -155,7 +156,7 @@ public class PayloadArgumentResolver implements HandlerMethodArgumentResolver {
* Specify if the given {@code payload} is empty.
* @param payload the payload to check (can be {@code null})
*/
protected boolean isEmptyPayload(Object payload) {
protected boolean isEmptyPayload(@Nullable Object payload) {
if (payload == null) {
return true;
}

View File

@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.core.ExceptionDepthComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -84,6 +85,7 @@ public abstract class AbstractExceptionHandlerMethodResolver {
* @param exception the exception
* @return a Method to handle the exception, or {@code null} if none found
*/
@Nullable
public Method resolveMethod(Exception exception) {
Method method = resolveMethodByExceptionType(exception.getClass());
if (method == null) {
@@ -102,6 +104,7 @@ public abstract class AbstractExceptionHandlerMethodResolver {
* @return a Method to handle the exception, or {@code null} if none found
* @since 4.3.1
*/
@Nullable
public Method resolveMethodByExceptionType(Class<? extends Throwable> exceptionType) {
Method method = this.exceptionLookupCache.get(exceptionType);
if (method == null) {
@@ -114,6 +117,7 @@ public abstract class AbstractExceptionHandlerMethodResolver {
/**
* Return the {@link Method} mapped to the given exception type, or {@code null} if none.
*/
@Nullable
private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
List<Class<? extends Throwable>> matches = new ArrayList<>();
for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {

View File

@@ -35,6 +35,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
@@ -304,6 +305,7 @@ public abstract class AbstractMethodMessageHandler<T>
* @param handlerType the handler type, possibly a sub-type of the method's declaring class
* @return the mapping, or {@code null} if the method is not mapped
*/
@Nullable
protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
/**
@@ -409,6 +411,7 @@ public abstract class AbstractMethodMessageHandler<T>
* <p>If there are no matching prefixes, return {@code null}.
* <p>If there are no destination prefixes, return the destination as is.
*/
@Nullable
protected String getLookupDestination(String destination) {
if (destination == null) {
return null;
@@ -477,6 +480,7 @@ public abstract class AbstractMethodMessageHandler<T>
* @param message the message being handled
* @return the match or {@code null} if there is no match
*/
@Nullable
protected abstract T getMatchingMapping(T mapping, Message<?> message);
protected void handleNoMatch(Set<T> ts, String lookupDestination, Message<?> message) {
@@ -559,6 +563,7 @@ public abstract class AbstractMethodMessageHandler<T>
* @return a method to handle the exception, or {@code null}
* @since 4.2
*/
@Nullable
protected InvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
if (logger.isDebugEnabled()) {
logger.debug("Searching methods to handle " + exception.getClass().getSimpleName());

View File

@@ -17,6 +17,7 @@
package org.springframework.messaging.handler.invocation;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.util.concurrent.ListenableFuture;
/**
@@ -61,6 +62,7 @@ public interface AsyncHandlerMethodReturnValueHandler extends HandlerMethodRetur
* @return the resulting ListenableFuture or {@code null} in which case no
* further handling will be performed.
*/
@Nullable
ListenableFuture<?> toListenableFuture(Object returnValue, MethodParameter returnType);
}

View File

@@ -17,6 +17,7 @@
package org.springframework.messaging.handler.invocation;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
/**
@@ -47,6 +48,7 @@ public interface HandlerMethodArgumentResolver {
* @return the resolved argument value, or {@code null}
* @throws Exception in case of errors with the preparation of argument values
*/
@Nullable
Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception;
}

View File

@@ -24,6 +24,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.ListenableFuture;
@@ -80,6 +81,7 @@ public class HandlerMethodReturnValueHandlerComposite implements AsyncHandlerMet
return getReturnValueHandler(returnType) != null;
}
@Nullable
private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (handler.supportsReturnType(returnType)) {

View File

@@ -25,6 +25,7 @@ import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.HandlerMethod;
import org.springframework.util.ClassUtils;
@@ -158,6 +159,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
/**
* Attempt to resolve a method parameter from the list of provided argument values.
*/
@Nullable
private Object resolveProvidedArgument(MethodParameter parameter, Object... providedArgs) {
if (providedArgs == null) {
return null;

View File

@@ -1,4 +1,7 @@
/**
* Common infrastructure for invoking message handler methods.
*/
@NonNullApi
package org.springframework.messaging.handler.invocation;
import org.springframework.lang.NonNullApi;

View File

@@ -1,4 +1,7 @@
/**
* Basic abstractions for working with message handler methods.
*/
@NonNullApi
package org.springframework.messaging.handler;
import org.springframework.lang.NonNullApi;

View File

@@ -1,4 +1,7 @@
/**
* Support for working with messaging APIs and protocols.
*/
@NonNullApi
package org.springframework.messaging;
import org.springframework.lang.NonNullApi;

View File

@@ -21,6 +21,7 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.Assert;
@@ -70,6 +71,7 @@ public class SimpAttributes {
* @param name the name of the attribute
* @return the current attribute value, or {@code null} if not found
*/
@Nullable
public Object getAttribute(String name) {
return this.attributes.get(name);
}

View File

@@ -17,6 +17,7 @@
package org.springframework.messaging.simp;
import org.springframework.core.NamedThreadLocal;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
@@ -66,6 +67,7 @@ public abstract class SimpAttributesContextHolder {
* Return the SimpAttributes currently bound to the thread.
* @return the attributes or {@code null} if not bound
*/
@Nullable
public static SimpAttributes getAttributes() {
return attributesHolder.get();
}

View File

@@ -18,6 +18,7 @@ package org.springframework.messaging.simp;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.core.MessagePostProcessor;
import org.springframework.messaging.core.MessageSendingOperations;
@@ -83,7 +84,7 @@ public interface SimpMessageSendingOperations extends MessageSendingOperations<S
* @param payload the payload to send (may be {@code null})
* @param headers the message headers (may be {@code null})
*/
void convertAndSendToUser(String user, String destination, Object payload, Map<String, Object> headers)
void convertAndSendToUser(String user, String destination, @Nullable Object payload, @Nullable Map<String, Object> headers)
throws MessagingException;
/**
@@ -93,7 +94,7 @@ public interface SimpMessageSendingOperations extends MessageSendingOperations<S
* @param payload the payload to send (may be {@code null})
* @param postProcessor a postProcessor to post-process or modify the created message
*/
void convertAndSendToUser(String user, String destination, Object payload,
void convertAndSendToUser(String user, String destination, @Nullable Object payload,
MessagePostProcessor postProcessor) throws MessagingException;
/**

View File

@@ -1,4 +1,7 @@
/**
* Annotations and for handling messages from SImple Messaging Protocols such as STOMP.
*/
@NonNullApi
package org.springframework.messaging.simp.annotation;
import org.springframework.lang.NonNullApi;

View File

@@ -23,6 +23,7 @@ import java.util.Map;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
@@ -185,6 +186,7 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
}
}
@Nullable
private Object findAnnotation(MethodParameter returnType) {
Annotation[] anns = new Annotation[4];
anns[0] = AnnotatedElementUtils.findMergedAnnotation(returnType.getMethod(), SendToUser.class);
@@ -221,6 +223,7 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
return new DestinationVariablePlaceholderResolver(vars);
}
@Nullable
protected String getUserName(Message<?> message, MessageHeaders headers) {
Principal principal = SimpMessageHeaderAccessor.getUser(headers);
if (principal != null) {

View File

@@ -2,4 +2,7 @@
* Support classes for handling messages from simple messaging protocols
* (like STOMP).
*/
@NonNullApi
package org.springframework.messaging.simp.annotation.support;
import org.springframework.lang.NonNullApi;

View File

@@ -35,6 +35,7 @@ import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
@@ -428,6 +429,7 @@ public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry {
return this.destinationLookup.get(destination);
}
@Nullable
public Subscription getSubscription(String subscriptionId) {
for (Map.Entry<String, Set<DefaultSubscriptionRegistry.Subscription>> destinationEntry : this.destinationLookup.entrySet()) {
Set<Subscription> subs = destinationEntry.getValue();
@@ -456,6 +458,7 @@ public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry {
subs.add(new Subscription(subscriptionId, selectorExpression));
}
@Nullable
public String removeSubscription(String subscriptionId) {
for (Map.Entry<String, Set<DefaultSubscriptionRegistry.Subscription>> destinationEntry : this.destinationLookup.entrySet()) {
Set<Subscription> subs = destinationEntry.getValue();

View File

@@ -2,4 +2,7 @@
* Provides a "simple" message broker implementation along with an abstract base
* class and other supporting types such as a registry for subscriptions.
*/
@NonNullApi
package org.springframework.messaging.simp.broker;
import org.springframework.lang.NonNullApi;

View File

@@ -26,6 +26,7 @@ import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.converter.ByteArrayMessageConverter;
@@ -447,6 +448,7 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
* Override this method to provide a custom {@link Validator}.
* @since 4.0.1
*/
@Nullable
public Validator getValidator() {
return null;
}

View File

@@ -19,6 +19,7 @@ package org.springframework.messaging.simp.config;
import java.util.Arrays;
import java.util.Collection;
import org.springframework.lang.Nullable;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler;
@@ -188,6 +189,7 @@ public class MessageBrokerRegistry {
}
@Nullable
protected SimpleBrokerMessageHandler getSimpleBroker(SubscribableChannel brokerChannel) {
if (this.simpleBrokerRegistration == null && this.brokerRelayRegistration == null) {
enableSimpleBroker();
@@ -201,6 +203,7 @@ public class MessageBrokerRegistry {
return null;
}
@Nullable
protected StompBrokerRelayMessageHandler getStompBrokerRelay(SubscribableChannel brokerChannel) {
if (this.brokerRelayRegistration != null) {
return this.brokerRelayRegistration.getMessageHandler(brokerChannel);

View File

@@ -1,4 +1,7 @@
/**
* Configuration support for WebSocket messaging using higher level messaging protocols.
*/
@NonNullApi
package org.springframework.messaging.simp.config;
import org.springframework.lang.NonNullApi;

View File

@@ -1,4 +1,7 @@
/**
* Generic support for SImple Messaging Protocols including protocols such as STOMP.
*/
@NonNullApi
package org.springframework.messaging.simp;
import org.springframework.lang.NonNullApi;

View File

@@ -26,6 +26,7 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.messaging.support.MessageHeaderInitializer;
@@ -66,6 +67,7 @@ public class StompDecoder {
/**
* Return the configured {@code MessageHeaderInitializer}, if any.
*/
@Nullable
public MessageHeaderInitializer getHeaderInitializer() {
return this.headerInitializer;
}
@@ -80,6 +82,7 @@ public class StompDecoder {
* @return the decoded messages, or an empty list if none
* @throws StompConversionException raised in case of decoding issues
*/
@Nullable
public List<Message<byte[]>> decode(ByteBuffer byteBuffer) {
return decode(byteBuffer, null);
}
@@ -285,6 +288,7 @@ public class StompDecoder {
return sb.toString();
}
@Nullable
private byte[] readPayload(ByteBuffer byteBuffer, StompHeaderAccessor headerAccessor) {
Integer contentLength;
try {

View File

@@ -18,6 +18,8 @@ package org.springframework.messaging.simp.stomp;
import java.lang.reflect.Type;
import org.springframework.lang.Nullable;
/**
* Contract to handle a STOMP frame.
*
@@ -39,6 +41,6 @@ public interface StompFrameHandler {
* @param headers the headers of the frame
* @param payload the payload or {@code null} if there was no payload
*/
void handleFrame(StompHeaders headers, Object payload);
void handleFrame(StompHeaders headers, @Nullable Object payload);
}

View File

@@ -25,6 +25,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageType;
@@ -219,6 +220,7 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
/**
* Return the STOMP command, or {@code null} if not yet set.
*/
@Nullable
public StompCommand getCommand() {
return (StompCommand) getHeader(COMMAND_HEADER);
}
@@ -286,6 +288,7 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
}
}
@Nullable
public Integer getContentLength() {
if (containsNativeHeader(STOMP_CONTENT_LENGTH_HEADER)) {
return Integer.valueOf(getFirstNativeHeader(STOMP_CONTENT_LENGTH_HEADER));
@@ -341,6 +344,7 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
/**
* Return the passcode header value, or {@code null} if not set.
*/
@Nullable
public String getPasscode() {
StompPasscode credentials = (StompPasscode) getHeader(CREDENTIALS_HEADER);
return (credentials != null ? credentials.passcode : null);
@@ -490,6 +494,7 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
/**
* Return the STOMP command from the given headers, or {@code null} if not set.
*/
@Nullable
public static StompCommand getCommand(Map<String, Object> headers) {
return (StompCommand) headers.get(COMMAND_HEADER);
}
@@ -497,6 +502,7 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
/**
* Return the passcode header value, or {@code null} if not set.
*/
@Nullable
public static String getPasscode(Map<String, Object> headers) {
StompPasscode credentials = (StompPasscode) headers.get(CREDENTIALS_HEADER);
return (credentials != null ? credentials.passcode : null);

View File

@@ -16,6 +16,8 @@
package org.springframework.messaging.simp.stomp;
import org.springframework.lang.Nullable;
/**
* Represents a STOMP session with operations to send messages, create
* subscriptions and receive messages on those subscriptions.
@@ -115,6 +117,7 @@ public interface StompSession {
* Return the receipt id, or {@code null} if the STOMP frame for which
* the handle was returned did not have a "receipt" header.
*/
@Nullable
String getReceiptId();
/**

View File

@@ -1,4 +1,7 @@
/**
* Generic support for simple messaging protocols (like STOMP).
*/
@NonNullApi
package org.springframework.messaging.simp.stomp;
import org.springframework.lang.NonNullApi;

View File

@@ -24,6 +24,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
@@ -138,6 +139,7 @@ public class DefaultUserDestinationResolver implements UserDestinationResolver {
return new UserDestinationResult(sourceDestination, targetSet, subscribeDestination, user);
}
@Nullable
private ParseResult parse(Message<?> message) {
MessageHeaders headers = message.getHeaders();
String destination = SimpMessageHeaderAccessor.getDestination(headers);
@@ -215,8 +217,9 @@ public class DefaultUserDestinationResolver implements UserDestinationResolver {
* @return a target destination, or {@code null} if none
*/
@SuppressWarnings("unused")
@Nullable
protected String getTargetDestination(String sourceDestination, String actualDestination,
String sessionId, String user) {
String sessionId, @Nullable String user) {
return actualDestination + "-user" + sessionId;
}

View File

@@ -18,6 +18,8 @@ package org.springframework.messaging.simp.user;
import java.util.Set;
import org.springframework.lang.Nullable;
/**
* Represents a connected user.
*
@@ -39,8 +41,9 @@ public interface SimpUser {
/**
* Look up the session for the given id.
* @param sessionId the session id
* @return the matching session of {@code null}.
* @return the matching session or {@code null}.
*/
@Nullable
SimpSession getSession(String sessionId);
/**

View File

@@ -18,6 +18,8 @@ package org.springframework.messaging.simp.user;
import java.util.Set;
import org.springframework.lang.Nullable;
/**
* A registry of currently connected users.
*
@@ -31,6 +33,7 @@ public interface SimpUserRegistry {
* @param userName the name of the user to look up
* @return the user, or {@code null} if not connected
*/
@Nullable
SimpUser getUser(String userName);
/**

View File

@@ -23,6 +23,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.SmartLifecycle;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessageHeaders;
@@ -253,6 +254,7 @@ public class UserDestinationMessageHandler implements MessageHandler, SmartLifec
return this.broadcastDestination;
}
@Nullable
public Message<?> preHandle(Message<?> message) throws MessagingException {
String destination = SimpMessageHeaderAccessor.getDestination(message.getHeaders());
if (!getBroadcastDestination().equals(destination)) {

View File

@@ -16,6 +16,7 @@
package org.springframework.messaging.simp.user;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
/**
@@ -44,6 +45,7 @@ public interface UserDestinationResolver {
* @return 0 or more target messages (one for each active session), or
* {@code null} if the source message does not contain a user destination.
*/
@Nullable
UserDestinationResult resolveDestination(Message<?> message);
}

View File

@@ -18,6 +18,7 @@ package org.springframework.messaging.simp.user;
import java.util.Set;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -89,6 +90,7 @@ public class UserDestinationResult {
* sessionId in place of a user name thus removing the need for a user-to-session
* lookup via {@link SimpUserRegistry}.
*/
@Nullable
public String getUser() {
return this.user;
}

View File

@@ -6,4 +6,7 @@
* <p>Also included is {@link org.springframework.messaging.simp.user.SimpUserRegistry}
* for keeping track of connected user sessions.
*/
@NonNullApi
package org.springframework.messaging.simp.user;
import org.springframework.lang.NonNullApi;

View File

@@ -21,6 +21,7 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.StringUtils;
@@ -88,6 +89,7 @@ public abstract class AbstractHeaderMapper<T> implements HeaderMapper<T> {
* Return the header value, or {@code null} if it does not exist
* or does not match the requested {@code type}.
*/
@Nullable
protected <V> V getHeaderIfAvailable(Map<String, Object> headers, String name, Class<V> type) {
Object value = headers.get(name);
if (value == null) {

View File

@@ -24,6 +24,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageDeliveryException;
@@ -152,6 +153,7 @@ public abstract class AbstractMessageChannel implements MessageChannel, Intercep
private int receiveInterceptorIndex = -1;
@Nullable
public Message<?> applyPreSend(Message<?> message, MessageChannel channel) {
Message<?> messageToUse = message;
for (ChannelInterceptor interceptor : interceptors) {
@@ -199,6 +201,7 @@ public abstract class AbstractMessageChannel implements MessageChannel, Intercep
return true;
}
@Nullable
public Message<?> applyPostReceive(Message<?> message, MessageChannel channel) {
for (ChannelInterceptor interceptor : interceptors) {
message = interceptor.postReceive(message, channel);

View File

@@ -16,6 +16,7 @@
package org.springframework.messaging.support;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
@@ -36,6 +37,7 @@ public interface ChannelInterceptor {
* If this method returns {@code null} then the actual
* send invocation will not occur.
*/
@Nullable
Message<?> preSend(Message<?> message, MessageChannel channel);
/**

View File

@@ -16,6 +16,7 @@
package org.springframework.messaging.support;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
@@ -42,6 +43,7 @@ public interface ExecutorChannelInterceptor extends ChannelInterceptor {
* @param handler the target handler to handle the message
* @return the input message, or a new instance, or {@code null}
*/
@Nullable
Message<?> beforeHandle(Message<?> message, MessageChannel channel, MessageHandler handler);
/**

View File

@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.messaging.MessageHandler;
@@ -54,7 +55,7 @@ public class ExecutorSubscribableChannel extends AbstractSubscribableChannel {
* @param executor the executor used to send the message,
* or {@code null} to execute in the callers thread.
*/
public ExecutorSubscribableChannel(Executor executor) {
public ExecutorSubscribableChannel(@Nullable Executor executor) {
this.executor = executor;
}
@@ -151,6 +152,7 @@ public class ExecutorSubscribableChannel extends AbstractSubscribableChannel {
}
}
@Nullable
private Message<?> applyBeforeHandle(Message<?> message) {
for (ExecutorChannelInterceptor interceptor : executorInterceptors) {
message = interceptor.beforeHandle(message, ExecutorSubscribableChannel.this, this.messageHandler);

View File

@@ -18,6 +18,7 @@ package org.springframework.messaging.support;
import java.util.UUID;
import org.springframework.lang.Nullable;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.IdGenerator;
@@ -57,6 +58,7 @@ public class IdTimestampMessageHeaderInitializer implements MessageHeaderInitial
/**
* Return the configured {@code IdGenerator}, if any.
*/
@Nullable
public IdGenerator getIdGenerator() {
return this.idGenerator;
}

View File

@@ -18,6 +18,7 @@ package org.springframework.messaging.support;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
@@ -73,7 +74,7 @@ public final class MessageBuilder<T> {
* Set the value for the given header name. If the provided value is {@code null},
* the header will be removed.
*/
public MessageBuilder<T> setHeader(String headerName, Object headerValue) {
public MessageBuilder<T> setHeader(String headerName, @Nullable Object headerValue) {
this.headerAccessor.setHeader(headerName, headerValue);
return this;
}
@@ -187,7 +188,7 @@ public final class MessageBuilder<T> {
* @since 4.1
*/
@SuppressWarnings("unchecked")
public static <T> Message<T> createMessage(T payload, MessageHeaders messageHeaders) {
public static <T> Message<T> createMessage(@Nullable T payload, MessageHeaders messageHeaders) {
Assert.notNull(payload, "Payload must not be null");
Assert.notNull(messageHeaders, "MessageHeaders must not be null");
if (payload instanceof Throwable) {

View File

@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
@@ -143,7 +144,7 @@ public class MessageHeaderAccessor {
* A constructor accepting the headers of an existing message to copy.
* @param message a message to copy the headers from, or {@code null} if none
*/
public MessageHeaderAccessor(Message<?> message) {
public MessageHeaderAccessor(@Nullable Message<?> message) {
this.headers = new MutableMessageHeaders(message != null ? message.getHeaders() : null);
}
@@ -284,6 +285,7 @@ public class MessageHeaderAccessor {
* @param headerName the name of the header
* @return the associated value, or {@code null} if none found
*/
@Nullable
public Object getHeader(String headerName) {
return this.headers.get(headerName);
}
@@ -292,7 +294,7 @@ public class MessageHeaderAccessor {
* Set the value for the given header name.
* <p>If the provided value is {@code null}, the header will be removed.
*/
public void setHeader(String name, Object value) {
public void setHeader(String name, @Nullable Object value) {
if (isReadOnly(name)) {
throw new IllegalArgumentException("'" + name + "' header is read-only");
}
@@ -414,6 +416,7 @@ public class MessageHeaderAccessor {
// Specific header accessors
@Nullable
public UUID getId() {
Object value = getHeader(MessageHeaders.ID);
if (value == null) {
@@ -422,6 +425,7 @@ public class MessageHeaderAccessor {
return (value instanceof UUID ? (UUID) value : UUID.fromString(value.toString()));
}
@Nullable
public Long getTimestamp() {
Object value = getHeader(MessageHeaders.TIMESTAMP);
if (value == null) {
@@ -434,6 +438,7 @@ public class MessageHeaderAccessor {
setHeader(MessageHeaders.CONTENT_TYPE, contentType);
}
@Nullable
public MimeType getContentType() {
Object value = getHeader(MessageHeaders.CONTENT_TYPE);
if (value == null) {
@@ -561,6 +566,7 @@ public class MessageHeaderAccessor {
* @return an accessor instance of the specified type, or {@code null} if none
* @since 4.1
*/
@Nullable
public static <T extends MessageHeaderAccessor> T getAccessor(Message<?> message, Class<T> requiredType) {
return getAccessor(message.getHeaders(), requiredType);
}
@@ -573,6 +579,7 @@ public class MessageHeaderAccessor {
* @since 4.1
*/
@SuppressWarnings("unchecked")
@Nullable
public static <T extends MessageHeaderAccessor> T getAccessor(
MessageHeaders messageHeaders, Class<T> requiredType) {

View File

@@ -21,6 +21,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -62,7 +63,7 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
* A protected constructor to create new headers.
* @param nativeHeaders native headers to create the message with (may be {@code null})
*/
protected NativeMessageHeaderAccessor(Map<String, List<String>> nativeHeaders) {
protected NativeMessageHeaderAccessor(@Nullable Map<String, List<String>> nativeHeaders) {
if (!CollectionUtils.isEmpty(nativeHeaders)) {
setHeader(NATIVE_HEADERS, new LinkedMultiValueMap<>(nativeHeaders));
}
@@ -121,14 +122,16 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
/**
* @return all values for the specified native header or {@code null}.
*/
@Nullable
public List<String> getNativeHeader(String headerName) {
Map<String, List<String>> map = getNativeHeaders();
return (map != null ? map.get(headerName) : null);
}
/**
* @return the first value for the specified native header of {@code null}.
* @return the first value for the specified native header or {@code null}.
*/
@Nullable
public String getFirstNativeHeader(String headerName) {
Map<String, List<String>> map = getNativeHeaders();
if (map != null) {
@@ -198,6 +201,7 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
}
}
@Nullable
public List<String> removeNativeHeader(String name) {
Assert.state(isMutable(), "Already immutable");
Map<String, List<String>> nativeHeaders = getNativeHeaders();
@@ -208,6 +212,7 @@ public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
}
@SuppressWarnings("unchecked")
@Nullable
public static String getFirstNativeHeader(String headerName, Map<String, Object> headers) {
Map<String, List<String>> map = (Map<String, List<String>>) headers.get(NATIVE_HEADERS);
if (map != null) {

View File

@@ -4,4 +4,7 @@
* message headers, as well as various {@link org.springframework.messaging.MessageChannel}
* implementations and channel interceptor support.
*/
@NonNullApi
package org.springframework.messaging.support;
import org.springframework.lang.NonNullApi;

View File

@@ -16,6 +16,8 @@
package org.springframework.messaging.tcp;
import org.springframework.lang.Nullable;
/**
* A contract to determine the frequency of reconnect attempts after connection failure.
*
@@ -30,6 +32,7 @@ public interface ReconnectStrategy {
* @param attemptCount how many reconnect attempts have been made already
* @return the amount of time in milliseconds or {@code null} to stop
*/
@Nullable
Long getTimeToNextAttempt(int attemptCount);
}

View File

@@ -6,4 +6,7 @@
* as well as sending messages via
* {@link org.springframework.messaging.tcp.TcpConnection TcpConnection}.
*/
@NonNullApi
package org.springframework.messaging.tcp;
import org.springframework.lang.NonNullApi;

View File

@@ -1,4 +1,7 @@
/**
* Contains support for TCP messaging based on Reactor.
*/
@NonNullApi
package org.springframework.messaging.tcp.reactor;
import org.springframework.lang.NonNullApi;