Use the Chunk API consistently

This commit replaces the usage of List with Chunk
where appropriate. Summary of changes:

- The Chunk class was moved from the `org.springframework.batch.core.step.item` package to the `org.springframework.batch.item` package
- The signature of the method `ItemWriter#write(List)` was changed to `ItemWriter#write(Chunk)`
- All implementations of `ItemWriter` were updated to use the Chunk API instead of List
- All methods in the `ItemWriteListener` interface were updated to use the Chunk API instead of List
- All implementations of `ItemWriteListener` were updated to use the Chunk API instead of List
- The constructor of `ChunkRequest` was changed to accept a Chunk instead of a Collection of items
- The return type of `ChunkRequest#getItems()` was changed from List to Chunk

Resolves #3954
This commit is contained in:
Mahmoud Ben Hassine
2022-08-17 21:06:09 +02:00
parent bf2e6ab0e5
commit e67c0069f1
175 changed files with 1077 additions and 763 deletions

View File

@@ -0,0 +1,264 @@
/*
* Copyright 2006-2022 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.
*/
package org.springframework.batch.item;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Encapsulation of a list of items to be processed and possibly a list of failed items to
* be skipped. To mark an item as skipped clients should iterate over the chunk using the
* {@link #iterator()} method, and if there is a failure call
* {@link Chunk.ChunkIterator#remove()} on the iterator. The skipped items are then
* available through the chunk.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
* @since 2.0
*/
public class Chunk<W> implements Iterable<W>, Serializable {
private List<W> items = new ArrayList<>();
private List<SkipWrapper<W>> skips = new ArrayList<>();
private List<Exception> errors = new ArrayList<>();
private Object userData;
private boolean end;
private boolean busy;
public Chunk(W... items) {
this(Arrays.stream(items).toList());
}
public static <W> Chunk<W> of(W... items) {
return new Chunk<>(items);
}
public Chunk(List<? extends W> items) {
this(items, null);
}
public Chunk(List<? extends W> items, List<SkipWrapper<W>> skips) {
super();
if (items != null) {
this.items = new ArrayList<>(items);
}
if (skips != null) {
this.skips = new ArrayList<>(skips);
}
}
/**
* Add the item to the chunk.
* @param item the item to add
*/
public void add(W item) {
items.add(item);
}
/**
* Add all items to the chunk.
* @param items the items to add
*/
public void addAll(List<W> items) {
this.items.addAll(items);
}
/**
* Clear the items down to signal that we are done.
*/
public void clear() {
items.clear();
skips.clear();
userData = null;
}
/**
* @return a copy of the items to be processed as an unmodifiable list
*/
public List<W> getItems() {
return Collections.unmodifiableList(new ArrayList<>(items));
}
/**
* @return a copy of the skips as an unmodifiable list
*/
public List<SkipWrapper<W>> getSkips() {
return Collections.unmodifiableList(skips);
}
/**
* @return a copy of the anonymous errors as an unmodifiable list
*/
public List<Exception> getErrors() {
return Collections.unmodifiableList(errors);
}
/**
* Register an anonymous skip. To skip an individual item, use
* {@link ChunkIterator#remove()}.
* @param e the exception that caused the skip
*/
public void skip(Exception e) {
errors.add(e);
}
/**
* @return true if there are no items in the chunk
*/
public boolean isEmpty() {
return items.isEmpty();
}
/**
* Get an unmodifiable iterator for the underlying items.
* @see java.lang.Iterable#iterator()
*/
@Override
public ChunkIterator iterator() {
return new ChunkIterator(items);
}
/**
* @return the number of items (excluding skips)
*/
public int size() {
return items.size();
}
/**
* Flag to indicate if the source data is exhausted.
* @return true if there is no more data to process
*/
public boolean isEnd() {
return end;
}
/**
* Set the flag to say that this chunk represents an end of stream (there is no more
* data to process).
*/
public void setEnd() {
this.end = true;
}
/**
* Query the chunk to see if anyone has registered an interest in keeping a reference
* to it.
* @return the busy flag
*/
public boolean isBusy() {
return busy;
}
/**
* Register an interest in the chunk to prevent it from being cleaned up before the
* flag is reset to false.
* @param busy the flag to set
*/
public void setBusy(boolean busy) {
this.busy = busy;
}
/**
* Clear only the skips list.
*/
public void clearSkips() {
skips.clear();
}
public Object getUserData() {
return userData;
}
public void setUserData(Object userData) {
this.userData = userData;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("[items=%s, skips=%s]", items, skips);
}
/**
* Special iterator for a chunk providing the {@link #remove(Throwable)} method for
* dynamically removing an item and adding it to the skips.
*
* @author Dave Syer
*
*/
public class ChunkIterator implements Iterator<W> {
final private Iterator<W> iterator;
private W next;
public ChunkIterator(List<W> items) {
iterator = items.iterator();
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public W next() {
next = iterator.next();
return next;
}
public void remove(Throwable e) {
remove();
skips.add(new SkipWrapper<>(next, e));
}
@Override
public void remove() {
if (next == null) {
if (iterator.hasNext()) {
next = iterator.next();
}
else {
return;
}
}
iterator.remove();
}
@Override
public String toString() {
return String.format("[items=%s, skips=%s]", items, skips);
}
}
}

View File

@@ -18,6 +18,8 @@ package org.springframework.batch.item;
import java.util.List;
import org.springframework.lang.NonNull;
/**
* <p>
* Basic interface for generic output operations. Class implementing this interface will
@@ -36,6 +38,7 @@ import java.util.List;
* @author Dave Syer
* @author Lucas Ward
* @author Taeik Lim
* @author Mahmoud Ben Hassine
*/
@FunctionalInterface
public interface ItemWriter<T> {
@@ -43,10 +46,10 @@ public interface ItemWriter<T> {
/**
* Process the supplied data element. Will not be called with any null items in normal
* operation.
* @param items items to be written
* @param chunk of items to be written. Must not be {@code null}.
* @throws Exception if there are errors. The framework will catch the exception and
* convert or rethrow it as appropriate.
*/
void write(List<? extends T> items) throws Exception;
void write(@NonNull Chunk<? extends T> chunk) throws Exception;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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
@@ -23,6 +23,7 @@ import org.springframework.util.Assert;
* a {@link Converter} to derive a key from an item
*
* @author David Turanski
* @author Mahmoud Ben Hassine
* @since 2.2
*
*/
@@ -38,7 +39,7 @@ public abstract class KeyValueItemWriter<K, V> implements ItemWriter<V>, Initial
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
*/
@Override
public void write(List<? extends V> items) throws Exception {
public void write(Chunk<? extends V> items) throws Exception {
if (items == null) {
return;
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2006-2022 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.
*/
package org.springframework.batch.item;
import org.springframework.lang.Nullable;
/**
* Wrapper for an item and its exception if it failed processing.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
*/
public class SkipWrapper<T> {
final private Throwable exception;
final private T item;
/**
* @param item the item being wrapped.
*/
public SkipWrapper(T item) {
this(item, null);
}
/**
* @param e instance of {@link Throwable} that being wrapped.
*/
public SkipWrapper(Throwable e) {
this(null, e);
}
public SkipWrapper(T item, @Nullable Throwable e) {
this.item = item;
this.exception = e;
}
/**
* Public getter for the exception.
* @return the exception
*/
@Nullable
public Throwable getException() {
return exception;
}
/**
* Public getter for the item.
* @return the item
*/
public T getItem() {
return item;
}
@Override
public String toString() {
return String.format("[exception=%s, item=%s]", exception, item);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2013 the original author or authors.
* Copyright 2006-2022 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,6 +18,7 @@ package org.springframework.batch.item.adapter;
import java.util.List;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
/**
@@ -26,11 +27,12 @@ import org.springframework.batch.item.ItemWriter;
*
* @see PropertyExtractingDelegatingItemWriter
* @author Robert Kasanicky
* @author Mahmoud Ben Hassine
*/
public class ItemWriterAdapter<T> extends AbstractMethodInvokingDelegator<T> implements ItemWriter<T> {
@Override
public void write(List<? extends T> items) throws Exception {
public void write(Chunk<? extends T> items) throws Exception {
for (T item : items) {
invokeDelegateMethodWithArgument(item);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2013 the original author or authors.
* Copyright 2006-2022 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.
@@ -19,6 +19,7 @@ package org.springframework.batch.item.adapter;
import java.util.Arrays;
import java.util.List;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
@@ -30,6 +31,7 @@ import org.springframework.util.Assert;
*
* @see ItemWriterAdapter
* @author Robert Kasanicky
* @author Mahmoud Ben Hassine
*/
public class PropertyExtractingDelegatingItemWriter<T> extends AbstractMethodInvokingDelegator<T>
implements ItemWriter<T> {
@@ -41,7 +43,7 @@ public class PropertyExtractingDelegatingItemWriter<T> extends AbstractMethodInv
* passes them as arguments to the delegate method.
*/
@Override
public void write(List<? extends T> items) throws Exception {
public void write(Chunk<? extends T> items) throws Exception {
for (T item : items) {
// helper for extracting property values from a bean

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2018 the original author or authors.
* Copyright 2012-2022 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.
@@ -19,6 +19,7 @@ package org.springframework.batch.item.amqp;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.util.Assert;
@@ -47,7 +48,7 @@ public class AmqpItemWriter<T> implements ItemWriter<T> {
}
@Override
public void write(final List<? extends T> items) throws Exception {
public void write(final Chunk<? extends T> items) throws Exception {
if (log.isDebugEnabled()) {
log.debug("Writing to AMQP with " + items.size() + " items.");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 the original author or authors.
* Copyright 2019-2022 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.
@@ -31,6 +31,7 @@ import org.apache.avro.reflect.ReflectDatumWriter;
import org.apache.avro.specific.SpecificDatumWriter;
import org.apache.avro.specific.SpecificRecordBase;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ItemWriter;
@@ -84,7 +85,7 @@ public class AvroItemWriter<T> extends AbstractItemStreamItemWriter<T> {
}
@Override
public void write(List<? extends T> items) throws Exception {
public void write(Chunk<? extends T> items) throws Exception {
items.forEach(item -> {
try {
if (this.dataFileWriter != null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@@ -22,6 +22,7 @@ import java.util.List;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.mongodb.core.BulkOperations;
@@ -113,39 +114,39 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
* If a transaction is active, buffer items to be written just before commit.
* Otherwise write items using the provided template.
*
* @see org.springframework.batch.item.ItemWriter#write(List)
* @see org.springframework.batch.item.ItemWriter#write(Chunk)
*/
@Override
public void write(List<? extends T> items) throws Exception {
public void write(Chunk<? extends T> chunk) throws Exception {
if (!transactionActive()) {
doWrite(items);
doWrite(chunk);
return;
}
List<T> bufferedItems = getCurrentBuffer();
bufferedItems.addAll(items);
Chunk bufferedItems = getCurrentBuffer();
bufferedItems.addAll(chunk.getItems());
}
/**
* Performs the actual write to the store via the template. This can be overridden by
* a subclass if necessary.
* @param items the list of items to be persisted.
* @param chunk the chunk of items to be persisted.
*/
protected void doWrite(List<? extends T> items) {
if (!CollectionUtils.isEmpty(items)) {
protected void doWrite(Chunk<? extends T> chunk) {
if (!CollectionUtils.isEmpty(chunk.getItems())) {
if (this.delete) {
delete(items);
delete(chunk);
}
else {
saveOrUpdate(items);
saveOrUpdate(chunk);
}
}
}
private void delete(List<? extends T> items) {
BulkOperations bulkOperations = initBulkOperations(BulkMode.ORDERED, items.get(0));
private void delete(Chunk<? extends T> chunk) {
BulkOperations bulkOperations = initBulkOperations(BulkMode.ORDERED, chunk.getItems().get(0));
MongoConverter mongoConverter = this.template.getConverter();
for (Object item : items) {
for (Object item : chunk) {
Document document = new Document();
mongoConverter.write(item, document);
Object objectId = document.get(ID_KEY);
@@ -157,11 +158,11 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
bulkOperations.execute();
}
private void saveOrUpdate(List<? extends T> items) {
BulkOperations bulkOperations = initBulkOperations(BulkMode.ORDERED, items.get(0));
private void saveOrUpdate(Chunk<? extends T> chunk) {
BulkOperations bulkOperations = initBulkOperations(BulkMode.ORDERED, chunk.getItems().get(0));
MongoConverter mongoConverter = this.template.getConverter();
FindAndReplaceOptions upsert = new FindAndReplaceOptions().upsert();
for (Object item : items) {
for (Object item : chunk) {
Document document = new Document();
mongoConverter.write(item, document);
Object objectId = document.get(ID_KEY) != null ? document.get(ID_KEY) : new ObjectId();
@@ -186,19 +187,18 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
return TransactionSynchronizationManager.isActualTransactionActive();
}
@SuppressWarnings("unchecked")
private List<T> getCurrentBuffer() {
private Chunk<T> getCurrentBuffer() {
if (!TransactionSynchronizationManager.hasResource(bufferKey)) {
TransactionSynchronizationManager.bindResource(bufferKey, new ArrayList<T>());
TransactionSynchronizationManager.bindResource(bufferKey, new Chunk<T>());
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void beforeCommit(boolean readOnly) {
List<T> items = (List<T>) TransactionSynchronizationManager.getResource(bufferKey);
Chunk<T> chunk = (Chunk<T>) TransactionSynchronizationManager.getResource(bufferKey);
if (!CollectionUtils.isEmpty(items)) {
if (!CollectionUtils.isEmpty(chunk.getItems())) {
if (!readOnly) {
doWrite(items);
doWrite(chunk);
}
}
}
@@ -212,7 +212,7 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
});
}
return (List<T>) TransactionSynchronizationManager.getResource(bufferKey);
return (Chunk<T>) TransactionSynchronizationManager.getResource(bufferKey);
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@@ -23,6 +23,7 @@ import org.apache.commons.logging.LogFactory;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
@@ -86,12 +87,12 @@ public class Neo4jItemWriter<T> implements ItemWriter<T>, InitializingBean {
/**
* Write all items to the data store.
*
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
* @see org.springframework.batch.item.ItemWriter#write(Chunk)
*/
@Override
public void write(List<? extends T> items) throws Exception {
if (!CollectionUtils.isEmpty(items)) {
doWrite(items);
public void write(Chunk<? extends T> chunk) throws Exception {
if (!CollectionUtils.isEmpty(chunk.getItems())) {
doWrite(chunk);
}
}
@@ -100,7 +101,7 @@ public class Neo4jItemWriter<T> implements ItemWriter<T>, InitializingBean {
* if necessary.
* @param items the list of items to be persisted.
*/
protected void doWrite(List<? extends T> items) {
protected void doWrite(Chunk<? extends T> items) {
if (delete) {
delete(items);
}
@@ -109,7 +110,7 @@ public class Neo4jItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
}
private void delete(List<? extends T> items) {
private void delete(Chunk<? extends T> items) {
Session session = this.sessionFactory.openSession();
for (T item : items) {
@@ -117,7 +118,7 @@ public class Neo4jItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
}
private void save(List<? extends T> items) {
private void save(Chunk<? extends T> items) {
Session session = this.sessionFactory.openSession();
for (T item : items) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2022 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.
@@ -20,6 +20,8 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.adapter.AbstractMethodInvokingDelegator.InvocationTargetThrowableWrapper;
import org.springframework.batch.item.adapter.DynamicMethodInvocationException;
@@ -87,12 +89,12 @@ public class RepositoryItemWriter<T> implements ItemWriter<T>, InitializingBean
/**
* Write all items to the data store via a Spring Data repository.
*
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
* @see org.springframework.batch.item.ItemWriter#write(Chunk)
*/
@Override
public void write(List<? extends T> items) throws Exception {
if (!CollectionUtils.isEmpty(items)) {
doWrite(items);
public void write(Chunk<? extends T> chunk) throws Exception {
if (!CollectionUtils.isEmpty(chunk.getItems())) {
doWrite(chunk);
}
}
@@ -102,7 +104,7 @@ public class RepositoryItemWriter<T> implements ItemWriter<T>, InitializingBean
* @param items the list of items to be persisted.
* @throws Exception thrown if error occurs during writing.
*/
protected void doWrite(List<? extends T> items) throws Exception {
protected void doWrite(Chunk<? extends T> items) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("Writing to the repository with " + items.size() + " items.");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2021 the original author or authors.
* Copyright 2006-2022 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.
@@ -23,6 +23,7 @@ import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.context.spi.CurrentSessionContext;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
@@ -81,10 +82,10 @@ public class HibernateItemWriter<T> implements ItemWriter<T>, InitializingBean {
* Save or update any entities not in the current hibernate session and then flush the
* hibernate session.
*
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
* @see org.springframework.batch.item.ItemWriter#write(Chunk)
*/
@Override
public void write(List<? extends T> items) {
public void write(Chunk<? extends T> items) {
doWrite(sessionFactory, items);
sessionFactory.getCurrentSession().flush();
if (clearSession) {
@@ -98,7 +99,7 @@ public class HibernateItemWriter<T> implements ItemWriter<T>, InitializingBean {
* @param sessionFactory Hibernate SessionFactory to be used
* @param items the list of items to use for the write
*/
protected void doWrite(SessionFactory sessionFactory, List<? extends T> items) {
protected void doWrite(SessionFactory sessionFactory, Chunk<? extends T> items) {
if (logger.isDebugEnabled()) {
logger.debug("Writing to Hibernate with " + items.size() + " items.");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2021 the original author or authors.
* Copyright 2006-2022 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.
@@ -25,6 +25,7 @@ import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
@@ -51,7 +52,7 @@ import org.springframework.util.Assert;
* be responsible for mapping the item to the parameters needed to execute the SQL
* statement.<br>
*
* It is expected that {@link #write(List)} is called inside a transaction.<br>
* It is expected that {@link #write(Chunk)} is called inside a transaction.<br>
*
* The writer is thread-safe after its properties are set (normal singleton behavior), so
* it can be used to write in multiple concurrent transactions.
@@ -59,6 +60,7 @@ import org.springframework.util.Assert;
* @author Dave Syer
* @author Thomas Risberg
* @author Michael Minella
* @author Mahmoud Ben Hassine
* @since 2.0
*/
public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
@@ -164,24 +166,25 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
*/
@SuppressWarnings("unchecked")
@Override
public void write(final List<? extends T> items) throws Exception {
public void write(final Chunk<? extends T> chunk) throws Exception {
if (!items.isEmpty()) {
if (!chunk.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Executing batch with " + items.size() + " items.");
logger.debug("Executing batch with " + chunk.size() + " items.");
}
int[] updateCounts;
if (usingNamedParameters) {
if (items.get(0) instanceof Map && this.itemSqlParameterSourceProvider == null) {
updateCounts = namedParameterJdbcTemplate.batchUpdate(sql, items.toArray(new Map[items.size()]));
if (chunk.getItems().get(0) instanceof Map && this.itemSqlParameterSourceProvider == null) {
updateCounts = namedParameterJdbcTemplate.batchUpdate(sql,
chunk.getItems().toArray(new Map[chunk.size()]));
}
else {
SqlParameterSource[] batchArgs = new SqlParameterSource[items.size()];
SqlParameterSource[] batchArgs = new SqlParameterSource[chunk.size()];
int i = 0;
for (T item : items) {
for (T item : chunk) {
batchArgs[i++] = itemSqlParameterSourceProvider.createSqlParameterSource(item);
}
updateCounts = namedParameterJdbcTemplate.batchUpdate(sql, batchArgs);
@@ -193,7 +196,7 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
@Override
public int[] doInPreparedStatement(PreparedStatement ps)
throws SQLException, DataAccessException {
for (T item : items) {
for (T item : chunk) {
itemPreparedStatementSetter.setValues(item, ps);
ps.addBatch();
}
@@ -207,7 +210,7 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
int value = updateCounts[i];
if (value == 0) {
throw new EmptyResultDataAccessException("Item " + i + " of " + updateCounts.length
+ " did not update any rows: [" + items.get(i) + "]", 1);
+ " did not update any rows: [" + chunk.getItems().get(i) + "]", 1);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2021 the original author or authors.
* Copyright 2006-2022 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,6 +18,8 @@ package org.springframework.batch.item.database;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessResourceFailureException;
@@ -32,7 +34,7 @@ import java.util.List;
* {@link org.springframework.batch.item.ItemWriter} that is using a JPA
* EntityManagerFactory to merge any Entities that aren't part of the persistence context.
*
* It is required that {@link #write(List)} is called inside a transaction.<br>
* It is required that {@link #write(Chunk)} is called inside a transaction.<br>
*
* The reader must be configured with an {@link jakarta.persistence.EntityManagerFactory}
* that is capable of participating in Spring managed transactions.
@@ -80,10 +82,10 @@ public class JpaItemWriter<T> implements ItemWriter<T>, InitializingBean {
* Merge all provided items that aren't already in the persistence context and then
* flush the entity manager.
*
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
* @see org.springframework.batch.item.ItemWriter#write(Chunk)
*/
@Override
public void write(List<? extends T> items) {
public void write(Chunk<? extends T> items) {
EntityManager entityManager = EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);
if (entityManager == null) {
throw new DataAccessResourceFailureException("Unable to obtain a transactional EntityManager");
@@ -98,7 +100,7 @@ public class JpaItemWriter<T> implements ItemWriter<T>, InitializingBean {
* @param entityManager the EntityManager to use for the operation
* @param items the list of items to use for the write
*/
protected void doWrite(EntityManager entityManager, List<? extends T> items) {
protected void doWrite(EntityManager entityManager, Chunk<? extends T> items) {
if (logger.isDebugEnabled()) {
logger.debug("Writing to JPA with " + items.size() + " items.");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2018 the original author or authors.
* Copyright 2006-2022 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,6 +18,7 @@ package org.springframework.batch.item.file;
import java.util.List;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.file.transform.LineAggregator;
import org.springframework.batch.item.support.AbstractFileItemWriter;
import org.springframework.core.io.Resource;
@@ -71,7 +72,7 @@ public class FlatFileItemWriter<T> extends AbstractFileItemWriter<T> {
}
@Override
public String doWrite(List<? extends T> items) {
public String doWrite(Chunk<? extends T> items) {
StringBuilder lines = new StringBuilder();
for (T item : items) {
lines.append(this.lineAggregator.aggregate(item)).append(this.lineSeparator);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2017 the original author or authors.
* Copyright 2006-2022 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.
@@ -19,6 +19,8 @@ package org.springframework.batch.item.file;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.support.AbstractItemStreamItemWriter;
@@ -39,6 +41,7 @@ import org.springframework.util.ClassUtils;
*
* @param <T> item type
* @author Robert Kasanicky
* @author Mahmoud Ben Hassine
*/
public class MultiResourceItemWriter<T> extends AbstractItemStreamItemWriter<T> {
@@ -67,7 +70,7 @@ public class MultiResourceItemWriter<T> extends AbstractItemStreamItemWriter<T>
}
@Override
public void write(List<? extends T> items) throws Exception {
public void write(Chunk<? extends T> items) throws Exception {
if (!opened) {
File file = setResourceToDelegate();
// create only if write is called

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2022 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,6 +18,8 @@ package org.springframework.batch.item.jms;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.jms.core.JmsOperations;
import org.springframework.jms.core.JmsTemplate;
@@ -27,13 +29,14 @@ import java.util.List;
/**
* An {@link ItemWriter} for JMS using a {@link JmsTemplate}. The template should have a
* default destination, which will be used to send items in {@link #write(List)}.<br>
* default destination, which will be used to send items in {@link #write(Chunk)}.<br>
* <br>
*
* The implementation is thread-safe after its properties are set (normal singleton
* behavior).
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
*/
public class JmsItemWriter<T> implements ItemWriter<T> {
@@ -58,10 +61,10 @@ public class JmsItemWriter<T> implements ItemWriter<T> {
/**
* Send the items one-by-one to the default destination of the JMS template.
*
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
* @see org.springframework.batch.item.ItemWriter#write(Chunk)
*/
@Override
public void write(List<? extends T> items) throws Exception {
public void write(Chunk<? extends T> items) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("Writing to JMS with " + items.size() + " items.");

View File

@@ -19,6 +19,7 @@ package org.springframework.batch.item.json;
import java.util.Iterator;
import java.util.List;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.support.AbstractFileItemWriter;
import org.springframework.core.io.WritableResource;
import org.springframework.util.Assert;
@@ -94,7 +95,7 @@ public class JsonFileItemWriter<T> extends AbstractFileItemWriter<T> {
}
@Override
public String doWrite(List<? extends T> items) {
public String doWrite(Chunk<? extends T> items) {
StringBuilder lines = new StringBuilder();
Iterator<? extends T> iterator = items.iterator();
if (!items.isEmpty() && state.getLinesWritten() > 0) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2010 the original author or authors.
* Copyright 2006-2022 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.
@@ -19,6 +19,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.mail.MailException;
@@ -50,6 +51,7 @@ import org.springframework.util.Assert;
* </p>
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
* @since 2.1
*
*/
@@ -60,7 +62,7 @@ public class SimpleMailMessageItemWriter implements ItemWriter<SimpleMailMessage
private MailErrorHandler mailErrorHandler = new DefaultMailErrorHandler();
/**
* A {@link MailSender} to be used to send messages in {@link #write(List)}.
* A {@link MailSender} to be used to send messages in {@link #write(Chunk)}.
* @param mailSender The {@link MailSender} to be used.
*/
public void setMailSender(MailSender mailSender) {
@@ -87,13 +89,13 @@ public class SimpleMailMessageItemWriter implements ItemWriter<SimpleMailMessage
}
/**
* @param items the items to send
* @see ItemWriter#write(List)
* @param chunk the chunk of items to send
* @see ItemWriter#write(Chunk)
*/
@Override
public void write(List<? extends SimpleMailMessage> items) throws MailException {
public void write(Chunk<? extends SimpleMailMessage> chunk) throws MailException {
try {
mailSender.send(items.toArray(new SimpleMailMessage[items.size()]));
mailSender.send(chunk.getItems().toArray(new SimpleMailMessage[chunk.size()]));
}
catch (MailSendException e) {
Map<Object, Exception> failedMessages = e.getFailedMessages();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2017-2022 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.
@@ -28,6 +28,7 @@ import org.springframework.util.Assert;
* Creates a fully qualified SimpleMailMessageItemWriter.
*
* @author Glenn Renfro
* @author Mahmoud Ben Hassine
* @since 4.0
*/
@@ -39,7 +40,7 @@ public class SimpleMailMessageItemWriterBuilder {
/**
* A {@link MailSender} to be used to send messages in
* {@link SimpleMailMessageItemWriter#write(List)}.
* {@link SimpleMailMessageItemWriter#write(Chunk)}.
* @param mailSender strategy for sending simple mails.
* @return this instance for method chaining.
* @see SimpleMailMessageItemWriter#setMailSender(MailSender)

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2021 the original author or authors.
* Copyright 2006-2022 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.
@@ -15,6 +15,7 @@
*/
package org.springframework.batch.item.mail.javamail;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.mail.DefaultMailErrorHandler;
import org.springframework.batch.item.mail.MailErrorHandler;
@@ -64,7 +65,7 @@ public class MimeMessageItemWriter implements ItemWriter<MimeMessage> {
private MailErrorHandler mailErrorHandler = new DefaultMailErrorHandler();
/**
* A {@link JavaMailSender} to be used to send messages in {@link #write(List)}.
* A {@link JavaMailSender} to be used to send messages in {@link #write(Chunk)}.
* @param mailSender service for doing the work of sending a MIME message
*/
public void setJavaMailSender(JavaMailSender mailSender) {
@@ -90,13 +91,13 @@ public class MimeMessageItemWriter implements ItemWriter<MimeMessage> {
}
/**
* @param items the items to send
* @see ItemWriter#write(List)
* @param chunk the chunk of items to send
* @see ItemWriter#write(Chunk)
*/
@Override
public void write(List<? extends MimeMessage> items) throws MailException {
public void write(Chunk<? extends MimeMessage> chunk) throws MailException {
try {
mailSender.send(items.toArray(new MimeMessage[items.size()]));
mailSender.send(chunk.getItems().toArray(new MimeMessage[chunk.size()]));
}
catch (MailSendException e) {
Map<Object, Exception> failedMessages = e.getFailedMessages();

View File

@@ -31,6 +31,7 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
@@ -220,7 +221,7 @@ public abstract class AbstractFileItemWriter<T> extends AbstractItemStreamItemWr
* @throws Exception if an error occurs while writing items to the output stream
*/
@Override
public void write(List<? extends T> items) throws Exception {
public void write(Chunk<? extends T> items) throws Exception {
if (!getOutputState().isInitialized()) {
throw new WriterNotOpenException("Writer must be open before it can be written to");
}
@@ -247,7 +248,7 @@ public abstract class AbstractFileItemWriter<T> extends AbstractItemStreamItemWr
* @param items to be written
* @return written lines
*/
protected abstract String doWrite(List<? extends T> items);
protected abstract String doWrite(Chunk<? extends T> items);
/**
* @see ItemStream#close()

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2007 the original author or authors.
* Copyright 2006-2022 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.
@@ -21,6 +21,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.batch.item.Chunk;
import org.springframework.classify.Classifier;
import org.springframework.classify.ClassifierSupport;
import org.springframework.batch.item.ItemWriter;
@@ -34,6 +35,7 @@ import org.springframework.util.Assert;
*
* @author Dave Syer
* @author Glenn Renfro
* @author Mahmoud Ben Hassine
* @since 2.0
*/
public class ClassifierCompositeItemWriter<T> implements ItemWriter<T> {
@@ -53,14 +55,14 @@ public class ClassifierCompositeItemWriter<T> implements ItemWriter<T> {
* classification by the {@link Classifier}.
*/
@Override
public void write(List<? extends T> items) throws Exception {
public void write(Chunk<? extends T> items) throws Exception {
Map<ItemWriter<? super T>, List<T>> map = new LinkedHashMap<>();
Map<ItemWriter<? super T>, Chunk<T>> map = new LinkedHashMap<>();
for (T item : items) {
ItemWriter<? super T> key = classifier.classify(item);
if (!map.containsKey(key)) {
map.put(key, new ArrayList<>());
map.put(key, new Chunk<>());
}
map.get(key).add(item);
}

View File

@@ -16,6 +16,7 @@
package org.springframework.batch.item.support;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
@@ -35,6 +36,7 @@ import java.util.List;
*
* @author Robert Kasanicky
* @author Dave Syer
* @author Mahmoud Ben Hassine
*/
public class CompositeItemWriter<T> implements ItemStreamWriter<T>, InitializingBean {
@@ -78,9 +80,9 @@ public class CompositeItemWriter<T> implements ItemStreamWriter<T>, Initializing
}
@Override
public void write(List<? extends T> item) throws Exception {
public void write(Chunk<? extends T> chunk) throws Exception {
for (ItemWriter<? super T> writer : delegates) {
writer.write(item);
writer.write(chunk);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2022 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.
@@ -15,6 +15,7 @@
*/
package org.springframework.batch.item.support;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import java.util.ArrayList;
@@ -22,14 +23,15 @@ import java.util.List;
/**
* @author mminella
* @author Mahmoud Ben Hassine
*/
public class ListItemWriter<T> implements ItemWriter<T> {
private List<T> writtenItems = new ArrayList<>();
@Override
public void write(List<? extends T> items) throws Exception {
writtenItems.addAll(items);
public void write(Chunk<? extends T> chunk) throws Exception {
writtenItems.addAll(chunk.getItems());
}
public List<? extends T> getWrittenItems() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2022 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.
@@ -15,6 +15,7 @@
*/
package org.springframework.batch.item.support;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ItemStreamWriter;
@@ -60,7 +61,7 @@ public class SynchronizedItemStreamWriter<T> implements ItemStreamWriter<T>, Ini
* This method delegates to the {@code write} method of the {@code delegate}.
*/
@Override
public synchronized void write(List<? extends T> items) throws Exception {
public synchronized void write(Chunk<? extends T> items) throws Exception {
this.delegate.write(items);
}

View File

@@ -38,6 +38,7 @@ import javax.xml.transform.Result;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ItemWriter;
@@ -761,7 +762,7 @@ public class StaxEventItemWriter<T> extends AbstractItemStreamItemWriter<T>
* @throws XmlMappingException thrown if error occurs during XML Mapping.
*/
@Override
public void write(List<? extends T> items) throws XmlMappingException, IOException {
public void write(Chunk<? extends T> items) throws XmlMappingException, IOException {
if (!this.initialized) {
throw new WriterNotOpenException("Writer must be open before it can be written to");