Skip to content

Commit a37958f

Browse files
committed
Add JSpecify Nullability to the xml package
* Tests were updated * Test XML files updated to handle non nullable attributes and parameters * In some cases I reformatted the whole xml file vs the changed section. If this is a problem I'll undo. * In many circumstances the chances of having null, should not happen, so `Objects.requireNonNull` was used. But wonder if we should use Assert.state and have a message. Thoughts?
1 parent 1bd1c13 commit a37958f

34 files changed

+225
-149
lines changed

spring-integration-cassandra/src/main/java/org/springframework/integration/cassandra/config/xml/CassandraParserUtils.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.List;
2020

21+
import org.jspecify.annotations.Nullable;
2122
import org.w3c.dom.Element;
2223

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

9293
}
9394

94-
public static boolean areMutuallyExclusive(String query, BeanDefinition statementExpressionDef,
95+
public static boolean areMutuallyExclusive(@Nullable String query, @Nullable BeanDefinition statementExpressionDef,
9596
String ingestQuery) {
9697

9798
return !StringUtils.hasText(query) && statementExpressionDef == null && !StringUtils.hasText(ingestQuery)
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
22
* Provides classes supporting annotation-based configuration.
33
*/
4+
@org.jspecify.annotations.NullMarked
45
package org.springframework.integration.config.annotation;

spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractChannelAdapterParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.integration.config.xml;
1818

19+
import org.jspecify.annotations.Nullable;
1920
import org.w3c.dom.Element;
2021

2122
import org.springframework.beans.MutablePropertyValues;
@@ -62,6 +63,7 @@ else if (!StringUtils.hasText(id)) {
6263
}
6364

6465
@Override
66+
@SuppressWarnings("NullAway")
6567
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
6668
String channelName = element.getAttribute("channel");
6769
if (!StringUtils.hasText(channelName)) {
@@ -88,7 +90,7 @@ protected final AbstractBeanDefinition parseInternal(Element element, ParserCont
8890
return beanDefinition;
8991
}
9092

91-
private String createDirectChannel(Element element, ParserContext parserContext) {
93+
private @Nullable String createDirectChannel(Element element, ParserContext parserContext) {
9294
if (parserContext.isNested()) {
9395
return null;
9496
}

spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractChannelParser.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.integration.config.xml;
1818

19+
import java.util.Objects;
20+
21+
import org.jspecify.annotations.Nullable;
1922
import org.w3c.dom.Element;
2023

2124
import org.springframework.aop.scope.ScopedProxyUtils;
@@ -44,7 +47,7 @@ public abstract class AbstractChannelParser extends AbstractBeanDefinitionParser
4447
@Override
4548
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
4649
BeanDefinitionBuilder builder = this.buildBeanDefinition(element, parserContext);
47-
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
50+
AbstractBeanDefinition beanDefinition = Objects.requireNonNull(builder).getBeanDefinition();
4851
Element interceptorsElement = DomUtils.getChildElementByTagName(element, "interceptors");
4952
String datatypeAttr = element.getAttribute("datatype");
5053
String messageConverter = element.getAttribute("message-converter");
@@ -107,6 +110,6 @@ protected void registerBeanDefinition(BeanDefinitionHolder definition, BeanDefin
107110
* @param parserContext The parser context.
108111
* @return The bean definition builder.
109112
*/
110-
protected abstract BeanDefinitionBuilder buildBeanDefinition(Element element, ParserContext parserContext);
113+
protected abstract @Nullable BeanDefinitionBuilder buildBeanDefinition(Element element, ParserContext parserContext);
111114

112115
}

spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
import java.util.Collection;
2020
import java.util.List;
21+
import java.util.Objects;
2122

23+
import org.jspecify.annotations.Nullable;
2224
import org.w3c.dom.Element;
2325

2426
import org.springframework.beans.factory.BeanDefinitionStoreException;
@@ -78,16 +80,16 @@ protected String resolveId(Element element, AbstractBeanDefinition definition, P
7880
* @param parserContext The parser context.
7981
* @return The bean definition builder.
8082
*/
81-
protected abstract BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext);
83+
protected abstract @Nullable BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext);
8284

8385
protected String getInputChannelAttributeName() {
8486
return "input-channel";
8587
}
8688

8789
@Override
88-
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
90+
protected final @Nullable AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
8991
BeanDefinitionBuilder handlerBuilder = parseHandler(element, parserContext);
90-
IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "output-channel",
92+
IntegrationNamespaceUtils.setValueIfAttributeDefined(Objects.requireNonNull(handlerBuilder), element, "output-channel",
9193
"outputChannelName");
9294
IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "order");
9395

@@ -140,9 +142,9 @@ protected final AbstractBeanDefinition parseInternal(Element element, ParserCont
140142

141143
String handlerBeanName =
142144
BeanDefinitionReaderUtils.generateBeanName(handlerBeanDefinition, parserContext.getRegistry());
143-
String[] handlerAlias = IntegrationNamespaceUtils.generateAlias(element);
144145
parserContext.registerBeanComponent(
145-
new BeanComponentDefinition(handlerBeanDefinition, handlerBeanName, handlerAlias));
146+
new BeanComponentDefinition(handlerBeanDefinition, handlerBeanName,
147+
IntegrationNamespaceUtils.generateAlias(element)));
146148

147149
builder.addPropertyReference("handler", handlerBeanName);
148150

@@ -194,13 +196,11 @@ private void registerChannelForCreation(ParserContext parserContext, String inpu
194196
if (vh == null) { //although it should never happen if it does we can fix it
195197
caValues.addIndexedArgumentValue(0, new ManagedSet<String>());
196198
}
197-
198199
@SuppressWarnings("unchecked")
199200
Collection<String> channelCandidateNames =
200-
(Collection<String>) caValues.getArgumentValue(0, Collection.class)
201+
(Collection<String>) Objects.requireNonNull(caValues.getArgumentValue(0, Collection.class))
201202
.getValue(); // NOSONAR see comment above
202-
channelCandidateNames.add(inputChannelName); // NOSONAR
203-
203+
Objects.requireNonNull(channelCandidateNames).add(inputChannelName); // NOSONAR
204204
consumerEndpointBuilder.addDependsOn(IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME);
205205
}
206206
else {

spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractCorrelatingMessageHandlerParser.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.integration.config.xml;
1818

19+
import org.jspecify.annotations.Nullable;
1920
import org.w3c.dom.Element;
2021

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

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

68-
protected void doParse(BeanDefinitionBuilder builder, Element element, BeanMetadataElement processor,
69+
protected void doParse(BeanDefinitionBuilder builder, Element element, @Nullable BeanMetadataElement processor,
6970
ParserContext parserContext) {
7071
IntegrationNamespaceUtils.injectPropertyWithAdapter(CORRELATION_STRATEGY_REF_ATTRIBUTE,
7172
CORRELATION_STRATEGY_METHOD_ATTRIBUTE,

spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractDelegatingConsumerEndpointParser.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.integration.config.xml;
1818

19+
import org.jspecify.annotations.Nullable;
1920
import org.w3c.dom.Element;
2021

2122
import org.springframework.beans.factory.config.BeanDefinition;
@@ -39,7 +40,7 @@
3940
abstract class AbstractDelegatingConsumerEndpointParser extends AbstractConsumerEndpointParser {
4041

4142
@Override
42-
protected final BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
43+
protected final @Nullable BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
4344
Object source = parserContext.extractSource(element);
4445
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(this.getFactoryBeanClassName());
4546
BeanComponentDefinition innerDefinition = IntegrationNamespaceUtils.parseInnerHandlerDefinition(element,
@@ -87,9 +88,9 @@ else if (!this.hasDefaultOption()) {
8788
return builder;
8889
}
8990

90-
private void innerDefinition(Element element, ParserContext parserContext, Object source,
91+
private void innerDefinition(Element element, ParserContext parserContext, @Nullable Object source,
9192
BeanDefinitionBuilder builder, BeanComponentDefinition innerDefinition, boolean hasRef,
92-
boolean hasExpression, Element expressionElement) {
93+
boolean hasExpression, @Nullable Element expressionElement) {
9394
if (hasRef || hasExpression || expressionElement != null) {
9495
parserContext.getReaderContext().error(
9596
"Neither 'ref' nor 'expression' are permitted when an inner bean (<bean/>) is configured on element " +
@@ -98,9 +99,9 @@ private void innerDefinition(Element element, ParserContext parserContext, Objec
9899
builder.addPropertyValue("targetObject", innerDefinition);
99100
}
100101

101-
private void scriptElement(Element element, ParserContext parserContext, Object source,
102+
private void scriptElement(Element element, ParserContext parserContext, @Nullable Object source,
102103
BeanDefinitionBuilder builder, boolean hasRef, boolean hasExpression, Element scriptElement,
103-
Element expressionElement) {
104+
@Nullable Element expressionElement) {
104105
if (hasRef || hasExpression || expressionElement != null) {
105106
parserContext.getReaderContext().error(
106107
"Neither 'ref' nor 'expression' are permitted when an inner script element is configured on element " +
@@ -110,7 +111,7 @@ private void scriptElement(Element element, ParserContext parserContext, Object
110111
builder.addPropertyValue("targetObject", scriptBeanDefinition);
111112
}
112113

113-
private void expressionElement(Element element, ParserContext parserContext, Object source,
114+
private void expressionElement(Element element, ParserContext parserContext, @Nullable Object source,
114115
BeanDefinitionBuilder builder, boolean hasRef, boolean hasExpression, Element expressionElement) {
115116
if (hasRef || hasExpression) {
116117
parserContext.getReaderContext().error(
@@ -126,9 +127,9 @@ private void expressionElement(Element element, ParserContext parserContext, Obj
126127
builder.addPropertyValue("expression", dynamicExpressionBuilder.getBeanDefinition());
127128
}
128129

129-
private void methodAttribute(Element element, ParserContext parserContext, Object source,
130-
BeanDefinitionBuilder builder, BeanComponentDefinition innerDefinition, boolean hasRef,
131-
boolean hasExpression, Element expressionElement) {
130+
private void methodAttribute(Element element, ParserContext parserContext, @Nullable Object source,
131+
BeanDefinitionBuilder builder, @Nullable BeanComponentDefinition innerDefinition, boolean hasRef,
132+
boolean hasExpression, @Nullable Element expressionElement) {
132133
String method = element.getAttribute(METHOD_ATTRIBUTE);
133134
if (StringUtils.hasText(method)) {
134135
if (hasExpression || expressionElement != null) {

spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractIntegrationNamespaceHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.concurrent.atomic.AtomicBoolean;
2020

21+
import org.jspecify.annotations.Nullable;
2122
import org.w3c.dom.Element;
2223

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

4950
@Override
50-
public final BeanDefinition parse(Element element, ParserContext parserContext) {
51+
public final @Nullable BeanDefinition parse(Element element, ParserContext parserContext) {
5152
if (!this.initialized.getAndSet(true)) {
5253
BeanDefinitionRegistry registry = parserContext.getRegistry();
5354
new IntegrationRegistrar().registerBeanDefinitions(null, registry);

spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.integration.config.xml;
1818

19+
import org.jspecify.annotations.Nullable;
1920
import org.w3c.dom.Element;
2021

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

8485
private void configureRequestHandlerAdviceChain(Element element, ParserContext parserContext,
85-
BeanDefinition handlerBeanDefinition, BeanDefinitionBuilder consumerBuilder) {
86+
BeanDefinition handlerBeanDefinition, @Nullable BeanDefinitionBuilder consumerBuilder) {
8687
Element txElement = DomUtils.getChildElementByTagName(element, "transactional");
8788
Element adviceChainElement = DomUtils.getChildElementByTagName(element,
8889
IntegrationNamespaceUtils.REQUEST_HANDLER_ADVICE_CHAIN);

spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractPollingInboundChannelAdapterParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.integration.config.xml;
1818

19+
import org.jspecify.annotations.Nullable;
1920
import org.w3c.dom.Element;
2021

2122
import org.springframework.beans.BeanMetadataElement;
@@ -59,6 +60,7 @@ else if (source instanceof RuntimeBeanReference runtimeBeanReference) {
5960
}
6061
else {
6162
parserContext.getReaderContext().error("Wrong 'source' type: must be 'BeanDefinition' or 'RuntimeBeanReference'", source);
63+
throw new IllegalStateException("sourceBeanName must not be null");
6264
}
6365

6466
adapterBuilder.addPropertyReference("source", sourceBeanName);
@@ -79,6 +81,6 @@ else if (source instanceof RuntimeBeanReference runtimeBeanReference) {
7981
* @param parserContext The parser context.
8082
* @return The bean metadata element.
8183
*/
82-
protected abstract BeanMetadataElement parseSource(Element element, ParserContext parserContext);
84+
protected abstract @Nullable BeanMetadataElement parseSource(Element element, ParserContext parserContext);
8385

8486
}

0 commit comments

Comments
 (0)