{
* @throws Exception if an there is a non-specific error.
* @return T the item to be processed or {@code null} if the data source is exhausted
*/
- @Nullable
- T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException;
+ @Nullable T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException;
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemStreamException.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemStreamException.java
index ef0e5af611..0dc3d7a72d 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemStreamException.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemStreamException.java
@@ -15,12 +15,15 @@
*/
package org.springframework.batch.item;
+import org.jspecify.annotations.Nullable;
+
/**
* Exception representing any errors encountered while processing a stream.
*
* @author Dave Syer
* @author Lucas Ward
* @author Mahmoud Ben Hassine
+ * @author Stefano Cordio
*/
public class ItemStreamException extends RuntimeException {
@@ -33,11 +36,10 @@ public ItemStreamException(String message) {
/**
* Constructs a new instance with a message and nested exception.
- * @param msg the exception message.
+ * @param msg the exception message (can be {@code null}).
* @param nested the cause of the exception.
- *
*/
- public ItemStreamException(String msg, Throwable nested) {
+ public ItemStreamException(@Nullable String msg, Throwable nested) {
super(msg, nested);
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemStreamSupport.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemStreamSupport.java
index 86446bc0ca..b3d246c9d6 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemStreamSupport.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemStreamSupport.java
@@ -15,6 +15,7 @@
*/
package org.springframework.batch.item;
+import org.jspecify.annotations.Nullable;
import org.springframework.batch.item.util.ExecutionContextUserSupport;
/**
@@ -23,6 +24,7 @@
* @author Dave Syer
* @author Dean de Bree
* @author Mahmoud Ben Hassine
+ * @author Stefano Cordio
*
*/
public abstract class ItemStreamSupport implements ItemStream {
@@ -43,7 +45,7 @@ public void setName(String name) {
* Get the name of the component
* @return the name of the component
*/
- public String getName() {
+ public @Nullable String getName() {
return executionContextUserSupport.getName();
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemWriter.java
index 674153ea17..76edb408b3 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemWriter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemWriter.java
@@ -16,8 +16,6 @@
package org.springframework.batch.item;
-import org.springframework.lang.NonNull;
-
/**
*
* Basic interface for generic output operations. Class implementing this interface will
@@ -48,6 +46,6 @@ public interface ItemWriter {
* @throws Exception if there are errors. The framework will catch the exception and
* convert or rethrow it as appropriate.
*/
- void write(@NonNull Chunk extends T> chunk) throws Exception;
+ void write(Chunk extends T> chunk) throws Exception;
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/KeyValueItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/KeyValueItemWriter.java
index 6354fb1358..e72fec9994 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/KeyValueItemWriter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/KeyValueItemWriter.java
@@ -12,6 +12,7 @@
*/
package org.springframework.batch.item;
+import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.Assert;
@@ -22,21 +23,20 @@
*
* @author David Turanski
* @author Mahmoud Ben Hassine
+ * @author Stefano Cordio
* @since 2.2
*
*/
public abstract class KeyValueItemWriter implements ItemWriter, InitializingBean {
- protected Converter itemKeyMapper;
+ protected @Nullable Converter itemKeyMapper;
protected boolean delete;
@Override
- public void write(Chunk extends V> items) throws Exception {
- if (items == null) {
- return;
- }
- for (V item : items) {
+ public void write(Chunk extends V> chunk) throws Exception {
+ for (V item : chunk) {
+ @SuppressWarnings({ "DataFlowIssue", "NullAway" })
K key = itemKeyMapper.convert(item);
writeKeyValue(key, item);
}
@@ -55,7 +55,7 @@ protected void flush() throws Exception {
* @param key the key
* @param value the item
*/
- protected abstract void writeKeyValue(K key, V value);
+ protected abstract void writeKeyValue(@Nullable K key, V value);
/**
* afterPropertiesSet() hook
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/PeekableItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/PeekableItemReader.java
index 4bf053738a..088c6688b0 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/PeekableItemReader.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/PeekableItemReader.java
@@ -15,7 +15,7 @@
*/
package org.springframework.batch.item;
-import org.springframework.lang.Nullable;
+import org.jspecify.annotations.Nullable;
/**
*
@@ -45,7 +45,6 @@ public interface PeekableItemReader extends ItemReader {
* @return the next item or {@code null} if the data source is exhausted
* @throws Exception if there is a problem
*/
- @Nullable
- T peek() throws Exception, UnexpectedInputException, ParseException;
+ @Nullable T peek() throws Exception, UnexpectedInputException, ParseException;
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SkipWrapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SkipWrapper.java
index e997d38b37..1b9a02b959 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SkipWrapper.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SkipWrapper.java
@@ -16,20 +16,21 @@
package org.springframework.batch.item;
-import org.springframework.lang.Nullable;
+import org.jspecify.annotations.Nullable;
/**
* Wrapper for an item and its exception if it failed processing.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
+ * @author Stefano Cordio
*
*/
public class SkipWrapper {
- final private Throwable exception;
+ private final @Nullable Throwable exception;
- final private T item;
+ private final @Nullable T item;
/**
* @param item the item being wrapped.
@@ -38,7 +39,7 @@ public SkipWrapper(T item) {
this(item, null);
}
- public SkipWrapper(T item, @Nullable Throwable e) {
+ public SkipWrapper(@Nullable T item, @Nullable Throwable e) {
this.item = item;
this.exception = e;
}
@@ -47,8 +48,7 @@ public SkipWrapper(T item, @Nullable Throwable e) {
* Public getter for the exception.
* @return the exception
*/
- @Nullable
- public Throwable getException() {
+ public @Nullable Throwable getException() {
return exception;
}
@@ -56,7 +56,7 @@ public Throwable getException() {
* Public getter for the item.
* @return the item
*/
- public T getItem() {
+ public @Nullable T getItem() {
return item;
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SpELItemKeyMapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SpELItemKeyMapper.java
index 13c4f49539..ac4a802ca1 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SpELItemKeyMapper.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SpELItemKeyMapper.java
@@ -12,30 +12,29 @@
*/
package org.springframework.batch.item;
+import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.converter.Converter;
import org.springframework.expression.Expression;
-import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
/**
* An implementation of {@link Converter} that uses SpEL to map a Value to a key
*
* @author David Turanski
+ * @author Stefano Cordio
* @since 2.2
*/
public class SpELItemKeyMapper implements Converter {
- private final ExpressionParser parser = new SpelExpressionParser();
-
private final Expression parsedExpression;
public SpELItemKeyMapper(String keyExpression) {
- parsedExpression = parser.parseExpression(keyExpression);
+ parsedExpression = new SpelExpressionParser().parseExpression(keyExpression);
}
@SuppressWarnings("unchecked")
@Override
- public K convert(V item) {
+ public @Nullable K convert(V item) {
return (K) parsedExpression.getValue(item);
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/AbstractMethodInvokingDelegator.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/AbstractMethodInvokingDelegator.java
index 4a0665ab12..94f2a8d7aa 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/AbstractMethodInvokingDelegator.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/AbstractMethodInvokingDelegator.java
@@ -22,6 +22,7 @@
import java.util.Arrays;
import java.util.List;
+import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -41,21 +42,22 @@
* @author Robert Kasanicky
* @author Mahmoud Ben Hassine
* @author Glenn Renfro
+ * @author Stefano Cordio
*/
public abstract class AbstractMethodInvokingDelegator implements InitializingBean {
- private Object targetObject;
+ private @Nullable Object targetObject;
- private String targetMethod;
+ private @Nullable String targetMethod;
- private Object[] arguments;
+ private @Nullable Object @Nullable [] arguments;
/**
* Invoker the target method with arguments set by {@link #setArguments(Object[])}.
* @return object returned by invoked method
* @throws Exception exception thrown when executing the delegate method.
*/
- protected T invokeDelegateMethod() throws Exception {
+ protected @Nullable T invokeDelegateMethod() throws Exception {
MethodInvoker invoker = createMethodInvoker(targetObject, targetMethod);
invoker.setArguments(arguments);
return doInvoke(invoker);
@@ -67,7 +69,7 @@ protected T invokeDelegateMethod() throws Exception {
* @return object returned by target method
* @throws Exception exception thrown when executing the delegate method.
*/
- protected T invokeDelegateMethodWithArgument(Object object) throws Exception {
+ protected @Nullable T invokeDelegateMethodWithArgument(Object object) throws Exception {
MethodInvoker invoker = createMethodInvoker(targetObject, targetMethod);
invoker.setArguments(object);
return doInvoke(invoker);
@@ -79,7 +81,7 @@ protected T invokeDelegateMethodWithArgument(Object object) throws Exception {
* @return object returned by invoked method
* @throws Exception exception thrown when executing the delegate method.
*/
- protected T invokeDelegateMethodWithArguments(Object[] args) throws Exception {
+ protected @Nullable T invokeDelegateMethodWithArguments(@Nullable Object[] args) throws Exception {
MethodInvoker invoker = createMethodInvoker(targetObject, targetMethod);
invoker.setArguments(args);
return doInvoke(invoker);
@@ -88,7 +90,7 @@ protected T invokeDelegateMethodWithArguments(Object[] args) throws Exception {
/**
* Create a new configured instance of {@link MethodInvoker}.
*/
- private MethodInvoker createMethodInvoker(Object targetObject, String targetMethod) {
+ private MethodInvoker createMethodInvoker(@Nullable Object targetObject, @Nullable String targetMethod) {
HippyMethodInvoker invoker = new HippyMethodInvoker();
invoker.setTargetObject(targetObject);
invoker.setTargetMethod(targetMethod);
@@ -102,7 +104,7 @@ private MethodInvoker createMethodInvoker(Object targetObject, String targetMeth
* @return return value of the invoked method
*/
@SuppressWarnings("unchecked")
- private T doInvoke(MethodInvoker invoker) throws Exception {
+ private @Nullable T doInvoke(MethodInvoker invoker) throws Exception {
try {
invoker.prepare();
}
@@ -141,6 +143,7 @@ public void afterPropertiesSet() throws Exception {
private boolean targetClassDeclaresTargetMethod() {
MethodInvoker invoker = createMethodInvoker(targetObject, targetMethod);
+ @SuppressWarnings({ "DataFlowIssue", "NullAway" })
Method[] memberMethods = invoker.getTargetClass().getMethods();
Method[] declaredMethods = invoker.getTargetClass().getDeclaredMethods();
@@ -200,11 +203,11 @@ public void setTargetMethod(String targetMethod) {
* providing explicit argument values.
*
* If arguments are set to not-null value {@link #afterPropertiesSet()} will check the
- * values are compatible with target method's signature. In case arguments are null
- * (not set) method signature will not be checked and it is assumed correct values
- * will be supplied at runtime.
+ * values are compatible with target method's signature. In case arguments are
+ * {@code null} (not set), the method signature will not be checked, and it is assumed
+ * correct values will be supplied at runtime.
*/
- public void setArguments(Object[] arguments) {
+ public void setArguments(Object @Nullable [] arguments) {
this.arguments = arguments == null ? null : arguments.clone();
}
@@ -212,7 +215,7 @@ public void setArguments(Object[] arguments) {
* Return arguments.
* @return arguments
*/
- protected Object[] getArguments() {
+ protected @Nullable Object @Nullable [] getArguments() {
return arguments;
}
@@ -220,7 +223,7 @@ protected Object[] getArguments() {
* @return the object on which the method will be invoked.
* @since 5.1
*/
- protected Object getTargetObject() {
+ protected @Nullable Object getTargetObject() {
return targetObject;
}
@@ -228,7 +231,7 @@ protected Object getTargetObject() {
* @return the name of the method to be invoked.
* @since 5.1
*/
- protected String getTargetMethod() {
+ protected @Nullable String getTargetMethod() {
return targetMethod;
}
@@ -240,7 +243,7 @@ protected String getTargetMethod() {
*/
public static class InvocationTargetThrowableWrapper extends RuntimeException {
- public InvocationTargetThrowableWrapper(Throwable cause) {
+ public InvocationTargetThrowableWrapper(@Nullable Throwable cause) {
super(cause);
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/HippyMethodInvoker.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/HippyMethodInvoker.java
index 452c60ddcf..359807fb4c 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/HippyMethodInvoker.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/HippyMethodInvoker.java
@@ -17,14 +17,15 @@
import java.lang.reflect.Method;
+import org.jspecify.annotations.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.MethodInvoker;
import org.springframework.util.ReflectionUtils;
/**
* A {@link MethodInvoker} that is a bit relaxed about its arguments. You can give it
- * arguments in the wrong order or you can give it too many arguments and it will try and
- * find a method that matches a subset.
+ * arguments in the wrong order, or you can give it too many arguments, and it will try
+ * and find a method that matches a subset.
*
* @author Dave Syer
* @since 2.1
@@ -34,7 +35,8 @@ public class HippyMethodInvoker extends MethodInvoker {
@Override
protected Method findMatchingMethod() {
String targetMethod = getTargetMethod();
- Object[] arguments = getArguments();
+
+ @Nullable Object[] arguments = getArguments();
Method[] candidates = ReflectionUtils.getAllDeclaredMethods(getTargetClass());
int minTypeDiffWeight = Integer.MAX_VALUE;
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/ItemProcessorAdapter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/ItemProcessorAdapter.java
index 1a640383c7..3d58930164 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/ItemProcessorAdapter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/ItemProcessorAdapter.java
@@ -16,8 +16,9 @@
package org.springframework.batch.item.adapter;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.batch.item.ItemProcessor;
-import org.springframework.lang.Nullable;
/**
* Invokes a custom method on a delegate plain old Java object which itself processes an
@@ -32,9 +33,8 @@ public class ItemProcessorAdapter extends AbstractMethodInvokingDelegator<
*
* @see ItemProcessor#process(Object)
*/
- @Nullable
@Override
- public O process(I item) throws Exception {
+ public @Nullable O process(I item) throws Exception {
return invokeDelegateMethodWithArgument(item);
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/ItemReaderAdapter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/ItemReaderAdapter.java
index 862d793d21..6d7e70bfce 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/ItemReaderAdapter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/ItemReaderAdapter.java
@@ -16,8 +16,9 @@
package org.springframework.batch.item.adapter;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.batch.item.ItemReader;
-import org.springframework.lang.Nullable;
/**
* Invokes a custom method on a delegate plain old Java object which itself provides an
@@ -35,9 +36,8 @@ public class ItemReaderAdapter extends AbstractMethodInvokingDelegator imp
/**
* @return return value of the target method.
*/
- @Nullable
@Override
- public T read() throws Exception {
+ public @Nullable T read() throws Exception {
return invokeDelegateMethod();
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/PropertyExtractingDelegatingItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/PropertyExtractingDelegatingItemWriter.java
index ea1be22468..032d348451 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/PropertyExtractingDelegatingItemWriter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/PropertyExtractingDelegatingItemWriter.java
@@ -16,8 +16,7 @@
package org.springframework.batch.item.adapter;
-import java.util.Arrays;
-
+import org.jspecify.annotations.Nullable;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.BeanWrapper;
@@ -41,12 +40,13 @@
public class PropertyExtractingDelegatingItemWriter extends AbstractMethodInvokingDelegator
implements ItemWriter {
- private String[] fieldsUsedAsTargetMethodArguments;
+ private @Nullable String @Nullable [] fieldsUsedAsTargetMethodArguments;
/**
* Extracts values from item's fields named in fieldsUsedAsTargetMethodArguments and
* passes them as arguments to the delegate method.
*/
+ @SuppressWarnings({ "DataFlowIssue", "NullAway" })
@Override
public void write(Chunk extends T> items) throws Exception {
for (T item : items) {
@@ -54,7 +54,8 @@ public void write(Chunk extends T> items) throws Exception {
// helper for extracting property values from a bean
BeanWrapper beanWrapper = new BeanWrapperImpl(item);
- Object[] methodArguments = new Object[fieldsUsedAsTargetMethodArguments.length];
+ @Nullable Object[] methodArguments = new Object[fieldsUsedAsTargetMethodArguments.length];
+
for (int i = 0; i < fieldsUsedAsTargetMethodArguments.length; i++) {
methodArguments[i] = beanWrapper.getPropertyValue(fieldsUsedAsTargetMethodArguments[i]);
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/package-info.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/package-info.java
index db2847283f..cc768b5f1e 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/package-info.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/adapter/package-info.java
@@ -3,7 +3,7 @@
* Adapters for Plain Old Java Objects.
*
*/
-@NonNullApi
+@NullMarked
package org.springframework.batch.item.adapter;
-import org.springframework.lang.NonNullApi;
+import org.jspecify.annotations.NullMarked;
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/AmqpItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/AmqpItemReader.java
index 8e1e4a654c..b1a33a0182 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/AmqpItemReader.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/AmqpItemReader.java
@@ -16,10 +16,11 @@
package org.springframework.batch.item.amqp;
+import org.jspecify.annotations.Nullable;
+
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.batch.item.ItemReader;
-import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -35,27 +36,27 @@
*
* @author Chris Schaefer
* @author Mahmoud Ben Hassine
+ * @author Stefano Cordio
*/
public class AmqpItemReader implements ItemReader {
private final AmqpTemplate amqpTemplate;
- private Class extends T> itemType;
+ private @Nullable Class extends T> itemType;
/**
* Initialize the AmqpItemReader.
* @param amqpTemplate the template to be used. Must not be null.
*/
- public AmqpItemReader(final AmqpTemplate amqpTemplate) {
+ public AmqpItemReader(AmqpTemplate amqpTemplate) {
Assert.notNull(amqpTemplate, "AmqpTemplate must not be null");
this.amqpTemplate = amqpTemplate;
}
- @Nullable
@Override
@SuppressWarnings("unchecked")
- public T read() {
+ public @Nullable T read() {
if (itemType != null && itemType.isAssignableFrom(Message.class)) {
return (T) amqpTemplate.receive();
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/AmqpItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/AmqpItemWriter.java
index c825635cf8..1e591d7ee9 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/AmqpItemWriter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/AmqpItemWriter.java
@@ -45,14 +45,14 @@ public class AmqpItemWriter implements ItemWriter {
private final Log log = LogFactory.getLog(getClass());
- public AmqpItemWriter(final AmqpTemplate amqpTemplate) {
+ public AmqpItemWriter(AmqpTemplate amqpTemplate) {
Assert.notNull(amqpTemplate, "AmqpTemplate must not be null");
this.amqpTemplate = amqpTemplate;
}
@Override
- public void write(final Chunk extends T> items) throws Exception {
+ public void write(Chunk extends T> items) throws Exception {
if (log.isDebugEnabled()) {
log.debug("Writing to AMQP with " + items.size() + " items.");
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/AmqpItemReaderBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/AmqpItemReaderBuilder.java
index 6f1619ad79..03eda92a92 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/AmqpItemReaderBuilder.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/AmqpItemReaderBuilder.java
@@ -16,6 +16,7 @@
package org.springframework.batch.item.amqp.builder;
+import org.jspecify.annotations.Nullable;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.batch.item.amqp.AmqpItemReader;
import org.springframework.util.Assert;
@@ -24,14 +25,15 @@
* A builder implementation for the {@link AmqpItemReader}
*
* @author Glenn Renfro
+ * @author Stefano Cordio
* @since 4.0
* @see AmqpItemReader
*/
public class AmqpItemReaderBuilder {
- private AmqpTemplate amqpTemplate;
+ private @Nullable AmqpTemplate amqpTemplate;
- private Class extends T> itemType;
+ private @Nullable Class extends T> itemType;
/**
* Establish the amqpTemplate to be used by the AmqpItemReader.
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/AmqpItemWriterBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/AmqpItemWriterBuilder.java
index 979a6ad993..a349a54a8e 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/AmqpItemWriterBuilder.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/AmqpItemWriterBuilder.java
@@ -16,6 +16,7 @@
package org.springframework.batch.item.amqp.builder;
+import org.jspecify.annotations.Nullable;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.batch.item.amqp.AmqpItemWriter;
import org.springframework.util.Assert;
@@ -24,12 +25,13 @@
* A builder implementation for the {@link AmqpItemWriter}
*
* @author Glenn Renfro
+ * @author Stefano Cordio
* @since 4.0
* @see AmqpItemWriter
*/
public class AmqpItemWriterBuilder {
- private AmqpTemplate amqpTemplate;
+ private @Nullable AmqpTemplate amqpTemplate;
/**
* Establish the amqpTemplate to be used by the AmqpItemWriter.
@@ -50,9 +52,7 @@ public AmqpItemWriterBuilder amqpTemplate(AmqpTemplate amqpTemplate) {
public AmqpItemWriter build() {
Assert.notNull(this.amqpTemplate, "amqpTemplate is required.");
- AmqpItemWriter writer = new AmqpItemWriter<>(this.amqpTemplate);
-
- return writer;
+ return new AmqpItemWriter<>(this.amqpTemplate);
}
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/package-info.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/package-info.java
index 250e32146f..573347cc1f 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/package-info.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/builder/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
* Builders for AMQP item reader and writer.
*
* @author Mahmoud Ben Hassine
+ * @author Stefano Cordio
*/
-
-@NonNullApi
+@NullMarked
package org.springframework.batch.item.amqp.builder;
-import org.springframework.lang.NonNullApi;
+import org.jspecify.annotations.NullMarked;
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/package-info.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/package-info.java
index aa419383c0..8724014cca 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/package-info.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/amqp/package-info.java
@@ -3,8 +3,9 @@
*
* @author Michael Minella
* @author Mahmoud Ben Hassine
+ * @author Stefano Cordio
*/
-@NonNullApi
+@NullMarked
package org.springframework.batch.item.amqp;
-import org.springframework.lang.NonNullApi;
+import org.jspecify.annotations.NullMarked;
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/AvroItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/AvroItemReader.java
index ab39d81571..4f887453da 100755
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/AvroItemReader.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/AvroItemReader.java
@@ -28,12 +28,12 @@
import org.apache.avro.reflect.ReflectDatumReader;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificRecordBase;
+import org.jspecify.annotations.Nullable;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
import org.springframework.core.io.Resource;
-import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -54,9 +54,9 @@ public class AvroItemReader extends AbstractItemCountingItemStreamItemReader<
private boolean embeddedSchema = true;
- private InputStreamReader inputStreamReader;
+ private @Nullable InputStreamReader inputStreamReader;
- private DataFileStream dataFileReader;
+ private @Nullable DataFileStream dataFileReader;
private final InputStream inputStream;
@@ -104,15 +104,16 @@ public AvroItemReader(Resource data, Resource schema) {
/**
* Disable or enable reading an embedded Avro schema. True by default.
- * @param embeddedSchema set to false to if the input does not embed an Avro schema.
+ * @param embeddedSchema set to {@code false} if the input does not embed an Avro
+ * schema.
*/
public void setEmbeddedSchema(boolean embeddedSchema) {
this.embeddedSchema = embeddedSchema;
}
- @Nullable
+ @SuppressWarnings({ "DataFlowIssue", "NullAway" })
@Override
- protected T doRead() throws Exception {
+ protected @Nullable T doRead() throws Exception {
if (this.inputStreamReader != null) {
return this.inputStreamReader.read();
}
@@ -124,6 +125,7 @@ protected void doOpen() throws Exception {
initializeReader();
}
+ @SuppressWarnings({ "DataFlowIssue", "NullAway" })
@Override
protected void doClose() throws Exception {
if (this.inputStreamReader != null) {
@@ -171,7 +173,7 @@ private InputStreamReader(InputStream inputStream, DatumReader datumReader) {
this.binaryDecoder = DecoderFactory.get().binaryDecoder(inputStream, null);
}
- private T read() throws Exception {
+ private @Nullable T read() throws Exception {
if (!this.binaryDecoder.isEnd()) {
return this.datumReader.read(null, this.binaryDecoder);
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/AvroItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/AvroItemWriter.java
index 99a63b04bf..16d80d827c 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/AvroItemWriter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/AvroItemWriter.java
@@ -30,6 +30,7 @@
import org.apache.avro.specific.SpecificDatumWriter;
import org.apache.avro.specific.SpecificRecordBase;
+import org.jspecify.annotations.Nullable;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
@@ -54,13 +55,13 @@
*/
public class AvroItemWriter extends AbstractItemStreamItemWriter {
- private DataFileWriter dataFileWriter;
+ private @Nullable DataFileWriter dataFileWriter;
- private OutputStreamWriter outputStreamWriter;
+ private @Nullable OutputStreamWriter outputStreamWriter;
private final WritableResource resource;
- private final Resource schemaResource;
+ private final @Nullable Resource schemaResource;
private final Class clazz;
@@ -71,7 +72,7 @@ public class AvroItemWriter extends AbstractItemStreamItemWriter {
* @param schema a {@link Resource} containing the Avro schema.
* @param clazz the data type to be serialized.
*/
- public AvroItemWriter(WritableResource resource, Resource schema, Class clazz) {
+ public AvroItemWriter(WritableResource resource, @Nullable Resource schema, Class clazz) {
this.schemaResource = schema;
this.resource = resource;
this.clazz = clazz;
@@ -87,6 +88,7 @@ public AvroItemWriter(WritableResource resource, Class clazz) {
embedSchema = false;
}
+ @SuppressWarnings({ "DataFlowIssue", "NullAway" })
@Override
public void write(Chunk extends T> items) throws Exception {
items.forEach(item -> {
@@ -118,6 +120,7 @@ public void open(ExecutionContext executionContext) {
}
}
+ @SuppressWarnings({ "DataFlowIssue", "NullAway" })
@Override
public void close() {
try {
@@ -155,7 +158,6 @@ private void initializeWriter() throws IOException {
this.outputStreamWriter = createOutputStreamWriter(this.resource.getOutputStream(),
datumWriterForClass(this.clazz));
}
-
}
private static DatumWriter datumWriterForClass(Class clazz) {
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/AvroItemReaderBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/AvroItemReaderBuilder.java
index c9803e2590..eab6ee661e 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/AvroItemReaderBuilder.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/AvroItemReaderBuilder.java
@@ -18,6 +18,7 @@
import org.apache.avro.Schema;
+import org.jspecify.annotations.Nullable;
import org.springframework.batch.item.avro.AvroItemReader;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
@@ -29,6 +30,7 @@
*
* @author David Turanski
* @author Mahmoud Ben Hassine
+ * @author Stefano Cordio
* @since 4.2
*/
public class AvroItemReaderBuilder {
@@ -41,11 +43,11 @@ public class AvroItemReaderBuilder {
private int currentItemCount;
- private Resource schema;
+ private @Nullable Resource schema;
- private Resource resource;
+ private @Nullable Resource resource;
- private Class type;
+ private @Nullable Class type;
private boolean embeddedSchema = true;
@@ -162,10 +164,12 @@ public AvroItemReader build() {
Assert.notNull(this.resource, "A 'resource' is required.");
if (this.type != null) {
- avroItemReader = buildForType();
+ Assert.isNull(this.schema, "You cannot specify a schema and 'type'.");
+ avroItemReader = new AvroItemReader<>(this.resource, this.type);
}
else {
- avroItemReader = buildForSchema();
+ Assert.notNull(this.schema, "'schema' is required.");
+ avroItemReader = new AvroItemReader<>(this.resource, this.schema);
}
avroItemReader.setSaveState(this.saveState);
@@ -182,14 +186,4 @@ public AvroItemReader build() {
return avroItemReader;
}
- private AvroItemReader buildForType() {
- Assert.isNull(this.schema, "You cannot specify a schema and 'type'.");
- return new AvroItemReader<>(this.resource, this.type);
- }
-
- private AvroItemReader buildForSchema() {
- Assert.notNull(this.schema, "'schema' is required.");
- return new AvroItemReader<>(this.resource, this.schema);
- }
-
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/AvroItemWriterBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/AvroItemWriterBuilder.java
index 69c9eb85cc..7bd72ba3c8 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/AvroItemWriterBuilder.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/AvroItemWriterBuilder.java
@@ -16,6 +16,7 @@
package org.springframework.batch.item.avro.builder;
+import org.jspecify.annotations.Nullable;
import org.springframework.batch.item.avro.AvroItemWriter;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
@@ -27,15 +28,16 @@
*
* @author David Turanski
* @author Mahmoud Ben Hassine
+ * @author Stefano Cordio
* @since 4.2
*/
public class AvroItemWriterBuilder {
- private Class type;
+ private @Nullable Class type;
- private WritableResource resource;
+ private @Nullable WritableResource resource;
- private Resource schema;
+ private @Nullable Resource schema;
private String name = AvroItemWriter.class.getSimpleName();
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/package-info.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/package-info.java
new file mode 100644
index 0000000000..a24fd63cab
--- /dev/null
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/builder/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Builders for Avro item reader and writer.
+ *
+ * @author Stefano Cordio
+ */
+@NullMarked
+package org.springframework.batch.item.avro.builder;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/package-info.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/package-info.java
new file mode 100644
index 0000000000..78781b2c36
--- /dev/null
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/avro/package-info.java
@@ -0,0 +1,9 @@
+/**
+ * Avro related reader and writer.
+ *
+ * @author Stefano Cordio
+ */
+@NullMarked
+package org.springframework.batch.item.avro;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/AbstractPaginatedDataItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/AbstractPaginatedDataItemReader.java
index 043e54b7ba..eca601e1ad 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/AbstractPaginatedDataItemReader.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/AbstractPaginatedDataItemReader.java
@@ -18,13 +18,14 @@
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStreamReader;
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
-import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.util.Iterator;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import org.jspecify.annotations.Nullable;
+
/**
* A base class that handles basic reading logic based on the paginated semantics of
* Spring Data's paginated facilities. It also handles the semantics required for
@@ -35,6 +36,7 @@
* @author Michael Minella
* @author Glenn Renfro
* @author Mahmoud Ben Hassine
+ * @author Stefano Cordio
* @since 2.2
* @param Type of item to be read
*/
@@ -44,7 +46,7 @@ public abstract class AbstractPaginatedDataItemReader extends AbstractItemCou
protected int pageSize = 10;
- protected Iterator results;
+ protected @Nullable Iterator results;
private final Lock lock = new ReentrantLock();
@@ -57,9 +59,8 @@ public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
- @Nullable
@Override
- protected T doRead() throws Exception {
+ protected @Nullable T doRead() throws Exception {
this.lock.lock();
try {
@@ -69,17 +70,12 @@ protected T doRead() throws Exception {
page++;
- if (results == null || !results.hasNext()) {
+ if (!results.hasNext()) {
return null;
}
}
- if (results.hasNext()) {
- return results.next();
- }
- else {
- return null;
- }
+ return results.next();
}
finally {
this.lock.unlock();
@@ -91,8 +87,8 @@ protected T doRead() throws Exception {
* page. Each time this method is called, the resulting {@link Iterator} should
* contain the items read within the next page.
*
- * If the {@link Iterator} is empty or null when it is returned, this
- * {@link ItemReader} will assume that the input has been exhausted.
+ * If the {@link Iterator} is empty when it is returned, this {@link ItemReader} will
+ * assume that the input has been exhausted.
* @return an {@link Iterator} containing the items within a page.
*/
protected abstract Iterator doPageRead();
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/MongoCursorItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/MongoCursorItemReader.java
index 1759557d61..5fbfc5d3ed 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/MongoCursorItemReader.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/MongoCursorItemReader.java
@@ -25,6 +25,7 @@
import org.bson.Document;
import org.bson.codecs.DecoderContext;
+import org.jspecify.annotations.Nullable;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
import org.springframework.beans.factory.InitializingBean;
@@ -48,37 +49,36 @@
*/
public class MongoCursorItemReader extends AbstractItemCountingItemStreamItemReader implements InitializingBean {
- private MongoOperations template;
+ private @Nullable MongoOperations template;
- private Class extends T> targetType;
+ private @Nullable Class extends T> targetType;
- private String collection;
+ private @Nullable String collection;
- private Query query;
+ private @Nullable Query query;
- private String queryString;
+ private @Nullable String queryString;
private List