Skip to content

Add JSpecify Nullability to the xml package #10196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 14, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.List;

import org.jspecify.annotations.Nullable;
import org.w3c.dom.Element;

import org.springframework.beans.factory.config.BeanDefinition;
Expand Down Expand Up @@ -91,7 +92,7 @@ public static void processOutboundTypeAttributes(Element element, ParserContext

}

public static boolean areMutuallyExclusive(String query, BeanDefinition statementExpressionDef,
private static boolean areMutuallyExclusive(String query, @Nullable BeanDefinition statementExpressionDef,
String ingestQuery) {

return !StringUtils.hasText(query) && statementExpressionDef == null && !StringUtils.hasText(ingestQuery)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/**
* Provides classes supporting annotation-based configuration.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.integration.config.annotation;
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.integration.config.xml;

import org.jspecify.annotations.Nullable;
import org.w3c.dom.Element;

import org.springframework.beans.MutablePropertyValues;
Expand Down Expand Up @@ -61,6 +62,7 @@ else if (!StringUtils.hasText(id)) {
return id;
}

@SuppressWarnings("NullAway")
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
String channelName = element.getAttribute("channel");
Expand Down Expand Up @@ -88,7 +90,7 @@ protected final AbstractBeanDefinition parseInternal(Element element, ParserCont
return beanDefinition;
}

private String createDirectChannel(Element element, ParserContext parserContext) {
private @Nullable String createDirectChannel(Element element, ParserContext parserContext) {
if (parserContext.isNested()) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Collection;
import java.util.List;

import org.jspecify.annotations.Nullable;
import org.w3c.dom.Element;

import org.springframework.beans.factory.BeanDefinitionStoreException;
Expand Down Expand Up @@ -85,7 +86,7 @@ protected String getInputChannelAttributeName() {
}

@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
protected final @Nullable AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder handlerBuilder = parseHandler(element, parserContext);
IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "output-channel",
"outputChannelName");
Expand Down Expand Up @@ -178,6 +179,7 @@ private void poller(Element element, ParserContext parserContext, BeanDefinition
}
}

@SuppressWarnings("NullAway") // Dataflow analysis limitation
private void registerChannelForCreation(ParserContext parserContext, String inputChannelName,
BeanDefinitionBuilder consumerEndpointBuilder) {

Expand All @@ -194,13 +196,11 @@ private void registerChannelForCreation(ParserContext parserContext, String inpu
if (vh == null) { //although it should never happen if it does we can fix it
caValues.addIndexedArgumentValue(0, new ManagedSet<String>());
}

@SuppressWarnings("unchecked")
Collection<String> channelCandidateNames =
(Collection<String>) caValues.getArgumentValue(0, Collection.class)
.getValue(); // NOSONAR see comment above
channelCandidateNames.add(inputChannelName); // NOSONAR

.getValue();
channelCandidateNames.add(inputChannelName);
consumerEndpointBuilder.addDependsOn(IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.integration.config.xml;

import org.jspecify.annotations.Nullable;
import org.w3c.dom.Element;

import org.springframework.beans.BeanMetadataElement;
Expand Down Expand Up @@ -65,7 +66,7 @@ public abstract class AbstractCorrelatingMessageHandlerParser extends AbstractCo

private static final String RELEASE_LOCK = "release-lock-before-send";

protected void doParse(BeanDefinitionBuilder builder, Element element, BeanMetadataElement processor,
protected void doParse(BeanDefinitionBuilder builder, Element element, @Nullable BeanMetadataElement processor,
ParserContext parserContext) {
IntegrationNamespaceUtils.injectPropertyWithAdapter(CORRELATION_STRATEGY_REF_ATTRIBUTE,
CORRELATION_STRATEGY_METHOD_ATTRIBUTE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.integration.config.xml;

import org.jspecify.annotations.Nullable;
import org.w3c.dom.Element;

import org.springframework.beans.factory.config.BeanDefinition;
Expand Down Expand Up @@ -65,7 +66,6 @@ else if (hasRef && hasExpression) {
parserContext.getReaderContext().error(
"Only one of 'ref' or 'expression' is permitted, not both, on element " +
IntegrationNamespaceUtils.createElementDescription(element) + ".", source);
return null;
}
else if (hasRef) {
builder.addPropertyReference("targetObject", ref);
Expand All @@ -77,7 +77,6 @@ else if (!this.hasDefaultOption()) {
parserContext.getReaderContext().error("Exactly one of the 'ref' attribute, 'expression' attribute, " +
"or inner bean (<bean/>) definition is required for element " +
IntegrationNamespaceUtils.createElementDescription(element) + ".", source);
return null;
}
methodAttribute(element, parserContext, source, builder, innerDefinition, hasRef, hasExpression,
expressionElement);
Expand All @@ -87,9 +86,9 @@ else if (!this.hasDefaultOption()) {
return builder;
}

private void innerDefinition(Element element, ParserContext parserContext, Object source,
private void innerDefinition(Element element, ParserContext parserContext, @Nullable Object source,
BeanDefinitionBuilder builder, BeanComponentDefinition innerDefinition, boolean hasRef,
boolean hasExpression, Element expressionElement) {
boolean hasExpression, @Nullable Element expressionElement) {
if (hasRef || hasExpression || expressionElement != null) {
parserContext.getReaderContext().error(
"Neither 'ref' nor 'expression' are permitted when an inner bean (<bean/>) is configured on element " +
Expand All @@ -98,9 +97,9 @@ private void innerDefinition(Element element, ParserContext parserContext, Objec
builder.addPropertyValue("targetObject", innerDefinition);
}

private void scriptElement(Element element, ParserContext parserContext, Object source,
private void scriptElement(Element element, ParserContext parserContext, @Nullable Object source,
BeanDefinitionBuilder builder, boolean hasRef, boolean hasExpression, Element scriptElement,
Element expressionElement) {
@Nullable Element expressionElement) {
if (hasRef || hasExpression || expressionElement != null) {
parserContext.getReaderContext().error(
"Neither 'ref' nor 'expression' are permitted when an inner script element is configured on element " +
Expand All @@ -110,7 +109,7 @@ private void scriptElement(Element element, ParserContext parserContext, Object
builder.addPropertyValue("targetObject", scriptBeanDefinition);
}

private void expressionElement(Element element, ParserContext parserContext, Object source,
private void expressionElement(Element element, ParserContext parserContext, @Nullable Object source,
BeanDefinitionBuilder builder, boolean hasRef, boolean hasExpression, Element expressionElement) {
if (hasRef || hasExpression) {
parserContext.getReaderContext().error(
Expand All @@ -126,9 +125,9 @@ private void expressionElement(Element element, ParserContext parserContext, Obj
builder.addPropertyValue("expression", dynamicExpressionBuilder.getBeanDefinition());
}

private void methodAttribute(Element element, ParserContext parserContext, Object source,
BeanDefinitionBuilder builder, BeanComponentDefinition innerDefinition, boolean hasRef,
boolean hasExpression, Element expressionElement) {
private void methodAttribute(Element element, ParserContext parserContext, @Nullable Object source,
BeanDefinitionBuilder builder, @Nullable BeanComponentDefinition innerDefinition, boolean hasRef,
boolean hasExpression, @Nullable Element expressionElement) {
String method = element.getAttribute(METHOD_ATTRIBUTE);
if (StringUtils.hasText(method)) {
if (hasExpression || expressionElement != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.concurrent.atomic.AtomicBoolean;

import org.jspecify.annotations.Nullable;
import org.w3c.dom.Element;

import org.springframework.beans.factory.config.BeanDefinition;
Expand Down Expand Up @@ -47,7 +48,7 @@ public abstract class AbstractIntegrationNamespaceHandler extends NamespaceHandl
private final AtomicBoolean initialized = new AtomicBoolean();

@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
public final @Nullable BeanDefinition parse(Element element, ParserContext parserContext) {
if (!this.initialized.getAndSet(true)) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
new IntegrationRegistrar().registerBeanDefinitions(null, registry);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.integration.config.xml;

import org.jspecify.annotations.Nullable;
import org.w3c.dom.Element;

import org.springframework.beans.factory.config.BeanDefinition;
Expand Down Expand Up @@ -82,7 +83,7 @@ protected AbstractBeanDefinition doParse(Element element, ParserContext parserCo
}

private void configureRequestHandlerAdviceChain(Element element, ParserContext parserContext,
BeanDefinition handlerBeanDefinition, BeanDefinitionBuilder consumerBuilder) {
BeanDefinition handlerBeanDefinition, @Nullable BeanDefinitionBuilder consumerBuilder) {
Element txElement = DomUtils.getChildElementByTagName(element, "transactional");
Element adviceChainElement = DomUtils.getChildElementByTagName(element,
IntegrationNamespaceUtils.REQUEST_HANDLER_ADVICE_CHAIN);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ else if (source instanceof RuntimeBeanReference runtimeBeanReference) {
}
else {
parserContext.getReaderContext().error("Wrong 'source' type: must be 'BeanDefinition' or 'RuntimeBeanReference'", source);
throw new IllegalStateException("This dummy exception is meant to signify to NullAway that an the error method throws an exception");
}

adapterBuilder.addPropertyReference("source", sourceBeanName);
adapterBuilder.addPropertyReference("outputChannel", channelName);
IntegrationNamespaceUtils.setValueIfAttributeDefined(adapterBuilder, element, "send-timeout");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Map;
import java.util.Set;

import org.jspecify.annotations.Nullable;
import org.w3c.dom.Element;

import org.springframework.beans.factory.config.BeanDefinition;
Expand All @@ -46,7 +47,7 @@
public class AnnotationConfigParser implements BeanDefinitionParser {

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
public @Nullable BeanDefinition parse(Element element, ParserContext parserContext) {
ExtendedAnnotationMetadata importingClassMetadata = new ExtendedAnnotationMetadata(element);
BeanDefinitionRegistry registry = parserContext.getRegistry();
new IntegrationRegistrar()
Expand All @@ -67,11 +68,11 @@ private static final class ExtendedAnnotationMetadata extends AnnotationMetadata
}

@Override
public Map<String, Object> getAnnotationAttributes(String annotationType) {
public @Nullable Map<String, @Nullable Object> getAnnotationAttributes(String annotationType) {
if (EnablePublisher.class.getName().equals(annotationType)) {
Element enablePublisherElement = DomUtils.getChildElementByTagName(this.element, "enable-publisher");
if (enablePublisherElement != null) {
Map<String, Object> attributes = new HashMap<>();
Map<String, @Nullable Object> attributes = new HashMap<>();
attributes.put("defaultChannel", enablePublisherElement.getAttribute("default-publisher-channel"));
attributes.put("proxyTargetClass", enablePublisherElement.getAttribute("proxy-target-class"));
attributes.put("order", enablePublisherElement.getAttribute("order"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.apache.commons.logging.Log;
Expand Down Expand Up @@ -90,7 +91,6 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
parserContext.getReaderContext().error("A bean definition is already registered for " +
"beanName: '" + handlerBeanName + "' within the current <chain>.",
element);
return null;
}
}
if ("gateway".equals(child.getLocalName())) {
Expand All @@ -100,7 +100,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
handlerList.add(gwBuilder.getBeanDefinition());
}
else {
handlerList.add(childBeanMetadata);
handlerList.add(Objects.requireNonNull(childBeanMetadata));
}
}
}
Expand Down Expand Up @@ -142,14 +142,14 @@ private BeanMetadataElement parseChild(String chainHandlerId, Element element, i
BeanDefinition beanDefinition = parserContext.getDelegate().parseCustomElement(element, parentDefinition);
if (beanDefinition == null) {
parserContext.getReaderContext().error("child BeanDefinition must not be null", element);
return null;
throw new IllegalStateException("This dummy exception is meant to signify to NullAway that an the error method throws an exception");
}
else {
holder = new BeanDefinitionHolder(beanDefinition, handlerComponentName + IntegrationConfigUtils.HANDLER_ALIAS_SUFFIX);
}
}

holder.getBeanDefinition().getPropertyValues().add("componentName", handlerComponentName); // NOSONAR never null
Objects.requireNonNull(holder).getBeanDefinition().getPropertyValues().add("componentName", handlerComponentName); // NOSONAR never null

if (hasId) {
BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());
Expand Down
Loading