diff --git a/spring-integration-core/src/main/java/org/springframework/integration/core/ErrorMessagePublisher.java b/spring-integration-core/src/main/java/org/springframework/integration/core/ErrorMessagePublisher.java index 8e92ba63fd1..4d0276acfe3 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/core/ErrorMessagePublisher.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/core/ErrorMessagePublisher.java @@ -70,7 +70,7 @@ public final void setErrorMessageStrategy(ErrorMessageStrategy errorMessageStrat this.errorMessageStrategy = errorMessageStrategy; } - public final void setChannel(MessageChannel channel) { + public final void setChannel(@Nullable MessageChannel channel) { this.channel = channel; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/MessageProcessorMessageSource.java b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/MessageProcessorMessageSource.java index 2fe0c3724b9..2bd6aed95ef 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/MessageProcessorMessageSource.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/MessageProcessorMessageSource.java @@ -19,6 +19,8 @@ import org.jspecify.annotations.Nullable; import org.springframework.integration.handler.MessageProcessor; +import org.springframework.integration.support.MutableMessageBuilder; +import org.springframework.messaging.Message; /** * The {@link org.springframework.integration.core.MessageSource} strategy implementation @@ -27,11 +29,15 @@ * * @author Artem Bilan * @author Gary Russell + * @author Jiandong Ma * * @since 5.0 */ public class MessageProcessorMessageSource extends AbstractMessageSource { + // provide a fake message since the contract of processMessage requires a NonNull Message. + static final Message FAKE_MESSAGE = MutableMessageBuilder.withPayload(new Object(), false).build(); + private final MessageProcessor messageProcessor; public MessageProcessorMessageSource(MessageProcessor messageProcessor) { @@ -45,7 +51,7 @@ public String getComponentType() { @Override protected @Nullable Object doReceive() { - return this.messageProcessor.processMessage(null); + return this.messageProcessor.processMessage(FAKE_MESSAGE); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java b/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java index 33b9fb9fad8..6172d6ff362 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java @@ -176,7 +176,7 @@ public boolean isRunning() { } @Override - public Object postProcess(Message message, Object result) { + public @Nullable Object postProcess(Message message, @Nullable Object result) { if (result == null) { MessageChannel channelToDiscard = getDiscardChannel(); if (channelToDiscard != null) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandler.java index a76e869956b..7e1ee107fd2 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandler.java @@ -55,7 +55,7 @@ public void setObservationConvention(@Nullable MessageReceiverObservationConvent this.observationConvention = observationConvention; } - @Override // NOSONAR + @Override public void handleMessage(Message message) { Assert.notNull(message, "Message must not be null"); if (isLoggingEnabled()) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageProducingHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageProducingHandler.java index 66aefb7f1fb..060aedd879f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageProducingHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageProducingHandler.java @@ -76,7 +76,7 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHandler implements MessageProducer, HeaderPropagationAware { - protected final MessagingTemplate messagingTemplate = new MessagingTemplate(); // NOSONAR final + protected final MessagingTemplate messagingTemplate = new MessagingTemplate(); private boolean async; @@ -88,7 +88,7 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan @Nullable private MessageChannel outputChannel; - private String[] notPropagatedHeaders; + private String @Nullable [] notPropagatedHeaders; private boolean selectiveHeaderPropagation; @@ -113,7 +113,7 @@ public void setOutputChannel(MessageChannel outputChannel) { @Override public void setOutputChannelName(String outputChannelName) { Assert.hasText(outputChannelName, "'outputChannelName' must not be empty"); - this.outputChannelName = outputChannelName; //NOSONAR (inconsistent sync) + this.outputChannelName = outputChannelName; } /** @@ -213,12 +213,10 @@ public void addNotPropagatedHeaders(String... headers) { @Override protected void onInit() { super.onInit(); - Assert.state(!(this.outputChannelName != null && this.outputChannel != null), //NOSONAR (inconsistent sync) + Assert.state(!(this.outputChannelName != null && this.outputChannel != null), "'outputChannelName' and 'outputChannel' are mutually exclusive."); BeanFactory beanFactory = getBeanFactory(); - if (beanFactory != null) { - this.messagingTemplate.setBeanFactory(beanFactory); - } + this.messagingTemplate.setBeanFactory(beanFactory); this.messagingTemplate.setDestinationResolver(getChannelResolver()); setAsyncIfCan(); if (!this.sendTimeoutSet) { @@ -244,9 +242,9 @@ public MessageChannel getOutputChannel() { return this.outputChannel; } - protected void sendOutputs(Object result, Message requestMessage) { - if (result instanceof Iterable && shouldSplitOutput((Iterable) result)) { - for (Object o : (Iterable) result) { + protected void sendOutputs(@Nullable Object result, Message requestMessage) { + if (result instanceof Iterable iterableResult && shouldSplitOutput(iterableResult)) { + for (Object o : iterableResult) { produceOutput(o, requestMessage); } } @@ -294,13 +292,12 @@ protected void produceOutput(Object replyArg, final Message requestMessage) { private Map obtainRoutingSlipHeader(MessageHeaders requestHeaders, Object reply) { Map routingSlipHeader = requestHeaders.get(IntegrationMessageHeaderAccessor.ROUTING_SLIP, Map.class); if (routingSlipHeader == null) { - if (reply instanceof Message) { - routingSlipHeader = ((Message) reply).getHeaders() + if (reply instanceof Message replyMessage) { + routingSlipHeader = replyMessage.getHeaders() .get(IntegrationMessageHeaderAccessor.ROUTING_SLIP, Map.class); } - else if (reply instanceof AbstractIntegrationMessageBuilder) { - routingSlipHeader = ((AbstractIntegrationMessageBuilder) reply) - .getHeader(IntegrationMessageHeaderAccessor.ROUTING_SLIP, Map.class); + else if (reply instanceof AbstractIntegrationMessageBuilder messageBuilder) { + routingSlipHeader = messageBuilder.getHeader(IntegrationMessageHeaderAccessor.ROUTING_SLIP, Map.class); } } return routingSlipHeader; @@ -310,12 +307,11 @@ else if (reply instanceof AbstractIntegrationMessageBuilder) { private Object obtainReplyChannel(MessageHeaders requestHeaders, Object reply) { Object replyChannel = requestHeaders.getReplyChannel(); if (replyChannel == null) { - if (reply instanceof Message) { - replyChannel = ((Message) reply).getHeaders().getReplyChannel(); + if (reply instanceof Message replyMessage) { + replyChannel = replyMessage.getHeaders().getReplyChannel(); } - else if (reply instanceof AbstractIntegrationMessageBuilder) { - replyChannel = ((AbstractIntegrationMessageBuilder) reply) - .getHeader(MessageHeaders.REPLY_CHANNEL, Object.class); + else if (reply instanceof AbstractIntegrationMessageBuilder messageBuilder) { + replyChannel = messageBuilder.getHeader(MessageHeaders.REPLY_CHANNEL, Object.class); } } return replyChannel; @@ -438,7 +434,7 @@ else if (reply instanceof AbstractIntegrationMessageBuilder) { return builder; } - private Object getOutputChannelFromRoutingSlip(Object reply, Message requestMessage, List routingSlip, + private @Nullable Object getOutputChannelFromRoutingSlip(Object reply, Message requestMessage, List routingSlip, AtomicInteger routingSlipIndex) { if (routingSlipIndex.get() >= routingSlip.size()) { @@ -446,7 +442,7 @@ private Object getOutputChannelFromRoutingSlip(Object reply, Message requestM } Object path = routingSlip.get(routingSlipIndex.get()); - Object routingSlipPathValue = null; + Object routingSlipPathValue; if (path instanceof String string) { routingSlipPathValue = getBeanFactory().getBean(string); @@ -558,7 +554,7 @@ protected boolean shouldCopyRequestHeaders() { protected void sendErrorMessage(Message requestMessage, Throwable ex) { Object errorChannel = resolveErrorChannel(requestMessage.getHeaders()); Throwable result = ex; - if (!(ex instanceof MessagingException)) { + if (!(result instanceof MessagingException)) { result = new MessageHandlingException(requestMessage, ex); } if (errorChannel == null) { @@ -578,7 +574,7 @@ protected void sendErrorMessage(Message requestMessage, Throwable ex) { } } - protected Object resolveErrorChannel(final MessageHeaders requestHeaders) { + protected @Nullable Object resolveErrorChannel(final MessageHeaders requestHeaders) { Object errorChannel = requestHeaders.getErrorChannel(); if (errorChannel == null) { try { @@ -594,12 +590,10 @@ protected Object resolveErrorChannel(final MessageHeaders requestHeaders) { protected void setupMessageProcessor(MessageProcessor processor) { if (processor instanceof AbstractMessageProcessor abstractMessageProcessor) { ConversionService conversionService = getConversionService(); - if (conversionService != null) { - abstractMessageProcessor.setConversionService(conversionService); - } + abstractMessageProcessor.setConversionService(conversionService); } BeanFactory beanFactory = getBeanFactory(); - if (processor instanceof BeanFactoryAware beanFactoryAware && beanFactory != null) { + if (processor instanceof BeanFactoryAware beanFactoryAware) { beanFactoryAware.setBeanFactory(beanFactory); } if (processor instanceof InitializingBean initializingBean) { @@ -628,7 +622,7 @@ private final class ReplyFutureCallback implements BiConsumer } @Override - public void accept(Object result, Throwable exception) { + public void accept(@Nullable Object result, @Nullable Throwable exception) { if (result != null) { Message replyMessage = null; try { @@ -637,7 +631,7 @@ public void accept(Object result, Throwable exception) { } catch (Exception ex) { Exception exceptionToLogAndSend = ex; - if (!(ex instanceof MessagingException)) { // NOSONAR + if (!(ex instanceof MessagingException)) { exceptionToLogAndSend = new MessageHandlingException(this.requestMessage, ex); if (replyMessage != null) { exceptionToLogAndSend = new MessagingException(replyMessage, exceptionToLogAndSend); @@ -648,7 +642,8 @@ public void accept(Object result, Throwable exception) { } } else if (exception != null) { - onFailure(exception instanceof CompletionException ? exception.getCause() : exception); + onFailure(exception instanceof CompletionException && exception.getCause() != null + ? exception.getCause() : exception); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractReplyProducingMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractReplyProducingMessageHandler.java index 9a659634775..ee66b3cfe04 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractReplyProducingMessageHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractReplyProducingMessageHandler.java @@ -31,7 +31,6 @@ import org.springframework.integration.handler.advice.HandleMessageAdvice; import org.springframework.messaging.Message; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; /** * Base class for MessageHandlers that are capable of producing replies. @@ -53,11 +52,12 @@ public abstract class AbstractReplyProducingMessageHandler extends AbstractMessa private final List adviceChain = new LinkedList<>(); - private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + @SuppressWarnings("NullAway.Init") + private ClassLoader beanClassLoader; private boolean requiresReply = false; - private volatile RequestHandler advisedRequestHandler; + private volatile @Nullable RequestHandler advisedRequestHandler; /** * Flag whether a reply is required. If true an incoming message MUST result in a reply message being sent. @@ -160,8 +160,8 @@ else if (!isAsync() && isLoggingEnabled()) { } } - @Nullable - protected Object doInvokeAdvisedRequestHandler(Message message) { + @SuppressWarnings("NullAway") // dataflow analysis limitation + protected @Nullable Object doInvokeAdvisedRequestHandler(Message message) { return this.advisedRequestHandler.handleRequestMessage(message); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/BeanNameMessageProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/BeanNameMessageProcessor.java index 0abe49fefd6..d48924a8ebc 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/BeanNameMessageProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/BeanNameMessageProcessor.java @@ -37,13 +37,15 @@ public class BeanNameMessageProcessor implements MessageProcessor, BeanFac private final String beanName; - private final String methodName; + private final @Nullable String methodName; + @SuppressWarnings("NullAway.Init") private MessageProcessor delegate; + @SuppressWarnings("NullAway.Init") private BeanFactory beanFactory; - public BeanNameMessageProcessor(String object, String methodName) { + public BeanNameMessageProcessor(String object, @Nullable String methodName) { this.beanName = object; this.methodName = methodName; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/ControlBusMessageProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/ControlBusMessageProcessor.java index f1d1958b584..7c9677c0b3f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/ControlBusMessageProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/ControlBusMessageProcessor.java @@ -18,6 +18,8 @@ import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.expression.Expression; import org.springframework.integration.IntegrationMessageHeaderAccessor; import org.springframework.integration.IntegrationPattern; @@ -41,6 +43,7 @@ public class ControlBusMessageProcessor extends AbstractMessageProcessor implements IntegrationPattern { + @SuppressWarnings("NullAway.Init") private ControlBusCommandRegistry controlBusCommandRegistry; public ControlBusMessageProcessor() { @@ -69,7 +72,7 @@ protected void onInit() { } @Override - public Object processMessage(Message message) { + public @Nullable Object processMessage(Message message) { String command = message.getPayload().toString(); @SuppressWarnings("unchecked") List arguments = diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/DelayHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/DelayHandler.java index 918bd3396da..19c5a7b6056 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/DelayHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/DelayHandler.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -34,6 +35,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import org.aopalliance.aop.Advice; +import org.jspecify.annotations.Nullable; import org.springframework.aop.framework.ProxyFactory; import org.springframework.context.ApplicationListener; @@ -116,27 +118,30 @@ public class DelayHandler extends AbstractReplyProducingMessageHandler implement private final ConcurrentMap deliveries = new ConcurrentHashMap<>(); + @SuppressWarnings("NullAway.Init") private String messageGroupId; private long defaultDelay; - private Expression delayExpression; + private @Nullable Expression delayExpression; private boolean ignoreExpressionFailures = true; + @SuppressWarnings("NullAway.Init") private MessageGroupStore messageStore; - private List delayedAdviceChain; + private @Nullable List delayedAdviceChain; private final AtomicBoolean initialized = new AtomicBoolean(); private MessageHandler releaseHandler = new ReleaseMessageHandler(); + @SuppressWarnings("NullAway.Init") private EvaluationContext evaluationContext; - private MessageChannel delayedMessageErrorChannel; + private @Nullable MessageChannel delayedMessageErrorChannel; - private String delayedMessageErrorChannelName; + private @Nullable String delayedMessageErrorChannelName; private int maxAttempts = DEFAULT_MAX_ATTEMPTS; @@ -309,12 +314,12 @@ public void setRetryDelay(long retryDelay) { this.retryDelay = retryDelay; } - private MessageChannel getErrorChannel() { + private @Nullable MessageChannel getErrorChannel() { if (this.delayedMessageErrorChannel != null) { return this.delayedMessageErrorChannel; } DestinationResolver channelResolver = getChannelResolver(); - if (this.delayedMessageErrorChannelName != null && channelResolver != null) { + if (this.delayedMessageErrorChannelName != null) { this.delayedMessageErrorChannel = channelResolver.resolveDestination(this.delayedMessageErrorChannelName); } return this.delayedMessageErrorChannel; @@ -362,7 +367,7 @@ protected boolean shouldCopyRequestHeaders() { /** * Check if 'requestMessage' wasn't delayed before ({@link #releaseMessageAfterDelay} - * and {@link DelayHandler.DelayedMessageWrapper}). Than determine 'delay' for + * and {@link DelayHandler.DelayedMessageWrapper}). Then determine 'delay' for * 'requestMessage' ({@link #determineDelayForMessage}) and if {@code delay > 0} * schedules 'releaseMessage' task after 'delay'. * @param requestMessage - the Message which may be delayed. @@ -371,7 +376,7 @@ protected boolean shouldCopyRequestHeaders() { * @see #releaseMessage */ @Override - protected Object handleRequestMessage(Message requestMessage) { + protected @Nullable Object handleRequestMessage(Message requestMessage) { boolean delayed = requestMessage.getPayload() instanceof DelayedMessageWrapper; if (!delayed) { @@ -397,11 +402,12 @@ private long determineDelayForMessage(Message message) { } } + @SuppressWarnings("NullAway") // dataflow analysis limitation private long determineDelayFromExpression(Message message) { long delay = this.defaultDelay; DelayedMessageWrapper delayedMessageWrapper = null; - if (message.getPayload() instanceof DelayedMessageWrapper) { - delayedMessageWrapper = (DelayedMessageWrapper) message.getPayload(); + if (message.getPayload() instanceof DelayedMessageWrapper payload) { + delayedMessageWrapper = payload; } Exception delayValueException = null; Object delayValue = null; @@ -414,12 +420,12 @@ private long determineDelayFromExpression(Message message) { catch (EvaluationException e) { delayValueException = e; } - if (delayValue instanceof Date) { + if (delayValue instanceof Date dealyValueDate) { long current = delayedMessageWrapper != null ? delayedMessageWrapper.getRequestDate() : System.currentTimeMillis(); - delay = ((Date) delayValue).getTime() - current; + delay = dealyValueDate.getTime() - current; } else if (delayValue != null) { try { @@ -496,6 +502,7 @@ private Runnable releaseTaskForMessage(Message delayedMessage) { } else { UUID messageId = delayedMessage.getHeaders().getId(); + Assert.state(messageId != null, "'messageId' must not be null"); return () -> { Message messageToRelease = getMessageById(messageId); if (messageToRelease != null) { @@ -505,7 +512,7 @@ private Runnable releaseTaskForMessage(Message delayedMessage) { } } - private Message getMessageById(UUID messageId) { + private @Nullable Message getMessageById(UUID messageId) { this.lock.lock(); try { Message theMessage = this.messageStore.getMessageFromGroup(this.messageGroupId, messageId); @@ -561,7 +568,8 @@ private void releaseMessage(Message message) { } private boolean rescheduleForRetry(Message message, String identity) { - if (this.deliveries.get(identity).incrementAndGet() >= this.maxAttempts) { + AtomicInteger deliveryAttempts = this.deliveries.get(identity); + if (Objects.requireNonNull(deliveryAttempts).incrementAndGet() >= this.maxAttempts) { this.logger.error(() -> "Discarding; maximum release attempts reached for: " + message); this.deliveries.remove(identity); return false; @@ -584,6 +592,7 @@ protected void rescheduleAt(Message message, Date startTime) { getTaskScheduler().schedule(releaseTask, startTime.toInstant()); } + @SuppressWarnings("NullAway") // critical path private void doReleaseMessage(Message message) { boolean removed; this.lock.lock(); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageHandler.java index ec1b03591c0..7eb06c0d5f6 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageHandler.java @@ -35,7 +35,7 @@ public class ExpressionEvaluatingMessageHandler extends AbstractMessageHandler { private final ExpressionEvaluatingMessageProcessor processor; - private String componentType; + private String componentType = "expression-evaluating-handler"; @SuppressWarnings("this-escape") public ExpressionEvaluatingMessageHandler(Expression expression) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessor.java index 9acc9aec938..481f6ad3a6c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/ExpressionEvaluatingMessageProcessor.java @@ -39,7 +39,7 @@ public class ExpressionEvaluatingMessageProcessor extends AbstractMessageProc private final Expression expression; - private final Class expectedType; + private final @Nullable Class expectedType; /** * Create an {@link ExpressionEvaluatingMessageProcessor} for the given expression. diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/LambdaMessageProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/LambdaMessageProcessor.java index 83b70a33076..e452b01ccc2 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/LambdaMessageProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/LambdaMessageProcessor.java @@ -61,11 +61,11 @@ public class LambdaMessageProcessor implements MessageProcessor, BeanFac private final Method method; - @Nullable - private final Class expectedType; + private final @Nullable Class expectedType; private final Class[] parameterTypes; + @SuppressWarnings("NullAway.Init") private MessageConverter messageConverter; /** @@ -114,8 +114,8 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException { } @Override - public Object processMessage(Message message) { - Object[] args = buildArgs(message); + public @Nullable Object processMessage(Message message) { + @Nullable Object[] args = buildArgs(message); try { Object result = invokeMethod(args); @@ -149,8 +149,8 @@ public Object processMessage(Message message) { } } - private Object[] buildArgs(Message message) { - Object[] args = new Object[this.parameterTypes.length]; + private @Nullable Object[] buildArgs(Message message) { + @Nullable Object[] args = new Object[this.parameterTypes.length]; for (int i = 0; i < this.parameterTypes.length; i++) { Class parameterType = this.parameterTypes[i]; if (Message.class.isAssignableFrom(parameterType)) { @@ -189,8 +189,9 @@ else if (Map.class.isAssignableFrom(parameterType)) { return args; } - @SuppressWarnings({"unchecked", "rawtypes"}) - private Object invokeMethod(Object[] args) throws InvocationTargetException, IllegalAccessException { + @SuppressWarnings({"unchecked", "rawtypes", "NullAway"}) + // allow null items passing into the underlying functional method + private @Nullable Object invokeMethod(@Nullable Object[] args) throws InvocationTargetException, IllegalAccessException { if (this.target instanceof Consumer consumer) { consumer.accept(args[0]); return null; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java index 9c6623de7a1..35ee488dc21 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java @@ -23,8 +23,6 @@ import java.util.function.Function; import java.util.function.Supplier; -import org.jspecify.annotations.Nullable; - import org.springframework.core.log.LogAccessor; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; @@ -189,19 +187,18 @@ protected void handleMessageInternal(Message message) { } } - @Nullable private String createLogMessage(Message message) { Object logMessage = this.expression.getValue(this.evaluationContext, message); - return logMessage instanceof Throwable - ? createLogMessage((Throwable) logMessage) + return logMessage instanceof Throwable throwableMessage + ? createLogMessage(throwableMessage) : Objects.toString(logMessage); } private static String createLogMessage(Throwable throwable) { StringWriter stringWriter = new StringWriter(); - if (throwable instanceof AggregateMessageDeliveryException) { + if (throwable instanceof AggregateMessageDeliveryException aggregateMessageDeliveryException) { stringWriter.append(throwable.getMessage()); - for (Exception exception : ((AggregateMessageDeliveryException) throwable).getAggregatedExceptions()) { + for (Exception exception : aggregateMessageDeliveryException.getAggregatedExceptions()) { printStackTrace(exception, stringWriter); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java index 444cdcb1a55..bdaddf29fce 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerChain.java @@ -76,6 +76,7 @@ public class MessageHandlerChain extends AbstractMessageProducingHandler private final ReentrantLock lifecycleLock = new ReentrantLock(); + @SuppressWarnings("NullAway.Init") private List handlers; private volatile boolean initialized; @@ -137,14 +138,14 @@ private void configureChain() { // If this 'handler' is a nested non-last <chain>, it is necessary // to 'force' re-init it for check its configuration in conjunction with current MessageHandlerChain. - if (handler instanceof MessageHandlerChain) { - ((MessageHandlerChain) handler).initialized = false; - ((MessageHandlerChain) handler).afterPropertiesSet(); + if (handler instanceof MessageHandlerChain messageHandlerChain) { + messageHandlerChain.initialized = false; + messageHandlerChain.afterPropertiesSet(); } } - else if (handler instanceof MessageProducer) { + else if (handler instanceof MessageProducer messageProducer) { MessageChannel replyChannel = new ReplyForwardingMessageChannel(); - ((MessageProducer) handler).setOutputChannel(replyChannel); + messageProducer.setOutputChannel(replyChannel); } else { Assert.isNull(getOutputChannel(), @@ -221,16 +222,16 @@ public final void stop(Runnable callback) { private void doStop() { for (MessageHandler handler : this.handlers) { - if (handler instanceof Lifecycle) { - ((Lifecycle) handler).stop(); + if (handler instanceof Lifecycle lifecycle) { + lifecycle.stop(); } } } private void doStart() { for (MessageHandler handler : this.handlers) { - if (handler instanceof Lifecycle) { - ((Lifecycle) handler).start(); + if (handler instanceof Lifecycle lifecycle) { + lifecycle.start(); } } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerSupport.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerSupport.java index 66a88707014..699a1e3abd4 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerSupport.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/MessageHandlerSupport.java @@ -20,6 +20,7 @@ import java.util.concurrent.ConcurrentHashMap; import io.micrometer.observation.ObservationRegistry; +import org.jspecify.annotations.Nullable; import org.springframework.core.Ordered; import org.springframework.integration.IntegrationPattern; @@ -62,17 +63,17 @@ public abstract class MessageHandlerSupport extends IntegrationObjectSupport private boolean loggingEnabled = true; - private MetricsCaptor metricsCaptor; + private @Nullable MetricsCaptor metricsCaptor; private ObservationRegistry observationRegistry = ObservationRegistry.NOOP; private int order = Ordered.LOWEST_PRECEDENCE; - private String managedName; + private @Nullable String managedName; - private String managedType; + private @Nullable String managedType; - private TimerFacade successTimer; + private @Nullable TimerFacade successTimer; @Override public boolean isLoggingEnabled() { @@ -90,7 +91,7 @@ public void registerMetricsCaptor(MetricsCaptor metricsCaptorToRegister) { this.metricsCaptor = metricsCaptorToRegister; } - protected MetricsCaptor getMetricsCaptor() { + protected @Nullable MetricsCaptor getMetricsCaptor() { return this.metricsCaptor; } @@ -150,10 +151,11 @@ protected TimerFacade sendTimer() { return this.successTimer; } + @SuppressWarnings("NullAway") // dataflow analysis limitation protected TimerFacade buildSendTimer(boolean success, String exception) { TimerFacade timer = this.metricsCaptor.timerBuilder(SEND_TIMER_NAME) .tag("type", "handler") - .tag("name", getComponentName() == null ? "unknown" : getComponentName()) + .tag("name", getComponentName()) .tag("result", success ? "success" : "failure") .tag("exception", exception) .description("Send processing time") @@ -166,7 +168,7 @@ public void setManagedName(String managedName) { this.managedName = managedName; } - public String getManagedName() { + public @Nullable String getManagedName() { return this.managedName; } @@ -174,7 +176,7 @@ public void setManagedType(String managedType) { this.managedType = managedType; } - public String getManagedType() { + public @Nullable String getManagedType() { return this.managedType; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageHandler.java index a95c229d104..38cc140da69 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageHandler.java @@ -36,7 +36,7 @@ public class MethodInvokingMessageHandler extends AbstractMessageHandler impleme private final MethodInvokingMessageProcessor processor; - private String componentType; + private String componentType = "method-invoking-handler"; public MethodInvokingMessageHandler(Object object, Method method) { Assert.isTrue(method.getReturnType().equals(void.class), diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageProcessor.java index e865686ecdc..cf24f38ae8d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/MethodInvokingMessageProcessor.java @@ -53,11 +53,11 @@ public MethodInvokingMessageProcessor(Object targetObject, Method method) { this.delegate = new MessagingMethodInvokerHelper(targetObject, method, false); } - public MethodInvokingMessageProcessor(Object targetObject, String methodName) { + public MethodInvokingMessageProcessor(Object targetObject, @Nullable String methodName) { this.delegate = new MessagingMethodInvokerHelper(targetObject, methodName, false); } - public MethodInvokingMessageProcessor(Object targetObject, String methodName, boolean canProcessMessageList) { + public MethodInvokingMessageProcessor(Object targetObject, @Nullable String methodName, boolean canProcessMessageList) { this.delegate = new MessagingMethodInvokerHelper(targetObject, methodName, canProcessMessageList); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/PostProcessingMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/PostProcessingMessageHandler.java index 2729e2b508b..fda9fc9f708 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/PostProcessingMessageHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/PostProcessingMessageHandler.java @@ -16,6 +16,8 @@ package org.springframework.integration.handler; +import org.jspecify.annotations.Nullable; + import org.springframework.messaging.Message; /** @@ -36,6 +38,6 @@ public interface PostProcessingMessageHandler { * @param message The message. * @return The post-processed result. */ - Object postProcess(Message message, Object result); + @Nullable Object postProcess(Message message, @Nullable Object result); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/ReplyProducingMessageHandlerWrapper.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/ReplyProducingMessageHandlerWrapper.java index 2e6a67b073b..26b7e6ed429 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/ReplyProducingMessageHandlerWrapper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/ReplyProducingMessageHandlerWrapper.java @@ -16,6 +16,8 @@ package org.springframework.integration.handler; +import org.jspecify.annotations.Nullable; + import org.springframework.context.Lifecycle; import org.springframework.integration.IntegrationPattern; import org.springframework.integration.IntegrationPatternType; @@ -49,35 +51,35 @@ public ReplyProducingMessageHandlerWrapper(MessageHandler target) { @Override public IntegrationPatternType getIntegrationPatternType() { - return (this.target instanceof IntegrationPattern) - ? ((IntegrationPattern) this.target).getIntegrationPatternType() + return (this.target instanceof IntegrationPattern integrationPattern) + ? integrationPattern.getIntegrationPatternType() : IntegrationPatternType.service_activator; } @Override - protected Object handleRequestMessage(Message requestMessage) { + protected @Nullable Object handleRequestMessage(Message requestMessage) { this.target.handleMessage(requestMessage); return null; } @Override public void start() { - if (this.target instanceof Lifecycle) { - ((Lifecycle) this.target).start(); + if (this.target instanceof Lifecycle lifecycle) { + lifecycle.start(); } } @Override public void stop() { - if (this.target instanceof Lifecycle) { - ((Lifecycle) this.target).stop(); + if (this.target instanceof Lifecycle lifecycle) { + lifecycle.stop(); } } @Override public boolean isRunning() { - return !(this.target instanceof Lifecycle) || ((Lifecycle) this.target).isRunning(); + return !(this.target instanceof Lifecycle lifecycle) || lifecycle.isRunning(); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java index 50f6d26afcd..1bfc5a2941b 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/ServiceActivatingHandler.java @@ -59,8 +59,8 @@ public String getComponentType() { @Override public IntegrationPatternType getIntegrationPatternType() { - return (this.processor instanceof IntegrationPattern) - ? ((IntegrationPattern) this.processor).getIntegrationPatternType() + return (this.processor instanceof IntegrationPattern integrationPattern) + ? integrationPattern.getIntegrationPatternType() : IntegrationPatternType.service_activator; } @@ -71,21 +71,21 @@ protected void doInit() { @Override public void start() { - if (this.processor instanceof Lifecycle) { - ((Lifecycle) this.processor).start(); + if (this.processor instanceof Lifecycle lifecycle) { + lifecycle.start(); } } @Override public void stop() { - if (this.processor instanceof Lifecycle) { - ((Lifecycle) this.processor).stop(); + if (this.processor instanceof Lifecycle lifecycle) { + lifecycle.stop(); } } @Override public boolean isRunning() { - return !(this.processor instanceof Lifecycle) || ((Lifecycle) this.processor).isRunning(); + return !(this.processor instanceof Lifecycle lifecycle) || lifecycle.isRunning(); } @Override @@ -97,7 +97,7 @@ protected Object handleRequestMessage(Message message) { @Override public String toString() { return "ServiceActivator for [" + this.processor + "]" - + (getComponentName() == null ? "" : " (" + getComponentName() + ")"); + + " (" + getComponentName() + ")"; } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractHandleMessageAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractHandleMessageAdvice.java index 85026e5be09..ff5d1db9eb3 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractHandleMessageAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractHandleMessageAdvice.java @@ -19,6 +19,7 @@ import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.springframework.integration.context.IntegrationObjectSupport; import org.springframework.messaging.Message; @@ -35,11 +36,12 @@ */ public abstract class AbstractHandleMessageAdvice extends IntegrationObjectSupport implements HandleMessageAdvice { + @SuppressWarnings("NullAway") // dataflow analysis limitation, invocationThis and message won't be null. @Override - public final Object invoke(MethodInvocation invocation) throws Throwable { // NOSONAR + public final @Nullable Object invoke(MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); Object invocationThis = invocation.getThis(); - Object[] arguments = invocation.getArguments(); + @Nullable Object[] arguments = invocation.getArguments(); boolean isMessageHandler = invocationThis instanceof MessageHandler; boolean isMessageMethod = method.getName().equals("handleMessage") && (arguments.length == 1 && arguments[0] instanceof Message); @@ -59,6 +61,6 @@ public final Object invoke(MethodInvocation invocation) throws Throwable { // NO return doInvoke(invocation, message); } - protected abstract Object doInvoke(MethodInvocation invocation, Message message) throws Throwable; // NOSONAR + protected abstract @Nullable Object doInvoke(MethodInvocation invocation, Message message) throws Throwable; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractRequestHandlerAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractRequestHandlerAdvice.java index 451380ec704..b54740df374 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractRequestHandlerAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/AbstractRequestHandlerAdvice.java @@ -20,6 +20,7 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.springframework.aop.ProxyMethodInvocation; import org.springframework.integration.context.IntegrationObjectSupport; @@ -42,11 +43,12 @@ public abstract class AbstractRequestHandlerAdvice extends IntegrationObjectSupport implements MethodInterceptor { + @SuppressWarnings("NullAway") // dataflow analysis limitation, invocationThis and message won't be null. @Override - public final Object invoke(final MethodInvocation invocation) throws Throwable { + public final @Nullable Object invoke(final MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); - Object[] arguments = invocation.getArguments(); + @Nullable Object[] arguments = invocation.getArguments(); boolean isMessageMethod = (method.getName().equals("handleRequestMessage") || method.getName().equals("handleMessage")) && (arguments.length == 1 && arguments[0] instanceof Message); @@ -62,15 +64,14 @@ public final Object invoke(final MethodInvocation invocation) throws Throwable { } return invocation.proceed(); } - else { - Message message = (Message) arguments[0]; - try { - return doInvoke(new CallbackImpl(invocation), invocationThis, message); - } - catch (Exception e) { - throw this.unwrapThrowableIfNecessary(e); - } + Message message = (Message) arguments[0]; + try { + return doInvoke(new CallbackImpl(invocation), invocationThis, message); + } + catch (Exception e) { + throw this.unwrapThrowableIfNecessary(e); } + } @Override @@ -88,7 +89,7 @@ public String getComponentType() { * @param message The message that will be sent to the handler. * @return the result after invoking the {@link MessageHandler}. */ - protected abstract Object doInvoke(ExecutionCallback callback, Object target, Message message); + protected abstract @Nullable Object doInvoke(ExecutionCallback callback, Object target, Message message); /** * Unwrap the cause of a {@link AbstractRequestHandlerAdvice.ThrowableHolderException}. @@ -111,8 +112,8 @@ protected Exception unwrapExceptionIfNecessary(Exception e) { */ protected Throwable unwrapThrowableIfNecessary(Exception e) { Throwable actualThrowable = e; - if (e instanceof ThrowableHolderException) { - actualThrowable = e.getCause(); + if (e instanceof ThrowableHolderException throwableHolderException) { + actualThrowable = throwableHolderException.getCause(); } return actualThrowable; } @@ -130,6 +131,7 @@ protected interface ExecutionCallback { * * @return The result of the execution. */ + @Nullable Object execute(); /** @@ -139,6 +141,7 @@ protected interface ExecutionCallback { * * @return The result of the execution. */ + @Nullable Object cloneAndExecute(); } @@ -152,17 +155,17 @@ private static final class CallbackImpl implements ExecutionCallback { } @Override - public Object execute() { + public @Nullable Object execute() { try { return this.invocation.proceed(); } - catch (Throwable e) { //NOSONAR - ok to catch; unwrapped and rethrown below + catch (Throwable e) { // ok to catch; unwrapped and rethrown below throw new ThrowableHolderException(e); } } @Override - public Object cloneAndExecute() { + public @Nullable Object cloneAndExecute() { try { /* * If we don't copy the invocation carefully it won't keep a reference to the other @@ -177,10 +180,14 @@ public Object cloneAndExecute() { " so please raise an issue if you see this exception"); } } - catch (Exception e) { //NOSONAR - catch necessary so we can wrap Errors - throw new MessagingException((Message) this.invocation.getArguments()[0], "Failed to handle", e); + catch (Exception e) { // catch necessary so we can wrap Errors + Message argument = (Message) this.invocation.getArguments()[0]; + // just in case, although argument should not be null. + throw argument == null + ? new MessagingException("Failed to handle", e) + : new MessagingException(argument, "Failed to handle", e); } - catch (Throwable e) { //NOSONAR - ok to catch; unwrapped and rethrown below + catch (Throwable e) { // ok to catch; unwrapped and rethrown below throw new ThrowableHolderException(e); } } @@ -194,6 +201,12 @@ protected static final class ThrowableHolderException extends RuntimeException { super(cause); } + @Override + public synchronized Throwable getCause() { + Throwable cause = super.getCause(); + return cause != null ? cause : this; + } + } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/CacheRequestHandlerAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/CacheRequestHandlerAdvice.java index 4e4553422a6..f10094aa2b4 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/CacheRequestHandlerAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/CacheRequestHandlerAdvice.java @@ -35,6 +35,7 @@ import org.springframework.cache.interceptor.CachePutOperation; import org.springframework.cache.interceptor.CacheResolver; import org.springframework.cache.interceptor.CacheableOperation; +import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.integration.expression.ExpressionUtils; @@ -64,6 +65,7 @@ public class CacheRequestHandlerAdvice extends AbstractRequestHandlerAdvice implements SmartInitializingSingleton { + @SuppressWarnings("NullAway.Init") private static final Method HANDLE_REQUEST_METHOD; static { @@ -77,19 +79,16 @@ public class CacheRequestHandlerAdvice extends AbstractRequestHandlerAdvice throw new IllegalStateException(ex); } finally { - if (requestHandlerClass != null) { - HANDLE_REQUEST_METHOD = - ReflectionUtils.findMethod(requestHandlerClass, "handleRequestMessage", Message.class); - } - else { - HANDLE_REQUEST_METHOD = null; - } + Assert.state(requestHandlerClass != null, "'requestHandlerClass' must not be null"); + Method handleRequestMethod = ReflectionUtils.findMethod(requestHandlerClass, "handleRequestMessage", Message.class); + Assert.state(handleRequestMethod != null, "'handleRequestMessage' method must not be null"); + HANDLE_REQUEST_METHOD = handleRequestMethod; } } private final IntegrationCacheAspect delegate = new IntegrationCacheAspect(); - private final String[] cacheNames; + private final String @Nullable [] cacheNames; private final List cacheOperations = new ArrayList<>(); @@ -102,7 +101,7 @@ public class CacheRequestHandlerAdvice extends AbstractRequestHandlerAdvice * @param cacheNamesArg the name of caches to use in the advice. * @see #setCacheOperations */ - public CacheRequestHandlerAdvice(String... cacheNamesArg) { + public CacheRequestHandlerAdvice(String @Nullable ... cacheNamesArg) { this.cacheNames = cacheNamesArg != null ? Arrays.copyOf(cacheNamesArg, cacheNamesArg.length) : null; } @@ -244,8 +243,12 @@ else if (operation instanceof CacheEvictOperation cacheEvictOperation) { BeanFactory beanFactory = getBeanFactory(); this.delegate.setBeanFactory(beanFactory); EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(beanFactory); - this.delegate.setKeyGenerator((target, method, params) -> - this.keyExpression.getValue(evaluationContext, params[0])); // NOSONAR + KeyGenerator keyGenerator = (target, method, params) -> { + Object key = this.keyExpression.getValue(evaluationContext, params[0]); + Assert.state(key != null, "the cache key evaluated from the KeyExpression must not be null"); + return key; + }; + this.delegate.setKeyGenerator(keyGenerator); this.delegate.setCacheOperationSources((method, targetClass) -> cacheOperationsToUse); this.delegate.afterPropertiesSet(); @@ -276,7 +279,7 @@ private static class IntegrationCacheAspect extends CacheAspectSupport { @Nullable Object invoke(CacheOperationInvoker invoker, Object target, Message message) { - return super.execute(invoker, target, HANDLE_REQUEST_METHOD, new Object[] {message}); // NOSONAR + return super.execute(invoker, target, HANDLE_REQUEST_METHOD, new Object[] {message}); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ContextHolderRequestHandlerAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ContextHolderRequestHandlerAdvice.java index 55ff5d829ac..c35bcd9efb6 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ContextHolderRequestHandlerAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ContextHolderRequestHandlerAdvice.java @@ -19,6 +19,8 @@ import java.util.function.Consumer; import java.util.function.Function; +import org.jspecify.annotations.Nullable; + import org.springframework.messaging.Message; import org.springframework.util.Assert; @@ -58,7 +60,7 @@ public ContextHolderRequestHandlerAdvice(Function, Object> valueProvi } @Override - protected Object doInvoke(ExecutionCallback callback, Object target, Message message) { + protected @Nullable Object doInvoke(ExecutionCallback callback, Object target, Message message) { Object value = this.valueProvider.apply(message); logger.trace(() -> "Setting context value to: " + value + " from message: " + message); try { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ErrorMessageSendingRecoverer.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ErrorMessageSendingRecoverer.java index 154fee1cf90..fde444b4b02 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ErrorMessageSendingRecoverer.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ErrorMessageSendingRecoverer.java @@ -18,6 +18,8 @@ import java.io.Serial; +import org.jspecify.annotations.Nullable; + import org.springframework.core.AttributeAccessor; import org.springframework.integration.core.ErrorMessagePublisher; import org.springframework.integration.core.RecoveryCallback; @@ -40,7 +42,7 @@ * @since 2.2 * */ -public class ErrorMessageSendingRecoverer extends ErrorMessagePublisher implements RecoveryCallback { +public class ErrorMessageSendingRecoverer extends ErrorMessagePublisher implements RecoveryCallback<@Nullable Object> { /** * Construct instance with the default {@code errorChannel} @@ -57,8 +59,9 @@ public ErrorMessageSendingRecoverer() { * The {@link DefaultErrorMessageStrategy} is used for building an error message to publish. * @param channel the message channel to publish error messages on recovery action. */ - public ErrorMessageSendingRecoverer(MessageChannel channel) { - this(channel, null); + @SuppressWarnings("this-escape") + public ErrorMessageSendingRecoverer(@Nullable MessageChannel channel) { + setChannel(channel); } /** @@ -81,7 +84,7 @@ public ErrorMessageSendingRecoverer(MessageChannel channel, ErrorMessageStrategy } @Override - public Object recover(AttributeAccessor context, Throwable cause) { + public @Nullable Object recover(AttributeAccessor context, Throwable cause) { publish(cause, context); return null; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ExpressionEvaluatingRequestHandlerAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ExpressionEvaluatingRequestHandlerAdvice.java index 1fd54e5b047..39adc2f12f7 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ExpressionEvaluatingRequestHandlerAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ExpressionEvaluatingRequestHandlerAdvice.java @@ -57,17 +57,17 @@ public class ExpressionEvaluatingRequestHandlerAdvice extends AbstractRequestHan private final MessagingTemplate messagingTemplate = new MessagingTemplate(); - private Expression onSuccessExpression; + private @Nullable Expression onSuccessExpression; - private MessageChannel successChannel; + private @Nullable MessageChannel successChannel; - private String successChannelName; + private @Nullable String successChannelName; - private Expression onFailureExpression; + private @Nullable Expression onFailureExpression; - private MessageChannel failureChannel; + private @Nullable MessageChannel failureChannel; - private String failureChannelName; + private @Nullable String failureChannelName; private boolean trapException = false; @@ -75,7 +75,7 @@ public class ExpressionEvaluatingRequestHandlerAdvice extends AbstractRequestHan private boolean propagateOnSuccessEvaluationFailures; - private EvaluationContext evaluationContext; + private @Nullable EvaluationContext evaluationContext; /** * Set the expression to evaluate against the message after a successful handler invocation. @@ -191,9 +191,7 @@ public void setPropagateEvaluationFailures(boolean propagateOnSuccessEvaluationF protected void onInit() { super.onInit(); BeanFactory beanFactory = getBeanFactory(); - if (beanFactory != null) { - this.messagingTemplate.setBeanFactory(beanFactory); - } + this.messagingTemplate.setBeanFactory(beanFactory); if (this.onSuccessExpression == null && (this.successChannel != null || StringUtils.hasText(this.successChannelName))) { @@ -209,7 +207,7 @@ protected void onInit() { } @Override - protected Object doInvoke(ExecutionCallback callback, Object target, Message message) { + protected @Nullable Object doInvoke(ExecutionCallback callback, Object target, Message message) { try { Object result = callback.execute(); if (this.onSuccessExpression != null) { @@ -237,6 +235,7 @@ protected Object doInvoke(ExecutionCallback callback, Object target, Message } } + @SuppressWarnings("NullAway") // dataflow analysis limitation, onSuccessExpression won't be null private void evaluateSuccessExpression(Message message) { Object evalResult; try { @@ -246,7 +245,7 @@ private void evaluateSuccessExpression(Message message) { evalResult = e; } DestinationResolver channelResolver = getChannelResolver(); - if (this.successChannel == null && this.successChannelName != null && channelResolver != null) { + if (this.successChannel == null && this.successChannelName != null) { this.successChannel = channelResolver.resolveDestination(this.successChannelName); } if (evalResult != null && this.successChannel != null) { @@ -258,7 +257,8 @@ private void evaluateSuccessExpression(Message message) { } } - private Object evaluateFailureExpression(Message message, Exception exception) { + @SuppressWarnings("NullAway") // dataflow analysis limitation, onFailureExpression won't be null + private @Nullable Object evaluateFailureExpression(Message message, Exception exception) { Object evalResult; try { evalResult = this.onFailureExpression.getValue(prepareEvaluationContextToUse(exception), message); @@ -268,7 +268,7 @@ private Object evaluateFailureExpression(Message message, Exception exception logger.error("Failure expression evaluation failed for " + message + ": " + e.getMessage()); } DestinationResolver channelResolver = getChannelResolver(); - if (this.failureChannel == null && this.failureChannelName != null && channelResolver != null) { + if (this.failureChannel == null && this.failureChannelName != null) { this.failureChannel = channelResolver.resolveDestination(this.failureChannelName); } if (evalResult != null && this.failureChannel != null) { @@ -291,7 +291,7 @@ protected StandardEvaluationContext createEvaluationContext() { * @param exception the {@link Exception} to use in the context. * @return The context. */ - private EvaluationContext prepareEvaluationContextToUse(Exception exception) { + private EvaluationContext prepareEvaluationContextToUse(@Nullable Exception exception) { EvaluationContext evaluationContextToUse; if (exception != null) { evaluationContextToUse = createEvaluationContext(); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/HandleMessageAdviceAdapter.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/HandleMessageAdviceAdapter.java index 996a1ae8adf..4145747e6ab 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/HandleMessageAdviceAdapter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/HandleMessageAdviceAdapter.java @@ -18,6 +18,7 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; @@ -43,7 +44,7 @@ public HandleMessageAdviceAdapter(MethodInterceptor delegate) { } @Override - public Object invoke(MethodInvocation invocation) throws Throwable { + public @Nullable Object invoke(MethodInvocation invocation) throws Throwable { return this.delegate.invoke(invocation); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/IdempotentReceiverInterceptor.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/IdempotentReceiverInterceptor.java index 79036282eec..0117f52c51a 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/IdempotentReceiverInterceptor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/IdempotentReceiverInterceptor.java @@ -17,6 +17,7 @@ package org.springframework.integration.handler.advice; import org.aopalliance.intercept.MethodInvocation; +import org.jspecify.annotations.Nullable; import org.springframework.integration.IntegrationMessageHeaderAccessor; import org.springframework.integration.MessageRejectedException; @@ -58,9 +59,9 @@ public class IdempotentReceiverInterceptor extends AbstractHandleMessageAdvice { private final MessageSelector messageSelector; - private MessageChannel discardChannel; + private @Nullable MessageChannel discardChannel; - private String discardChannelName; + private @Nullable String discardChannelName; private boolean throwExceptionOnRejection; @@ -141,7 +142,7 @@ public String getComponentType() { } @Override - protected Object doInvoke(MethodInvocation invocation, Message message) throws Throwable { + protected @Nullable Object doInvoke(MethodInvocation invocation, Message message) throws Throwable { boolean accept = this.messageSelector.accept(message); if (!accept) { boolean discarded = false; @@ -169,7 +170,7 @@ protected Object doInvoke(MethodInvocation invocation, Message message) throw return invocation.proceed(); } - private MessageChannel obtainDiscardChannel() { + private @Nullable MessageChannel obtainDiscardChannel() { if (this.discardChannel == null && this.discardChannelName != null) { this.discardChannel = getChannelResolver().resolveDestination(this.discardChannelName); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/LockRequestHandlerAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/LockRequestHandlerAdvice.java index ceb5627377a..bd2f88737f6 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/LockRequestHandlerAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/LockRequestHandlerAdvice.java @@ -59,6 +59,7 @@ public class LockRequestHandlerAdvice extends AbstractRequestHandlerAdvice { @Nullable private Expression waitLockDurationExpression; + @SuppressWarnings("NullAway.Init") private EvaluationContext evaluationContext; /** @@ -151,8 +152,9 @@ protected void onInit() { this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory()); } + @SuppressWarnings("NullAway") // CheckedCallable.call() is nullable @Override - protected Object doInvoke(ExecutionCallback callback, Object target, Message message) { + protected @Nullable Object doInvoke(ExecutionCallback callback, Object target, Message message) { Object lockKey = this.lockKeyExpression.getValue(this.evaluationContext, message); if (lockKey != null) { Duration waitLockDuration = getWaitLockDuration(message); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RateLimiterRequestHandlerAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RateLimiterRequestHandlerAdvice.java index e5c20842f30..c2190c81612 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RateLimiterRequestHandlerAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RateLimiterRequestHandlerAdvice.java @@ -22,6 +22,7 @@ import io.github.resilience4j.ratelimiter.RateLimiter; import io.github.resilience4j.ratelimiter.RateLimiterConfig; import io.github.resilience4j.ratelimiter.RequestNotPermitted; +import org.jspecify.annotations.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessagingException; @@ -126,7 +127,7 @@ public RateLimiter getRateLimiter() { } @Override - protected Object doInvoke(ExecutionCallback callback, Object target, Message message) { + protected @Nullable Object doInvoke(ExecutionCallback callback, Object target, Message message) { try { return RateLimiter.decorateSupplier(this.rateLimiter, callback::execute).get(); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ReactiveRequestHandlerAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ReactiveRequestHandlerAdvice.java index df95d14a72e..5abc0e73af0 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ReactiveRequestHandlerAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/ReactiveRequestHandlerAdvice.java @@ -23,6 +23,7 @@ import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; @@ -58,13 +59,14 @@ public ReactiveRequestHandlerAdvice(BiFunction, Mono, Publisher this.replyCustomizer = replyCustomizer; } + @SuppressWarnings("NullAway") // dataflow analysis limitation, replyMono won't be null. @Override - public final Object invoke(MethodInvocation invocation) throws Throwable { + public final @Nullable Object invoke(MethodInvocation invocation) throws Throwable { Object result = invocation.proceed(); Method method = invocation.getMethod(); Object invocationThis = invocation.getThis(); - Object[] arguments = invocation.getArguments(); + @Nullable Object[] arguments = invocation.getArguments(); boolean isReactiveMethod = method.getName().equals("handleRequestMessage") && (arguments.length == 1 && arguments[0] instanceof Message) && diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerCircuitBreakerAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerCircuitBreakerAdvice.java index 747c78c93d9..ac0c411663d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerCircuitBreakerAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerCircuitBreakerAdvice.java @@ -20,6 +20,8 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; +import org.jspecify.annotations.Nullable; + import org.springframework.messaging.Message; import org.springframework.messaging.MessagingException; @@ -62,7 +64,7 @@ public void setHalfOpenAfter(long halfOpenAfter) { } @Override - protected Object doInvoke(ExecutionCallback callback, Object target, Message message) { + protected @Nullable Object doInvoke(ExecutionCallback callback, Object target, Message message) { AdvisedMetadata metadata = this.metadataMap.get(target); if (metadata == null) { this.metadataMap.putIfAbsent(target, new AdvisedMetadata()); @@ -83,8 +85,8 @@ protected Object doInvoke(ExecutionCallback callback, Object target, Message catch (Exception e) { metadata.getFailures().incrementAndGet(); metadata.setLastFailure(System.currentTimeMillis()); - if (e instanceof ThrowableHolderException) { // NOSONAR - throw (ThrowableHolderException) e; + if (e instanceof ThrowableHolderException ex) { + throw ex; } else { throw new ThrowableHolderException(e); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerRetryAdvice.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerRetryAdvice.java index 94a94dd1713..a8f7060b2a9 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerRetryAdvice.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RequestHandlerRetryAdvice.java @@ -16,6 +16,8 @@ package org.springframework.integration.handler.advice; +import org.jspecify.annotations.Nullable; + import org.springframework.integration.core.RecoveryCallback; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; import org.springframework.integration.support.ErrorMessageUtils; @@ -47,7 +49,7 @@ public class RequestHandlerRetryAdvice extends AbstractRequestHandlerAdvice { private RetryTemplate retryTemplate = new RetryTemplate(); - private org.springframework.retry.RecoveryCallback recoveryCallback; + private org.springframework.retry.@Nullable RecoveryCallback recoveryCallback; // Stateless unless a state generator is provided private RetryStateGenerator retryStateGenerator = message -> null; @@ -62,6 +64,7 @@ public void setRetryTemplate(RetryTemplate retryTemplate) { this.retryTemplate = retryTemplate; } + @SuppressWarnings("NullAway") // need rework on retry public void setRecoveryCallback(RecoveryCallback recoveryCallback) { this.recoveryCallback = (context) -> recoveryCallback.recover(context, context.getLastThrowable()); @@ -119,7 +122,7 @@ private record IntegrationRetryCallback(Message messageToTry, ExecutionCallba implements RetryCallback { @Override - public Object doWithRetry(RetryContext context) { + public @Nullable Object doWithRetry(RetryContext context) { return this.callback.cloneAndExecute(); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RetryStateGenerator.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RetryStateGenerator.java index eb2acb6fb1d..d3b380dd095 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RetryStateGenerator.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/RetryStateGenerator.java @@ -16,6 +16,8 @@ package org.springframework.integration.handler.advice; +import org.jspecify.annotations.Nullable; + import org.springframework.messaging.Message; import org.springframework.retry.RetryState; @@ -29,6 +31,7 @@ @FunctionalInterface public interface RetryStateGenerator { + @Nullable RetryState determineRetryState(Message message); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/SpelExpressionRetryStateGenerator.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/SpelExpressionRetryStateGenerator.java index 11b3628636f..2212b2c491c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/SpelExpressionRetryStateGenerator.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/SpelExpressionRetryStateGenerator.java @@ -16,6 +16,8 @@ package org.springframework.integration.handler.advice; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -41,15 +43,15 @@ public class SpelExpressionRetryStateGenerator implements RetryStateGenerator, B private final Expression keyExpression; - private final Expression forceRefreshExpression; + private final @Nullable Expression forceRefreshExpression; - private volatile Classifier classifier; + private volatile @Nullable Classifier classifier; public SpelExpressionRetryStateGenerator(String keyExpression) { this(keyExpression, null); } - public SpelExpressionRetryStateGenerator(String keyExpression, String forceRefreshExpression) { + public SpelExpressionRetryStateGenerator(String keyExpression, @Nullable String forceRefreshExpression) { Assert.notNull(keyExpression, "keyExpression must not be null"); this.keyExpression = new SpelExpressionParser().parseExpression(keyExpression); this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(); @@ -76,7 +78,7 @@ public RetryState determineRetryState(Message message) { ? Boolean.FALSE : this.forceRefreshExpression.getValue(this.evaluationContext, message, Boolean.class); return new DefaultRetryState(this.keyExpression.getValue(this.evaluationContext, message), - forceRefresh == null ? false : forceRefresh, + forceRefresh != null && forceRefresh, this.classifier); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/package-info.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/package-info.java index 01236b5247d..d3e104d1053 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/package-info.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/advice/package-info.java @@ -3,4 +3,5 @@ * {@link org.springframework.messaging.MessageHandler}s with * cross-cutting concerns. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.handler.advice; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/package-info.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/package-info.java index 0b725c19d70..9824fb49dfc 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/package-info.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/package-info.java @@ -1,4 +1,5 @@ /** * Provides classes implementing various types of message handler. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.handler; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/CollectionArgumentResolver.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/CollectionArgumentResolver.java index 942a84288ce..994a41ee17c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/CollectionArgumentResolver.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/CollectionArgumentResolver.java @@ -22,6 +22,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.convert.TypeDescriptor; import org.springframework.integration.util.AbstractExpressionEvaluator; @@ -66,7 +68,7 @@ public boolean supportsParameter(MethodParameter parameter) { @Override @SuppressWarnings("unchecked") - public Object resolveArgument(MethodParameter parameter, Message message) { + public @Nullable Object resolveArgument(MethodParameter parameter, Message message) { Object value = message.getPayload(); if (this.canProcessMessageList) { @@ -86,8 +88,8 @@ public Object resolveArgument(MethodParameter parameter, Message message) { } if (Iterator.class.isAssignableFrom(parameter.getParameterType())) { - if (value instanceof Iterable) { - return ((Iterable) value).iterator(); + if (value instanceof Iterable iterablePayload) { + return iterablePayload.iterator(); } else { return Collections.singleton(value).iterator(); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/IntegrationInvocableHandlerMethod.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/IntegrationInvocableHandlerMethod.java index ecbc18b240a..4894c555f27 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/IntegrationInvocableHandlerMethod.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/IntegrationInvocableHandlerMethod.java @@ -18,6 +18,8 @@ import java.lang.reflect.Method; +import org.jspecify.annotations.Nullable; + import org.springframework.core.CoroutinesUtils; import org.springframework.core.KotlinDetector; import org.springframework.messaging.handler.invocation.InvocableHandlerMethod; @@ -36,7 +38,7 @@ public IntegrationInvocableHandlerMethod(Object bean, Method method) { } @Override - protected Object doInvoke(Object... args) throws Exception { + protected @Nullable Object doInvoke(@Nullable Object... args) throws Exception { Method method = getBridgedMethod(); if (KotlinDetector.isSuspendingFunction(method)) { return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/IntegrationMessageHandlerMethodFactory.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/IntegrationMessageHandlerMethodFactory.java index 473c9bd75ae..ba47db33fe3 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/IntegrationMessageHandlerMethodFactory.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/IntegrationMessageHandlerMethodFactory.java @@ -46,8 +46,10 @@ public class IntegrationMessageHandlerMethodFactory extends DefaultMessageHandle private final boolean listCapable; + @SuppressWarnings("NullAway.Init") private MessageConverter messageConverter; + @SuppressWarnings("NullAway.Init") private BeanFactory beanFactory; public IntegrationMessageHandlerMethodFactory() { @@ -104,12 +106,12 @@ private List buildArgumentResolvers(boolean listC } for (HandlerMethodArgumentResolver resolver : resolvers) { - if (resolver instanceof BeanFactoryAware) { - ((BeanFactoryAware) resolver).setBeanFactory(this.beanFactory); + if (resolver instanceof BeanFactoryAware beanFactoryAware) { + beanFactoryAware.setBeanFactory(this.beanFactory); } - if (resolver instanceof InitializingBean) { + if (resolver instanceof InitializingBean initializingBean) { try { - ((InitializingBean) resolver).afterPropertiesSet(); + initializingBean.afterPropertiesSet(); } catch (Exception ex) { throw new BeanInitializationException("Cannot initialize 'HandlerMethodArgumentResolver'", ex); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MapArgumentResolver.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MapArgumentResolver.java index 5418c22fa48..bb714456798 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MapArgumentResolver.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MapArgumentResolver.java @@ -19,6 +19,8 @@ import java.util.Map; import java.util.Properties; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.convert.TypeDescriptor; import org.springframework.integration.util.AbstractExpressionEvaluator; @@ -58,7 +60,7 @@ public boolean supportsParameter(MethodParameter parameter) { @Override @SuppressWarnings("unchecked") - public Object resolveArgument(MethodParameter parameter, Message message) { + public @Nullable Object resolveArgument(MethodParameter parameter, Message message) { Object payload = message.getPayload(); if (Properties.class.isAssignableFrom(parameter.getParameterType())) { Map map = message.getHeaders(); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java index 53802e64643..97d65df033d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java @@ -169,43 +169,45 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im private final Object targetObject; - private final JsonObjectMapper jsonObjectMapper; + private final @Nullable JsonObjectMapper jsonObjectMapper; - private final Map, HandlerMethod> handlerMethods; + private final @Nullable Map, HandlerMethod> handlerMethods; - private final Map, HandlerMethod> handlerMessageMethods; + private final @Nullable Map, HandlerMethod> handlerMessageMethods; private final List, HandlerMethod>> handlerMethodsList = new LinkedList<>(); - private final TypeDescriptor expectedType; + private final @Nullable TypeDescriptor expectedType; private final boolean canProcessMessageList; - private final String methodName; + private final @Nullable String methodName; - private final Method method; + private final @Nullable Method method; - private final Class annotationType; + private final @Nullable Class annotationType; - private final HandlerMethod handlerMethod; + private final @Nullable HandlerMethod handlerMethod; private final String displayString; private final boolean requiresReply; - private HandlerMethod defaultHandlerMethod; + private @Nullable HandlerMethod defaultHandlerMethod; private BeanExpressionResolver resolver = new StandardBeanExpressionResolver(); + @SuppressWarnings("NullAway.Init") private BeanExpressionContext expressionContext; private boolean useSpelInvoker; + @SuppressWarnings("NullAway.Init") private volatile MessageHandlerMethodFactory messageHandlerMethodFactory; private volatile boolean initialized; - public MessagingMethodInvokerHelper(Object targetObject, Method method, Class expectedType, + public MessagingMethodInvokerHelper(Object targetObject, Method method, @Nullable Class expectedType, boolean canProcessMessageList) { this(targetObject, null, method, expectedType, canProcessMessageList); @@ -215,13 +217,13 @@ public MessagingMethodInvokerHelper(Object targetObject, Method method, boolean this(targetObject, method, null, canProcessMessageList); } - public MessagingMethodInvokerHelper(Object targetObject, String methodName, Class expectedType, + public MessagingMethodInvokerHelper(Object targetObject, @Nullable String methodName, @Nullable Class expectedType, boolean canProcessMessageList) { this(targetObject, null, methodName, expectedType, canProcessMessageList); } - public MessagingMethodInvokerHelper(Object targetObject, String methodName, boolean canProcessMessageList) { + public MessagingMethodInvokerHelper(Object targetObject, @Nullable String methodName, boolean canProcessMessageList) { this(targetObject, methodName, null, canProcessMessageList); } @@ -232,13 +234,13 @@ public MessagingMethodInvokerHelper(Object targetObject, Class annotationType, - Class expectedType, boolean canProcessMessageList) { + @Nullable Class expectedType, boolean canProcessMessageList) { this(targetObject, annotationType, (String) null, expectedType, canProcessMessageList); } - private MessagingMethodInvokerHelper(Object targetObject, Class annotationType, - Method method, Class expectedType, boolean canProcessMessageList) { + private MessagingMethodInvokerHelper(Object targetObject, @Nullable Class annotationType, + Method method, @Nullable Class expectedType, boolean canProcessMessageList) { this.annotationType = annotationType; this.canProcessMessageList = canProcessMessageList; @@ -266,8 +268,8 @@ private MessagingMethodInvokerHelper(Object targetObject, Class annotationType, - String methodName, Class expectedType, boolean canProcessMessageList) { + private MessagingMethodInvokerHelper(Object targetObject, @Nullable Class annotationType, + @Nullable String methodName, @Nullable Class expectedType, boolean canProcessMessageList) { Assert.notNull(targetObject, "targetObject must not be null"); this.annotationType = annotationType; @@ -300,6 +302,8 @@ else if (targetObject instanceof Consumer) { Map, HandlerMethod>> handlerMethodsForTarget = findHandlerMethodsForTarget(); Map, HandlerMethod> methods = handlerMethodsForTarget.get(CANDIDATE_METHODS); Map, HandlerMethod> messageMethods = handlerMethodsForTarget.get(CANDIDATE_MESSAGE_METHODS); + Assert.state(methods != null, "candidate methods must not be null"); + Assert.state(messageMethods != null, "candidate messageMethods must not be null"); if ((methods.size() == 1 && messageMethods.isEmpty()) || (messageMethods.size() == 1 && methods.isEmpty())) { if (methods.size() == 1) { @@ -323,7 +327,7 @@ else if (targetObject instanceof Consumer) { this.jsonObjectMapper = configureJsonObjectMapperIfAny(); } - private JsonObjectMapper configureJsonObjectMapperIfAny() { + private @Nullable JsonObjectMapper configureJsonObjectMapperIfAny() { try { return JsonObjectMapperProvider.newInstance(); } @@ -362,7 +366,7 @@ public Object process(Message message) { } @Nullable - public Object process(Collection> messages, Map headers) { + public Object process(Collection> messages, @Nullable Map headers) { ParametersWrapper parameters = new ParametersWrapper(messages, headers); return processInternal(parameters); } @@ -406,12 +410,12 @@ private InvocableHandlerMethod createInvocableHandlerMethod(Method method) { return this.messageHandlerMethodFactory.createInvocableHandlerMethod(this.targetObject, method); } - private String buildDisplayString(Object targetObject, Object targetMethod) { + private String buildDisplayString(Object targetObject, @Nullable Object targetMethod) { StringBuilder sb = new StringBuilder(targetObject.getClass().getName()) .append('.'); - if (targetMethod instanceof Method) { - sb.append(((Method) targetMethod).getName()); + if (targetMethod instanceof Method target) { + sb.append(target.getName()); } else if (targetMethod instanceof String) { sb.append(targetMethod); @@ -555,11 +559,12 @@ private void initializeHandler(HandlerMethod candidate) { parser = EXPRESSION_PARSER_DEFAULT; } else { - String compilerMode = resolveExpression(candidate.useSpelInvoker.compilerMode()).toUpperCase(); + String compilerMode = resolveExpression(candidate.useSpelInvoker.compilerMode()); parser = !StringUtils.hasText(compilerMode) ? EXPRESSION_PARSER_DEFAULT - : SPEL_COMPILERS.get(SpelCompilerMode.valueOf(compilerMode)); + : SPEL_COMPILERS.get(SpelCompilerMode.valueOf(compilerMode.toUpperCase())); } + Assert.state(parser != null, "'parser' must not be null"); candidate.expression = parser.parseExpression(candidate.expressionString); if (!this.useSpelInvoker && !candidate.spelOnly) { candidate.setInvocableHandlerMethod(createInvocableHandlerMethod(candidate.method)); @@ -583,7 +588,7 @@ private Object invokeHandlerMethod(HandlerMethod handlerMethod, ParametersWrappe } } - private Object processInvokeExceptionAndFallbackToExpressionIfAny(HandlerMethod handlerMethod, + private @Nullable Object processInvokeExceptionAndFallbackToExpressionIfAny(HandlerMethod handlerMethod, ParametersWrapper parameters, RuntimeException ex) { if (ex instanceof MessageConversionException) { @@ -592,10 +597,11 @@ private Object processInvokeExceptionAndFallbackToExpressionIfAny(HandlerMethod throw ex; } } - else if (ex instanceof IllegalStateException && // NOSONAR complex boolean expression + else if (ex instanceof IllegalStateException && (!(ex.getCause() instanceof IllegalArgumentException) || !ex.getStackTrace()[0].getClassName().equals(InvocableHandlerMethod.class.getName()) || (!"argument type mismatch".equals(ex.getCause().getMessage()) && + ex.getCause().getMessage() != null && // JVM generates GeneratedMethodAccessor### after several calls with less error // checking !ex.getCause().getMessage().startsWith("java.lang.ClassCastException@")))) { @@ -605,7 +611,7 @@ else if (ex instanceof IllegalStateException && // NOSONAR complex boolean expre return fallbackToInvokeExpression(handlerMethod, parameters); } - private Object fallbackToInvokeExpression(HandlerMethod handlerMethod, ParametersWrapper parameters) { + private @Nullable Object fallbackToInvokeExpression(HandlerMethod handlerMethod, ParametersWrapper parameters) { Expression expression = handlerMethod.expression; if (++handlerMethod.failedAttempts >= FAILED_ATTEMPTS_THRESHOLD) { @@ -619,7 +625,7 @@ private Object fallbackToInvokeExpression(HandlerMethod handlerMethod, Parameter return invokeExpression(expression, parameters); } - private Object invokeExpression(Expression expression, ParametersWrapper parameters) { + private @Nullable Object invokeExpression(Expression expression, ParametersWrapper parameters) { try { convertJsonPayloadIfNecessary(parameters); @@ -663,6 +669,7 @@ && contentTypeIsJson(parameters.message)) { } } + @SuppressWarnings("NullAway") // dataflow analysis limitation private void doConvertJsonPayload(ParametersWrapper parameters) { try { Object targetPayload = @@ -695,8 +702,8 @@ private Map, HandlerMethod>> findHandlerMethodsForTarget() Map, HandlerMethod> candidateMessageMethods = new HashMap<>(); Map, HandlerMethod> fallbackMethods = new HashMap<>(); Map, HandlerMethod> fallbackMessageMethods = new HashMap<>(); - AtomicReference> ambiguousFallbackType = new AtomicReference<>(); - AtomicReference> ambiguousFallbackMessageGenericType = new AtomicReference<>(); + AtomicReference<@Nullable Class> ambiguousFallbackType = new AtomicReference<>(); + AtomicReference<@Nullable Class> ambiguousFallbackMessageGenericType = new AtomicReference<>(); Class targetClass = getTargetClass(this.targetObject); processMethodsFromTarget(candidateMethods, candidateMessageMethods, fallbackMethods, fallbackMessageMethods, @@ -735,8 +742,8 @@ private Map, HandlerMethod>> findHandlerMethodsForTarget() } private void validateFallbackMethods(Map, HandlerMethod> fallbackMethods, - Map, HandlerMethod> fallbackMessageMethods, AtomicReference> ambiguousFallbackType, - AtomicReference> ambiguousFallbackMessageGenericType) { + Map, HandlerMethod> fallbackMessageMethods, AtomicReference<@Nullable Class> ambiguousFallbackType, + AtomicReference<@Nullable Class> ambiguousFallbackMessageGenericType) { Assert.state(!fallbackMethods.isEmpty() || !fallbackMessageMethods.isEmpty(), () -> "Target object of type [" + this.targetObject.getClass() + "] has no eligible methods for handling Messages."); @@ -753,8 +760,8 @@ private void validateFallbackMethods(Map, HandlerMethod> fallbackMethod private void processMethodsFromTarget(Map, HandlerMethod> candidateMethods, Map, HandlerMethod> candidateMessageMethods, Map, HandlerMethod> fallbackMethods, - Map, HandlerMethod> fallbackMessageMethods, AtomicReference> ambiguousFallbackType, - AtomicReference> ambiguousFallbackMessageGenericType, Class targetClass) { + Map, HandlerMethod> fallbackMessageMethods, AtomicReference<@Nullable Class> ambiguousFallbackType, + AtomicReference<@Nullable Class> ambiguousFallbackMessageGenericType, Class targetClass) { ReflectionUtils.doWithMethods(targetClass, method1 -> { boolean matchesAnnotation = false; @@ -828,8 +835,8 @@ private HandlerMethod obtainHandlerMethodIfAny(Method methodToProcess) { private void populateHandlerMethod(Map, HandlerMethod> candidateMethods, Map, HandlerMethod> candidateMessageMethods, Map, HandlerMethod> fallbackMethods, - Map, HandlerMethod> fallbackMessageMethods, AtomicReference> ambiguousFallbackType, - AtomicReference> ambiguousFallbackMessageGenericType, boolean matchesAnnotation, + Map, HandlerMethod> fallbackMessageMethods, AtomicReference<@Nullable Class> ambiguousFallbackType, + AtomicReference<@Nullable Class> ambiguousFallbackMessageGenericType, boolean matchesAnnotation, HandlerMethod handlerMethod1) { Class targetParameterType = handlerMethod1.getTargetParameterType(); @@ -898,7 +905,7 @@ private Method obtainFrameworkMethod(Class targetClass) { private void findSingleSpecificMethodOnInterfacesIfProxy(Map, HandlerMethod> candidateMessageMethods, Map, HandlerMethod> candidateMethods) { if (AopUtils.isAopProxy(this.targetObject)) { - final AtomicReference targetMethod = new AtomicReference<>(); + final AtomicReference<@Nullable Method> targetMethod = new AtomicReference<>(); Class[] interfaces = ((Advised) this.targetObject).getProxiedInterfaces(); for (Class clazz : interfaces) { ReflectionUtils.doWithMethods(clazz, method1 -> { @@ -953,10 +960,10 @@ private void checkSpelInvokerRequired(final Class targetClass, Method methodA } } - private String resolveExpression(String value) { + private @Nullable String resolveExpression(String value) { String resolvedValue = resolve(value); - if (!(resolvedValue.startsWith("#{") && value.endsWith("}"))) { + if (!(resolvedValue != null && resolvedValue.startsWith("#{") && value.endsWith("}"))) { return resolvedValue; } @@ -965,10 +972,10 @@ private String resolveExpression(String value) { return (String) evaluated; } - private String resolve(String value) { + private @Nullable String resolve(String value) { BeanFactory beanFactory = getBeanFactory(); - if (beanFactory instanceof ConfigurableBeanFactory) { - return ((ConfigurableBeanFactory) beanFactory).resolveEmbeddedValue(value); + if (beanFactory instanceof ConfigurableBeanFactory configurableBeanFactory) { + return configurableBeanFactory.resolveEmbeddedValue(value); } return value; } @@ -991,7 +998,7 @@ private Class getTargetClass(Object targetObject) { return targetClass; } - private HandlerMethod findHandlerMethodForParameters(ParametersWrapper parameters) { + private @Nullable HandlerMethod findHandlerMethodForParameters(ParametersWrapper parameters) { if (this.handlerMethod != null) { return this.handlerMethod; } @@ -1004,6 +1011,7 @@ private HandlerMethod findHandlerMethodForParameters(ParametersWrapper parameter } + Assert.state(this.handlerMethods != null, "'handlerMethods' must not be null"); if (Iterable.class.isAssignableFrom(payloadType) && this.handlerMethods.containsKey(Iterator.class)) { return this.handlerMethods.get(Iterator.class); } @@ -1012,7 +1020,7 @@ private HandlerMethod findHandlerMethodForParameters(ParametersWrapper parameter } } - private HandlerMethod findClosestMatch(Class payloadType) { + private @Nullable HandlerMethod findClosestMatch(Class payloadType) { for (Map, HandlerMethod> methods : this.handlerMethodsList) { Set> candidates = methods.keySet(); Class match = null; @@ -1046,19 +1054,20 @@ private static class HandlerMethod { private final Method method; - private InvocableHandlerMethod invocableHandlerMethod; + private @Nullable InvocableHandlerMethod invocableHandlerMethod; + @SuppressWarnings("NullAway.Init") private Expression expression; - private TypeDescriptor targetParameterTypeDescriptor; + private @Nullable TypeDescriptor targetParameterTypeDescriptor; private Class targetParameterType = Void.class; - private MethodParameter exclusiveMethodParameter; + private @Nullable MethodParameter exclusiveMethodParameter; private boolean messageMethod; - private UseSpelInvoker useSpelInvoker; + private @Nullable UseSpelInvoker useSpelInvoker; private volatile boolean spelOnly; @@ -1079,8 +1088,8 @@ void setInvocableHandlerMethod(InvocableHandlerMethod newInvocableHandlerMethod) this.invocableHandlerMethod = newInvocableHandlerMethod; } - @Nullable - public Object invoke(ParametersWrapper parameters) { + @SuppressWarnings("NullAway") // critical execution path, invocableHandlerMethod and message won't be null + public @Nullable Object invoke(ParametersWrapper parameters) { Message message = parameters.getMessage(); if (this.canProcessMessageList) { message = new MutableMessage<>(parameters.getMessages(), parameters.getHeaders()); @@ -1146,7 +1155,7 @@ private String generateExpression(Method method) { private boolean processMethodParameterForExpression(StringBuilder sb, boolean hasUnqualifiedMapParameter, MethodParameter methodParameter, TypeDescriptor parameterTypeDescriptor, Class parameterType, - Type genericParameterType, Annotation mappingAnnotation) { + Type genericParameterType, @Nullable Annotation mappingAnnotation) { if (mappingAnnotation != null) { processMappingAnnotationForExpression(sb, methodParameter, parameterTypeDescriptor, parameterType, @@ -1337,13 +1346,13 @@ private void setExclusiveTargetParameterType(TypeDescriptor targetParameterType, public static class ParametersWrapper { - private final Collection> messages; + private final @Nullable Collection> messages; - private final Map headers; + private final @Nullable Map headers; - private Message message; + private @Nullable Message message; - private Object payload; + private @Nullable Object payload; ParametersWrapper(Message message) { this.message = message; @@ -1352,7 +1361,7 @@ public static class ParametersWrapper { this.messages = null; } - ParametersWrapper(Collection> messages, Map headers) { + ParametersWrapper(Collection> messages, @Nullable Map headers) { this.messages = messages; this.headers = headers; } @@ -1382,14 +1391,15 @@ public Collection> getMessages() { return this.messages; } - public Map getHeaders() { + public @Nullable Map getHeaders() { return this.headers; } - public Message getMessage() { + public @Nullable Message getMessage() { return this.message; } + @SuppressWarnings("NullAway") // dataflow analysis limitation, messages won't be null public Class getFirstParameterType() { if (this.payload != null) { return this.payload.getClass(); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/PayloadExpressionArgumentResolver.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/PayloadExpressionArgumentResolver.java index d7baf55580c..eb2d36eff72 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/PayloadExpressionArgumentResolver.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/PayloadExpressionArgumentResolver.java @@ -19,6 +19,8 @@ import java.util.HashMap; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.expression.Expression; import org.springframework.integration.util.AbstractExpressionEvaluator; @@ -49,14 +51,13 @@ public boolean supportsParameter(MethodParameter parameter) { return ann != null && StringUtils.hasText(ann.expression()); } + @SuppressWarnings("NullAway") // dataflow analysis limitation, Payload never null @Override - public Object resolveArgument(MethodParameter parameter, Message message) { - Expression expression = this.expressionCache.get(parameter); - if (expression == null) { + public @Nullable Object resolveArgument(MethodParameter parameter, Message message) { + Expression expression = this.expressionCache.computeIfAbsent(parameter, key -> { Payload ann = parameter.getParameterAnnotation(Payload.class); - expression = EXPRESSION_PARSER.parseExpression(ann.expression()); // NOSONAR never null - supportsParameter() - this.expressionCache.put(parameter, expression); - } + return EXPRESSION_PARSER.parseExpression(ann.expression()); // never null - supportsParameter() + }); return evaluateExpression(expression, message.getPayload(), parameter.getParameterType()); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/PayloadsArgumentResolver.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/PayloadsArgumentResolver.java index df162d6cd42..16c05fbd785 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/PayloadsArgumentResolver.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/PayloadsArgumentResolver.java @@ -23,6 +23,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + import org.springframework.core.MethodParameter; import org.springframework.core.convert.TypeDescriptor; import org.springframework.expression.Expression; @@ -47,7 +49,7 @@ public class PayloadsArgumentResolver extends AbstractExpressionEvaluator implements HandlerMethodArgumentResolver { - private final Map expressionCache = new HashMap<>(); + private final Map expressionCache = new HashMap<>(); @Override public boolean supportsParameter(MethodParameter parameter) { @@ -55,26 +57,24 @@ public boolean supportsParameter(MethodParameter parameter) { } @Override - @SuppressWarnings("unchecked") - public Object resolveArgument(MethodParameter parameter, Message message) { + @SuppressWarnings({"unchecked", "NullAway"}) + public @Nullable Object resolveArgument(MethodParameter parameter, Message message) { Object payload = message.getPayload(); Assert.state(payload instanceof Collection, "This Argument Resolver support only messages with payload as Collection>"); Collection> messages = (Collection>) payload; - if (!this.expressionCache.containsKey(parameter)) { + Expression expression = this.expressionCache.computeIfAbsent(parameter, key -> { Payloads payloads = parameter.getParameterAnnotation(Payloads.class); - String expression = payloads.value(); // NOSONAR never null - supportsParameter() - if (StringUtils.hasText(expression)) { - this.expressionCache.put(parameter, EXPRESSION_PARSER.parseExpression("![payload." + expression + "]")); + String expressionString = payloads.value(); // never null - supportsParameter() + if (StringUtils.hasText(expressionString)) { + return EXPRESSION_PARSER.parseExpression("![payload." + expressionString + "]"); } else { - this.expressionCache.put(parameter, null); + return null; } + }); - } - - Expression expression = this.expressionCache.get(parameter); if (expression != null) { return evaluateExpression(expression, messages, parameter.getParameterType()); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/package-info.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/package-info.java index 7deb8ab5c77..74b614a3904 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/package-info.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/package-info.java @@ -1,4 +1,5 @@ /** * Provides classes for message handlers support. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.handler.support; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/util/AbstractExpressionEvaluator.java b/spring-integration-core/src/main/java/org/springframework/integration/util/AbstractExpressionEvaluator.java index 06673af3390..e4dcf1c4e15 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/util/AbstractExpressionEvaluator.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/util/AbstractExpressionEvaluator.java @@ -174,7 +174,7 @@ protected T evaluateExpression(String expression, Object input, @Nullable Cl } @Nullable - protected Object evaluateExpression(Expression expression, Object input) { + protected Object evaluateExpression(Expression expression, @Nullable Object input) { return evaluateExpression(expression, input, null); } @@ -189,7 +189,7 @@ protected Object evaluateExpression(Expression expression) { } @Nullable - protected T evaluateExpression(Expression expression, Object input, @Nullable Class expectedType) { + protected T evaluateExpression(Expression expression, @Nullable Object input, @Nullable Class expectedType) { return expression.getValue(getEvaluationContext(), input, expectedType); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/util/AnnotatedMethodFilter.java b/spring-integration-core/src/main/java/org/springframework/integration/util/AnnotatedMethodFilter.java index e0ec58fdb21..70ba74fe1b4 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/util/AnnotatedMethodFilter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/util/AnnotatedMethodFilter.java @@ -21,6 +21,8 @@ import java.util.ArrayList; import java.util.List; +import org.jspecify.annotations.Nullable; + import org.springframework.core.annotation.AnnotationUtils; import org.springframework.expression.MethodFilter; import org.springframework.util.StringUtils; @@ -39,13 +41,14 @@ */ public class AnnotatedMethodFilter implements MethodFilter { - private final Class annotationType; + private final @Nullable Class annotationType; - private final String methodName; + private final @Nullable String methodName; private final boolean requiresReply; - public AnnotatedMethodFilter(Class annotationType, String methodName, boolean requiresReply) { + public AnnotatedMethodFilter(@Nullable Class annotationType, @Nullable String methodName, + boolean requiresReply) { this.annotationType = annotationType; this.methodName = methodName; this.requiresReply = requiresReply;