Apply spring-javaformat style for consistency with other projects

Resolves #4118
This commit is contained in:
Mahmoud Ben Hassine
2022-05-25 17:47:13 +02:00
parent b3fe088879
commit c4ad90b9b1
1626 changed files with 44478 additions and 45612 deletions

View File

@@ -25,12 +25,12 @@ import java.util.concurrent.ConcurrentHashMap;
import org.springframework.lang.Nullable;
/**
* Object representing a context for an {@link ItemStream}. It is a thin wrapper
* for a map that allows optionally for type safety on reads. It also allows for
* dirty checking by setting a 'dirty' flag whenever any put is called.
* Object representing a context for an {@link ItemStream}. It is a thin wrapper for a map
* that allows optionally for type safety on reads. It also allows for dirty checking by
* setting a 'dirty' flag whenever any put is called.
*
* Note that putting <code>null</code> value is equivalent to removing the entry
* for the given key.
* Note that putting <code>null</code> value is equivalent to removing the entry for the
* given key.
*
* @author Lucas Ward
* @author Douglas Kaminsky
@@ -44,8 +44,8 @@ public class ExecutionContext implements Serializable {
private final Map<String, Object> map;
/**
* Default constructor. Initializes a new execution context with an empty
* internal map.
* Default constructor. Initializes a new execution context with an empty internal
* map.
*/
public ExecutionContext() {
this.map = new ConcurrentHashMap<>();
@@ -53,7 +53,6 @@ public class ExecutionContext implements Serializable {
/**
* Initializes a new execution context with the contents of another map.
*
* @param map Initial contents of context.
*/
public ExecutionContext(Map<String, Object> map) {
@@ -63,8 +62,8 @@ public class ExecutionContext implements Serializable {
/**
* Initializes a new {@link ExecutionContext} with the contents of another
* {@code ExecutionContext}.
*
* @param executionContext containing the entries to be copied to this current context.
* @param executionContext containing the entries to be copied to this current
* context.
*/
public ExecutionContext(ExecutionContext executionContext) {
this();
@@ -77,9 +76,8 @@ public class ExecutionContext implements Serializable {
}
/**
* Adds a String value to the context. Putting <code>null</code>
* value for a given key removes the key.
*
* Adds a String value to the context. Putting <code>null</code> value for a given key
* removes the key.
* @param key Key to add to context
* @param value Value to associate with key
*/
@@ -91,7 +89,6 @@ public class ExecutionContext implements Serializable {
/**
* Adds a Long value to the context.
*
* @param key Key to add to context
* @param value Value to associate with key
*/
@@ -102,7 +99,6 @@ public class ExecutionContext implements Serializable {
/**
* Adds an Integer value to the context.
*
* @param key Key to add to context
* @param value Value to associate with key
*/
@@ -112,7 +108,6 @@ public class ExecutionContext implements Serializable {
/**
* Add a Double value to the context.
*
* @param key Key to add to context
* @param value Value to associate with key
*/
@@ -122,28 +117,26 @@ public class ExecutionContext implements Serializable {
}
/**
* Add an Object value to the context. Putting <code>null</code>
* value for a given key removes the key.
*
* Add an Object value to the context. Putting <code>null</code> value for a given key
* removes the key.
* @param key Key to add to context
* @param value Value to associate with key
*/
public void put(String key, @Nullable Object value) {
if (value != null) {
Object result = this.map.put(key, value);
this.dirty = result==null || result!=null && !result.equals(value);
this.dirty = result == null || result != null && !result.equals(value);
}
else {
Object result = this.map.remove(key);
this.dirty = result!=null;
this.dirty = result != null;
}
}
/**
* Indicates if context has been changed with a "put" operation since the
* dirty flag was last cleared. Note that the last time the flag was cleared
* might correspond to creation of the context.
*
* Indicates if context has been changed with a "put" operation since the dirty flag
* was last cleared. Note that the last time the flag was cleared might correspond to
* creation of the context.
* @return True if "put" operation has occurred since flag was last cleared
*/
public boolean isDirty() {
@@ -152,7 +145,6 @@ public class ExecutionContext implements Serializable {
/**
* Typesafe Getter for the String represented by the provided key.
*
* @param key The key to get a value for
* @return The <code>String</code> value
*/
@@ -162,13 +154,12 @@ public class ExecutionContext implements Serializable {
}
/**
* Typesafe Getter for the String represented by the provided key with
* default value to return if key is not represented.
*
* Typesafe Getter for the String represented by the provided key with default value
* to return if key is not represented.
* @param key The key to get a value for
* @param defaultString Default to return if key is not represented
* @return The <code>String</code> value if key is represented, specified
* default otherwise
* @return The <code>String</code> value if key is represented, specified default
* otherwise
*/
public String getString(String key, String defaultString) {
if (!containsKey(key)) {
@@ -180,7 +171,6 @@ public class ExecutionContext implements Serializable {
/**
* Typesafe Getter for the Long represented by the provided key.
*
* @param key The key to get a value for
* @return The <code>Long</code> value
*/
@@ -190,13 +180,12 @@ public class ExecutionContext implements Serializable {
}
/**
* Typesafe Getter for the Long represented by the provided key with default
* value to return if key is not represented.
*
* Typesafe Getter for the Long represented by the provided key with default value to
* return if key is not represented.
* @param key The key to get a value for
* @param defaultLong Default to return if key is not represented
* @return The <code>long</code> value if key is represented, specified
* default otherwise
* @return The <code>long</code> value if key is represented, specified default
* otherwise
*/
public long getLong(String key, long defaultLong) {
if (!containsKey(key)) {
@@ -208,7 +197,6 @@ public class ExecutionContext implements Serializable {
/**
* Typesafe Getter for the Integer represented by the provided key.
*
* @param key The key to get a value for
* @return The <code>Integer</code> value
*/
@@ -218,13 +206,12 @@ public class ExecutionContext implements Serializable {
}
/**
* Typesafe Getter for the Integer represented by the provided key with
* default value to return if key is not represented.
*
* Typesafe Getter for the Integer represented by the provided key with default value
* to return if key is not represented.
* @param key The key to get a value for
* @param defaultInt Default to return if key is not represented
* @return The <code>int</code> value if key is represented, specified
* default otherwise
* @return The <code>int</code> value if key is represented, specified default
* otherwise
*/
public int getInt(String key, int defaultInt) {
if (!containsKey(key)) {
@@ -236,7 +223,6 @@ public class ExecutionContext implements Serializable {
/**
* Typesafe Getter for the Double represented by the provided key.
*
* @param key The key to get a value for
* @return The <code>Double</code> value
*/
@@ -245,13 +231,12 @@ public class ExecutionContext implements Serializable {
}
/**
* Typesafe Getter for the Double represented by the provided key with
* default value to return if key is not represented.
*
* Typesafe Getter for the Double represented by the provided key with default value
* to return if key is not represented.
* @param key The key to get a value for
* @param defaultDouble Default to return if key is not represented
* @return The <code>double</code> value if key is represented, specified
* default otherwise
* @return The <code>double</code> value if key is represented, specified default
* otherwise
*/
public double getDouble(String key, double defaultDouble) {
if (!containsKey(key)) {
@@ -263,10 +248,9 @@ public class ExecutionContext implements Serializable {
/**
* Getter for the value represented by the provided key.
*
* @param key The key to get a value for
* @return The value represented by the given key or {@code null} if the key
* is not present
* @return The value represented by the given key or {@code null} if the key is not
* present
*/
@Nullable
public Object get(String key) {
@@ -274,9 +258,8 @@ public class ExecutionContext implements Serializable {
}
/**
* Utility method that attempts to take a value represented by a given key
* and validate it as a member of the specified type.
*
* Utility method that attempts to take a value represented by a given key and
* validate it as a member of the specified type.
* @param key The key to validate a value for
* @param type Class against which value should be validated
* @return Value typed to the specified <code>Class</code>
@@ -295,7 +278,6 @@ public class ExecutionContext implements Serializable {
/**
* Indicates whether or not the context is empty.
*
* @return True if the context has no entries, false otherwise.
* @see java.util.Map#isEmpty()
*/
@@ -312,7 +294,6 @@ public class ExecutionContext implements Serializable {
/**
* Returns the entry set containing the contents of this context.
*
* @return A set representing the contents of the context
* @see java.util.Map#entrySet()
*/
@@ -322,7 +303,6 @@ public class ExecutionContext implements Serializable {
/**
* Indicates whether or not a key is represented in this context.
*
* @param key Key to check existence for
* @return True if key is represented in context, false otherwise
* @see java.util.Map#containsKey(Object)
@@ -333,7 +313,6 @@ public class ExecutionContext implements Serializable {
/**
* Removes the mapping for a key from this context if it is present.
*
* @param key {@link String} that identifies the entry to be removed from the context.
* @return the value that was removed from the context.
*
@@ -346,7 +325,6 @@ public class ExecutionContext implements Serializable {
/**
* Indicates whether or not a value is represented in this context.
*
* @param value Value to check existence for
* @return True if value is represented in context, false otherwise
* @see java.util.Map#containsValue(Object)
@@ -394,7 +372,6 @@ public class ExecutionContext implements Serializable {
/**
* Returns number of entries in the context
*
* @return Number of entries in the context
* @see java.util.Map#size()
*/

View File

@@ -1,34 +1,34 @@
/*
* Copyright 20013 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.batch.item.support.AbstractItemCountingItemStreamItemReader;
/**
* Marker interface indicating that an item should have the item count set on it. Typically used within
* an {@link AbstractItemCountingItemStreamItemReader}.
*
* @author Jimmy Praet
*/
public interface ItemCountAware {
/**
* Setter for the injection of the current item count.
*
* @param count the number of items that have been processed in this execution.
*/
void setItemCount(int count);
}
/*
* Copyright 20013 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.batch.item.support.AbstractItemCountingItemStreamItemReader;
/**
* Marker interface indicating that an item should have the item count set on it.
* Typically used within an {@link AbstractItemCountingItemStreamItemReader}.
*
* @author Jimmy Praet
*/
public interface ItemCountAware {
/**
* Setter for the injection of the current item count.
* @param count the number of items that have been processed in this execution.
*/
void setItemCount(int count);
}

View File

@@ -20,37 +20,38 @@ import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
/**
* Interface for item transformation. Given an item as input, this interface provides
* an extension point which allows for the application of business logic in an item
* oriented processing scenario. It should be noted that while it's possible to return
* a different type than the one provided, it's not strictly necessary. Furthermore,
* returning {@code null} indicates that the item should not be continued to be processed.
*
* Interface for item transformation. Given an item as input, this interface provides an
* extension point which allows for the application of business logic in an item oriented
* processing scenario. It should be noted that while it's possible to return a different
* type than the one provided, it's not strictly necessary. Furthermore, returning
* {@code null} indicates that the item should not be continued to be processed.
*
* @author Robert Kasanicky
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
* @param <I> type of input item
* @param <O> type of output item
*/
public interface ItemProcessor<I, O> {
/**
* Process the provided item, returning a potentially modified or new item for continued
* processing. If the returned result is {@code null}, it is assumed that processing of the item
* should not continue.
*
* A {@code null} item will never reach this method because the only possible sources are:
* Process the provided item, returning a potentially modified or new item for
* continued processing. If the returned result is {@code null}, it is assumed that
* processing of the item should not continue.
*
* A {@code null} item will never reach this method because the only possible sources
* are:
* <ul>
* <li>an {@link ItemReader} (which indicates no more items)</li>
* <li>a previous {@link ItemProcessor} in a composite processor (which indicates a filtered item)</li>
* <li>an {@link ItemReader} (which indicates no more items)</li>
* <li>a previous {@link ItemProcessor} in a composite processor (which indicates a
* filtered item)</li>
* </ul>
*
* @param item to be processed, never {@code null}.
* @return potentially modified or new item for continued processing, {@code null} if processing of the
* provided item should not continue.
* @return potentially modified or new item for continued processing, {@code null} if
* processing of the provided item should not continue.
* @throws Exception thrown if exception occurs during processing.
*/
@Nullable
O process(@NonNull I item) throws Exception;
}

View File

@@ -20,17 +20,17 @@ import org.springframework.lang.Nullable;
/**
* Strategy interface for providing the data. <br>
*
* Implementations are expected to be stateful and will be called multiple times
* for each batch, with each call to {@link #read()} returning a different value
* and finally returning <code>null</code> when all input data is exhausted.<br>
*
* Implementations need <b>not</b> be thread-safe and clients of a {@link ItemReader}
* need to be aware that this is the case.<br>
*
* A richer interface (e.g. with a look ahead or peek) is not feasible because
* we need to support transactions in an asynchronous batch.
*
*
* Implementations are expected to be stateful and will be called multiple times for each
* batch, with each call to {@link #read()} returning a different value and finally
* returning <code>null</code> when all input data is exhausted.<br>
*
* Implementations need <b>not</b> be thread-safe and clients of a {@link ItemReader} need
* to be aware that this is the case.<br>
*
* A richer interface (e.g. with a look ahead or peek) is not feasible because we need to
* support transactions in an asynchronous batch.
*
* @author Rob Harrop
* @author Dave Syer
* @author Lucas Ward
@@ -41,22 +41,19 @@ public interface ItemReader<T> {
/**
* Reads a piece of input data and advance to the next one. Implementations
* <strong>must</strong> return <code>null</code> at the end of the input
* data set. In a transactional setting, caller might get the same item
* twice from successive calls (or otherwise), if the first call was in a
* transaction that rolled back.
*
* @throws ParseException if there is a problem parsing the current record
* (but the next one may still be valid)
* @throws NonTransientResourceException if there is a fatal exception in
* the underlying resource. After throwing this exception implementations
* should endeavour to return null from subsequent calls to read.
* @throws UnexpectedInputException if there is an uncategorised problem
* with the input data. Assume potentially transient, so subsequent calls to
* read might succeed.
* <strong>must</strong> return <code>null</code> at the end of the input data set. In
* a transactional setting, caller might get the same item twice from successive calls
* (or otherwise), if the first call was in a transaction that rolled back.
* @throws ParseException if there is a problem parsing the current record (but the
* next one may still be valid)
* @throws NonTransientResourceException if there is a fatal exception in the
* underlying resource. After throwing this exception implementations should endeavour
* to return null from subsequent calls to read.
* @throws UnexpectedInputException if there is an uncategorised problem with the
* input data. Assume potentially transient, so subsequent calls to read might
* succeed.
* @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
* @return T the item to be processed or {@code null} if the data source is exhausted
*/
@Nullable
T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException;

View File

@@ -18,7 +18,7 @@ package org.springframework.batch.item;
/**
* A base exception class that all exceptions thrown from an {@link ItemReader} extend.
*
*
* @author Ben Hale
*/
@SuppressWarnings("serial")
@@ -26,7 +26,6 @@ public abstract class ItemReaderException extends RuntimeException {
/**
* Create a new {@link ItemReaderException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
@@ -36,7 +35,6 @@ public abstract class ItemReaderException extends RuntimeException {
/**
* Create a new {@link ItemReaderException} based on a message.
*
* @param message the message for this exception
*/
public ItemReaderException(String message) {

View File

@@ -18,38 +18,40 @@ package org.springframework.batch.item;
/**
* <p>
* Marker interface defining a contract for periodically storing state and restoring from that state should an error
* occur.
* Marker interface defining a contract for periodically storing state and restoring from
* that state should an error occur.
* </p>
*
*
* @author Dave Syer
* @author Lucas Ward
* @author Mahmoud Ben Hassine
*
*
*/
public interface ItemStream {
/**
* Open the stream for the provided {@link ExecutionContext}.
*
* @param executionContext current step's {@link org.springframework.batch.item.ExecutionContext}. Will be the
* executionContext from the last run of the step on a restart.
* @param executionContext current step's
* {@link org.springframework.batch.item.ExecutionContext}. Will be the
* executionContext from the last run of the step on a restart.
* @throws IllegalArgumentException if context is null
*/
void open(ExecutionContext executionContext) throws ItemStreamException;
/**
* Indicates that the execution context provided during open is about to be saved. If any state is remaining, but
* has not been put in the context, it should be added here.
*
* Indicates that the execution context provided during open is about to be saved. If
* any state is remaining, but has not been put in the context, it should be added
* here.
* @param executionContext to be updated
* @throws IllegalArgumentException if executionContext is null.
*/
void update(ExecutionContext executionContext) throws ItemStreamException;
/**
* If any resources are needed for the stream to operate they need to be destroyed here. Once this method has been
* called all other methods (except open) may throw an exception.
* If any resources are needed for the stream to operate they need to be destroyed
* here. Once this method has been called all other methods (except open) may throw an
* exception.
*/
void close() throws ItemStreamException;
}

View File

@@ -17,7 +17,7 @@ package org.springframework.batch.item;
/**
* Exception representing any errors encountered while processing a stream.
*
*
* @author Dave Syer
* @author Lucas Ward
*/
@@ -33,10 +33,9 @@ public class ItemStreamException extends RuntimeException {
/**
* Constructs a new instance with a message and nested exception.
*
* @param msg the exception message.
* @param nested the cause of the exception.
*
*
*/
public ItemStreamException(String msg, Throwable nested) {
super(msg, nested);
@@ -44,10 +43,10 @@ public class ItemStreamException extends RuntimeException {
/**
* Constructs a new instance with a nested exception and empty message.
*
* @param nested the cause of the exception.
*/
public ItemStreamException(Throwable nested) {
super(nested);
}
}

View File

@@ -1,26 +1,26 @@
/*
* Copyright 2006-2007 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;
/**
* Convenience interface that combines {@link ItemStream} and {@link ItemReader}
* .
* @author Dave Syer
*
*/
public interface ItemStreamReader<T> extends ItemStream, ItemReader<T> {
}
/*
* Copyright 2006-2007 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;
/**
* Convenience interface that combines {@link ItemStream} and {@link ItemReader} .
*
* @author Dave Syer
*
*/
public interface ItemStreamReader<T> extends ItemStream, ItemReader<T> {
}

View File

@@ -51,12 +51,11 @@ public abstract class ItemStreamSupport implements ItemStream {
@Override
public void update(ExecutionContext executionContext) {
}
/**
* The name of the component which will be used as a stem for keys in the
* {@link ExecutionContext}. Subclasses should provide a default value, e.g.
* the short form of the class name.
*
* {@link ExecutionContext}. Subclasses should provide a default value, e.g. the short
* form of the class name.
* @param name the name for the component
*/
public void setName(String name) {

View File

@@ -1,26 +1,26 @@
/*
* Copyright 2006-2007 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;
/**
* Convenience interface that combines {@link ItemStream} and {@link ItemWriter}
* .
* @author Dave Syer
*
*/
public interface ItemStreamWriter<T> extends ItemStream, ItemWriter<T> {
}
/*
* Copyright 2006-2007 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;
/**
* Convenience interface that combines {@link ItemStream} and {@link ItemWriter} .
*
* @author Dave Syer
*
*/
public interface ItemStreamWriter<T> extends ItemStream, ItemWriter<T> {
}

View File

@@ -20,31 +20,30 @@ import java.util.List;
/**
* <p>
* Basic interface for generic output operations. Class implementing this
* interface will be responsible for serializing objects as necessary.
* Generally, it is responsibility of implementing class to decide which
* technology to use for mapping and how it should be configured.
* Basic interface for generic output operations. Class implementing this interface will
* be responsible for serializing objects as necessary. Generally, it is responsibility of
* implementing class to decide which technology to use for mapping and how it should be
* configured.
* </p>
*
*
* <p>
* The write method is responsible for making sure that any internal buffers are
* flushed. If a transaction is active it will also usually be necessary to
* discard the output on a subsequent rollback. The resource to which the writer
* is sending data should normally be able to handle this itself.
* The write method is responsible for making sure that any internal buffers are flushed.
* If a transaction is active it will also usually be necessary to discard the output on a
* subsequent rollback. The resource to which the writer is sending data should normally
* be able to handle this itself.
* </p>
*
*
* @author Dave Syer
* @author Lucas Ward
*/
public interface ItemWriter<T> {
/**
* Process the supplied data element. Will not be called with any null items
* in normal operation.
*
* Process the supplied data element. Will not be called with any null items in normal
* operation.
* @param items items to be written
* @throws Exception if there are errors. The framework will catch the
* exception and convert or rethrow it as appropriate.
* @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;

View File

@@ -18,7 +18,7 @@ package org.springframework.batch.item;
/**
* A base exception class that all exceptions thrown from an {@link ItemWriter} extend.
*
*
* @author Ben Hale
*/
@SuppressWarnings("serial")
@@ -26,7 +26,6 @@ public abstract class ItemWriterException extends RuntimeException {
/**
* Create a new {@link ItemWriterException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
@@ -36,7 +35,6 @@ public abstract class ItemWriterException extends RuntimeException {
/**
* Create a new {@link ItemWriterException} based on a message.
*
* @param message the message for this exception
*/
public ItemWriterException(String message) {

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2021 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.
@@ -19,9 +19,9 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.util.Assert;
/**
* A base class to implement any {@link ItemWriter} that writes to a key value store
* using a {@link Converter} to derive a key from an item
*
* A base class to implement any {@link ItemWriter} that writes to a key value store using
* a {@link Converter} to derive a key from an item
*
* @author David Turanski
* @since 2.2
*
@@ -29,9 +29,12 @@ import org.springframework.util.Assert;
public abstract class KeyValueItemWriter<K, V> implements ItemWriter<V>, InitializingBean {
protected Converter<V, K> itemKeyMapper;
protected boolean delete;
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
*/
@Override
@@ -48,10 +51,10 @@ public abstract class KeyValueItemWriter<K, V> implements ItemWriter<V>, Initial
/**
* Flush items to the key/value store.
*
* @throws Exception if unable to flush items
*/
protected void flush() throws Exception {}
protected void flush() throws Exception {
}
/**
* Subclasses implement this method to write each item to key value store
@@ -67,7 +70,6 @@ public abstract class KeyValueItemWriter<K, V> implements ItemWriter<V>, Initial
/**
* Set the {@link Converter} to use to derive the key from the item
*
* @param itemKeyMapper the {@link Converter} used to derive a key from an item.
*/
public void setItemKeyMapper(Converter<V, K> itemKeyMapper) {
@@ -76,15 +78,16 @@ public abstract class KeyValueItemWriter<K, V> implements ItemWriter<V>, Initial
/**
* Sets the delete flag to have the item writer perform deletes
*
* @param delete if true {@link ItemWriter} will perform deletes,
* if false not to perform deletes.
* @param delete if true {@link ItemWriter} will perform deletes, if false not to
* perform deletes.
*/
public void setDelete(boolean delete) {
this.delete = delete;
}
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
@@ -92,4 +95,5 @@ public abstract class KeyValueItemWriter<K, V> implements ItemWriter<V>, Initial
Assert.notNull(itemKeyMapper, "itemKeyMapper requires a Converter type.");
init();
}
}

View File

@@ -16,18 +16,17 @@
package org.springframework.batch.item;
/**
* Exception indicating that an error has been encountered doing I/O from a
* reader, and the exception should be considered fatal.
*
* Exception indicating that an error has been encountered doing I/O from a reader, and
* the exception should be considered fatal.
*
* @author Dave Syer
*/
@SuppressWarnings("serial")
public class NonTransientResourceException extends ItemReaderException {
/**
* Create a new {@link NonTransientResourceException} based on a message and
* another exception.
*
* Create a new {@link NonTransientResourceException} based on a message and another
* exception.
* @param message the message for this exception
* @param cause the other exception
*/
@@ -37,7 +36,6 @@ public class NonTransientResourceException extends ItemReaderException {
/**
* Create a new {@link NonTransientResourceException} based on a message.
*
* @param message the message for this exception
*/
public NonTransientResourceException(String message) {

View File

@@ -16,8 +16,9 @@
package org.springframework.batch.item;
/**
* Exception indicating that an error has been encountered parsing IO, typically from a file.
*
* Exception indicating that an error has been encountered parsing IO, typically from a
* file.
*
* @author Lucas Ward
* @author Ben Hale
*/
@@ -26,7 +27,6 @@ public class ParseException extends ItemReaderException {
/**
* Create a new {@link ParseException} based on a message and another exception.
*
* @param message the message for this exception
* @param cause the other exception
*/
@@ -36,7 +36,6 @@ public class ParseException extends ItemReaderException {
/**
* Create a new {@link ParseException} based on a message.
*
* @param message the message for this exception
*/
public ParseException(String message) {

View File

@@ -19,31 +19,29 @@ import org.springframework.lang.Nullable;
/**
* <p>
* A specialisation of {@link ItemReader} that allows the user to look ahead
* into the stream of items. This is useful, for instance, when reading flat
* file data that contains record separator lines which are actually part of the
* next record.
* A specialisation of {@link ItemReader} that allows the user to look ahead into the
* stream of items. This is useful, for instance, when reading flat file data that
* contains record separator lines which are actually part of the next record.
* </p>
*
*
* <p>
* The detailed contract for {@link #peek()} has to be defined by the
* implementation because there is no general way to define it in a concurrent
* environment. The definition of "the next read()" operation is tenuous if
* multiple clients are reading concurrently, and the ability to peek implies
* that some state is likely to be stored, so implementations of
* {@link PeekableItemReader} may well be restricted to single threaded use.
* The detailed contract for {@link #peek()} has to be defined by the implementation
* because there is no general way to define it in a concurrent environment. The
* definition of "the next read()" operation is tenuous if multiple clients are reading
* concurrently, and the ability to peek implies that some state is likely to be stored,
* so implementations of {@link PeekableItemReader} may well be restricted to single
* threaded use.
* </p>
*
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
*
*/
public interface PeekableItemReader<T> extends ItemReader<T> {
/**
* Get the next item that would be returned by {@link #read()}, without
* affecting the result of {@link #read()}.
*
* Get the next item that would be returned by {@link #read()}, without affecting the
* result of {@link #read()}.
* @return the next item or {@code null} if the data source is exhausted
* @throws Exception if there is a problem
*/

View File

@@ -17,7 +17,7 @@ package org.springframework.batch.item;
/**
* Exception indicating that an {@link ItemReader} needed to be opened before read.
*
*
* @author Ben Hale
*/
@SuppressWarnings("serial")
@@ -25,7 +25,6 @@ public class ReaderNotOpenException extends ItemReaderException {
/**
* Create a new {@link ReaderNotOpenException} based on a message.
*
* @param message the message for this exception
*/
public ReaderNotOpenException(String message) {
@@ -33,12 +32,13 @@ public class ReaderNotOpenException extends ItemReaderException {
}
/**
* Create a new {@link ReaderNotOpenException} based on a message and another exception.
*
* Create a new {@link ReaderNotOpenException} based on a message and another
* exception.
* @param msg the message for this exception
* @param nested the other exception
*/
public ReaderNotOpenException(String msg, Throwable nested) {
super(msg, nested);
}
}

View File

@@ -19,13 +19,15 @@ import org.springframework.core.io.Resource;
import org.springframework.batch.item.file.MultiResourceItemReader;
/**
* Marker interface indicating that an item should have the Spring {@link Resource} in which it was read from, set on it.
* The canonical example is within {@link MultiResourceItemReader}, which will set the current resource on any items
* that implement this interface.
* Marker interface indicating that an item should have the Spring {@link Resource} in
* which it was read from, set on it. The canonical example is within
* {@link MultiResourceItemReader}, which will set the current resource on any items that
* implement this interface.
*
* @author Lucas Ward
*/
public interface ResourceAware {
void setResource(Resource resource);
void setResource(Resource resource);
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2013 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.
@@ -19,17 +19,23 @@ 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
* @since 2.2
*/
public class SpELItemKeyMapper<K,V> implements Converter<V,K> {
public class SpELItemKeyMapper<K, V> implements Converter<V, K> {
private final ExpressionParser parser = new SpelExpressionParser();
private final Expression parsedExpression;
public SpELItemKeyMapper(String keyExpression) {
parsedExpression = parser.parseExpression(keyExpression);
parsedExpression = parser.parseExpression(keyExpression);
}
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.springframework.batch.item.ItemKeyMapper#mapKey(java.lang.Object)
*/
@SuppressWarnings("unchecked")
@@ -37,4 +43,5 @@ public class SpELItemKeyMapper<K,V> implements Converter<V,K> {
public K convert(V item) {
return (K) parsedExpression.getValue(item);
}
}

View File

@@ -17,18 +17,18 @@
package org.springframework.batch.item;
/**
* Used to signal an unexpected end of an input or message stream. This is an abnormal condition, not just the end of
* the data - e.g. if a resource becomes unavailable, or a stream becomes unreadable.
*
* Used to signal an unexpected end of an input or message stream. This is an abnormal
* condition, not just the end of the data - e.g. if a resource becomes unavailable, or a
* stream becomes unreadable.
*
* @author Dave Syer
* @author Ben Hale
*/
@SuppressWarnings("serial")
public class UnexpectedInputException extends ItemReaderException {
/**
* Create a new {@link UnexpectedInputException} based on a message.
*
* @param message the message for this exception
*/
public UnexpectedInputException(String message) {
@@ -36,12 +36,13 @@ public class UnexpectedInputException extends ItemReaderException {
}
/**
* Create a new {@link UnexpectedInputException} based on a message and another exception.
*
* Create a new {@link UnexpectedInputException} based on a message and another
* exception.
* @param msg the message for this exception
* @param nested the other exception
*/
public UnexpectedInputException(String msg, Throwable nested) {
super(msg, nested);
}
}

View File

@@ -16,9 +16,9 @@
package org.springframework.batch.item;
/**
* Unchecked exception indicating that an error has occurred while trying to
* clear a buffer on a rollback.
*
* Unchecked exception indicating that an error has occurred while trying to clear a
* buffer on a rollback.
*
* @author Lucas Ward
* @author Ben Hale
*/
@@ -26,9 +26,7 @@ package org.springframework.batch.item;
public class WriteFailedException extends ItemWriterException {
/**
* Create a new {@link WriteFailedException} based on a message and another
* exception.
*
* Create a new {@link WriteFailedException} based on a message and another exception.
* @param message the message for this exception
* @param cause the other exception
*/
@@ -38,7 +36,6 @@ public class WriteFailedException extends ItemWriterException {
/**
* Create a new {@link WriteFailedException} based on a message.
*
* @param message the message for this exception
*/
public WriteFailedException(String message) {

View File

@@ -18,7 +18,7 @@ package org.springframework.batch.item;
/**
* Exception indicating that an {@link ItemWriter} needed to be opened before being
* written to.
*
*
* @author Lucas Ward
*/
@SuppressWarnings("serial")
@@ -26,7 +26,6 @@ public class WriterNotOpenException extends ItemWriterException {
/**
* Create a new {@link WriterNotOpenException} based on a message.
*
* @param message the message for this exception
*/
public WriterNotOpenException(String message) {
@@ -34,12 +33,13 @@ public class WriterNotOpenException extends ItemWriterException {
}
/**
* Create a new {@link WriterNotOpenException} based on a message and another exception.
*
* Create a new {@link WriterNotOpenException} based on a message and another
* exception.
* @param msg the message for this exception
* @param nested the other exception
*/
public WriterNotOpenException(String msg, Throwable nested) {
super(msg, nested);
}
}

View File

@@ -28,14 +28,14 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.MethodInvoker;
/**
* Superclass for delegating classes which dynamically call a custom method of
* injected object. Provides convenient API for dynamic method invocation
* shielding subclasses from low-level details and exception handling.
* Superclass for delegating classes which dynamically call a custom method of injected
* object. Provides convenient API for dynamic method invocation shielding subclasses from
* low-level details and exception handling.
*
* {@link Exception}s thrown by a successfully invoked delegate method are
* re-thrown without wrapping. In case the delegate method throws a
* {@link Throwable} that doesn't subclass {@link Exception} it will be wrapped
* by {@link InvocationTargetThrowableWrapper}.
* {@link Exception}s thrown by a successfully invoked delegate method are re-thrown
* without wrapping. In case the delegate method throws a {@link Throwable} that doesn't
* subclass {@link Exception} it will be wrapped by
* {@link InvocationTargetThrowableWrapper}.
*
* @author Robert Kasanicky
* @author Mahmoud Ben Hassine
@@ -49,11 +49,8 @@ public abstract class AbstractMethodInvokingDelegator<T> implements Initializing
private Object[] arguments;
/**
* Invoker the target method with arguments set by
* {@link #setArguments(Object[])}.
*
* 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 {
@@ -64,10 +61,8 @@ public abstract class AbstractMethodInvokingDelegator<T> implements Initializing
/**
* Invokes the target method with given argument.
*
* @param object argument for the target method
* @return object returned by target method
*
* @throws Exception exception thrown when executing the delegate method.
*/
protected T invokeDelegateMethodWithArgument(Object object) throws Exception {
@@ -78,10 +73,8 @@ public abstract class AbstractMethodInvokingDelegator<T> implements Initializing
/**
* Invokes the target method with given arguments.
*
* @param args arguments for the invoked method
* @return object returned by invoked method
*
* @throws Exception exception thrown when executing the delegate method.
*/
protected T invokeDelegateMethodWithArguments(Object[] args) throws Exception {
@@ -140,8 +133,8 @@ public abstract class AbstractMethodInvokingDelegator<T> implements Initializing
}
/**
* @return true if target class declares a method matching target method
* name with given number of arguments of appropriate type.
* @return true if target class declares a method matching target method name with
* given number of arguments of appropriate type.
*/
private boolean targetClassDeclaresTargetMethod() {
MethodInvoker invoker = createMethodInvoker(targetObject, targetMethod);
@@ -184,8 +177,8 @@ public abstract class AbstractMethodInvokingDelegator<T> implements Initializing
}
/**
* @param targetObject the delegate - bean id can be used to set this value
* in Spring configuration
* @param targetObject the delegate - bean id can be used to set this value in Spring
* configuration
*/
public void setTargetObject(Object targetObject) {
this.targetObject = targetObject;
@@ -200,15 +193,14 @@ public abstract class AbstractMethodInvokingDelegator<T> implements Initializing
}
/**
* @param arguments arguments values for the {
* {@link #setTargetMethod(String)}. These will be used only when the
* subclass tries to invoke the target method without providing explicit
* argument values.
* @param arguments arguments values for the { {@link #setTargetMethod(String)}. These
* will be used only when the subclass tries to invoke the target method without
* 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.
* 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.
*/
public void setArguments(Object[] arguments) {
this.arguments = arguments == null ? null : Arrays.asList(arguments).toArray();
@@ -221,7 +213,7 @@ public abstract class AbstractMethodInvokingDelegator<T> implements Initializing
protected Object[] getArguments() {
return arguments;
}
/**
* Used to wrap a {@link Throwable} (not an {@link Exception}) thrown by a
* reflectively-invoked delegate.
@@ -236,4 +228,5 @@ public abstract class AbstractMethodInvokingDelegator<T> implements Initializing
}
}
}

View File

@@ -19,12 +19,12 @@ package org.springframework.batch.item.adapter;
import org.springframework.util.MethodInvoker;
/**
* Indicates an error has been encountered while trying to dynamically invoke a
* method e.g. using {@link MethodInvoker}.
*
* The exception should be caused by a failed invocation of a method, it
* shouldn't be used to wrap an exception thrown by successfully invoked method.
*
* Indicates an error has been encountered while trying to dynamically invoke a method
* e.g. using {@link MethodInvoker}.
*
* The exception should be caused by a failed invocation of a method, it shouldn't be used
* to wrap an exception thrown by successfully invoked method.
*
* @author Robert Kasanicky
*/
public class DynamicMethodInvocationException extends RuntimeException {
@@ -39,4 +39,5 @@ public class DynamicMethodInvocationException extends RuntimeException {
public DynamicMethodInvocationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -22,12 +22,11 @@ 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.
*
* 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.
*
* @author Dave Syer
*
* @since 2.1
*/
public class HippyMethodInvoker extends MethodInvoker {
@@ -78,4 +77,5 @@ public class HippyMethodInvoker extends MethodInvoker {
return matchingMethod;
}
}

View File

@@ -20,12 +20,12 @@ 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 item.
* Invokes a custom method on a delegate plain old Java object which itself processes an
* item.
*
* @author Dave Syer
*/
public class ItemProcessorAdapter<I,O> extends AbstractMethodInvokingDelegator<O> implements ItemProcessor<I,O> {
public class ItemProcessorAdapter<I, O> extends AbstractMethodInvokingDelegator<O> implements ItemProcessor<I, O> {
/**
* Invoke the delegate method and return the result.

View File

@@ -20,8 +20,8 @@ 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 item.
* Invokes a custom method on a delegate plain old Java object which itself provides an
* item.
*
* @author Robert Kasanicky
*/

View File

@@ -20,13 +20,11 @@ import java.util.List;
import org.springframework.batch.item.ItemWriter;
/**
* Delegates item processing to a custom method -
* passes the item as an argument for the delegate method.
* Delegates item processing to a custom method - passes the item as an argument for the
* delegate method.
*
* @see PropertyExtractingDelegatingItemWriter
*
* @author Robert Kasanicky
*/
public class ItemWriterAdapter<T> extends AbstractMethodInvokingDelegator<T> implements ItemWriter<T> {
@@ -39,4 +37,3 @@ public class ItemWriterAdapter<T> extends AbstractMethodInvokingDelegator<T> imp
}
}

View File

@@ -25,22 +25,20 @@ import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.Assert;
/**
* Delegates processing to a custom method - extracts property values from item
* object and uses them as arguments for the delegate method.
* Delegates processing to a custom method - extracts property values from item object and
* uses them as arguments for the delegate method.
*
* @see ItemWriterAdapter
*
* @author Robert Kasanicky
*/
public class PropertyExtractingDelegatingItemWriter<T> extends AbstractMethodInvokingDelegator<T> implements
ItemWriter<T> {
public class PropertyExtractingDelegatingItemWriter<T> extends AbstractMethodInvokingDelegator<T>
implements ItemWriter<T> {
private String[] fieldsUsedAsTargetMethodArguments;
/**
* Extracts values from item's fields named in
* fieldsUsedAsTargetMethodArguments and passes them as arguments to the
* delegate method.
* Extracts values from item's fields named in fieldsUsedAsTargetMethodArguments and
* passes them as arguments to the delegate method.
*/
@Override
public void write(List<? extends T> items) throws Exception {
@@ -66,13 +64,13 @@ ItemWriter<T> {
}
/**
* @param fieldsUsedAsMethodArguments the values of the these item's fields
* will be used as arguments for the delegate method. Nested property values
* are supported, e.g. <code>address.city</code>
* @param fieldsUsedAsMethodArguments the values of the these item's fields will be
* used as arguments for the delegate method. Nested property values are supported,
* e.g. <code>address.city</code>
*/
public void setFieldsUsedAsTargetMethodArguments(String[] fieldsUsedAsMethodArguments) {
this.fieldsUsedAsTargetMethodArguments = Arrays.asList(fieldsUsedAsMethodArguments).toArray(
new String[fieldsUsedAsMethodArguments.length]);
this.fieldsUsedAsTargetMethodArguments = Arrays.asList(fieldsUsedAsMethodArguments)
.toArray(new String[fieldsUsedAsMethodArguments.length]);
}
}

View File

@@ -24,21 +24,22 @@ import org.springframework.util.Assert;
/**
* <p>
* AMQP {@link ItemReader} implementation using an {@link AmqpTemplate} to
* receive and/or convert messages.
* AMQP {@link ItemReader} implementation using an {@link AmqpTemplate} to receive and/or
* convert messages.
* </p>
*
* @author Chris Schaefer
* @author Mahmoud Ben Hassine
*/
public class AmqpItemReader<T> implements ItemReader<T> {
private final AmqpTemplate amqpTemplate;
private Class<? extends T> itemType;
/**
* Initialize the AmqpItemReader.
*
* @param amqpTemplate the template to be used. Must not be null.
* @param amqpTemplate the template to be used. Must not be null.
*/
public AmqpItemReader(final AmqpTemplate amqpTemplate) {
Assert.notNull(amqpTemplate, "AmqpTemplate must not be null");
@@ -66,11 +67,11 @@ public class AmqpItemReader<T> implements ItemReader<T> {
/**
* Establish the itemType for the reader.
*
* @param itemType class type that will be returned by the reader.
*/
public void setItemType(Class<? extends T> itemType) {
Assert.notNull(itemType, "Item type cannot be null");
this.itemType = itemType;
}
}

View File

@@ -26,32 +26,35 @@ import java.util.List;
/**
* <p>
* AMQP {@link ItemWriter} implementation using an {@link AmqpTemplate} to
* send messages. Messages will be sent to the nameless exchange if not specified
* on the provided {@link AmqpTemplate}.
* AMQP {@link ItemWriter} implementation using an {@link AmqpTemplate} to send messages.
* Messages will be sent to the nameless exchange if not specified on the provided
* {@link AmqpTemplate}.
* </p>
*
* @author Chris Schaefer
* @author Mahmoud Ben Hassine
*/
public class AmqpItemWriter<T> implements ItemWriter<T> {
private final AmqpTemplate amqpTemplate;
private final Log log = LogFactory.getLog(getClass());
public AmqpItemWriter(final AmqpTemplate amqpTemplate) {
Assert.notNull(amqpTemplate, "AmqpTemplate must not be null");
private final AmqpTemplate amqpTemplate;
this.amqpTemplate = amqpTemplate;
}
private final Log log = LogFactory.getLog(getClass());
@Override
public void write(final List<? extends T> items) throws Exception {
if (log.isDebugEnabled()) {
log.debug("Writing to AMQP with " + items.size() + " items.");
}
public AmqpItemWriter(final AmqpTemplate amqpTemplate) {
Assert.notNull(amqpTemplate, "AmqpTemplate must not be null");
this.amqpTemplate = amqpTemplate;
}
@Override
public void write(final List<? extends T> items) throws Exception {
if (log.isDebugEnabled()) {
log.debug("Writing to AMQP with " + items.size() + " items.");
}
for (T item : items) {
amqpTemplate.convertAndSend(item);
}
}
for (T item : items) {
amqpTemplate.convertAndSend(item);
}
}
}

View File

@@ -59,17 +59,17 @@ public class AmqpItemReaderBuilder<T> {
/**
* Validates and builds a {@link AmqpItemReader}.
*
* @return a {@link AmqpItemReader}
*/
public AmqpItemReader<T> build() {
Assert.notNull(this.amqpTemplate, "amqpTemplate is required.");
AmqpItemReader<T> reader = new AmqpItemReader<>(this.amqpTemplate);
if(this.itemType != null) {
if (this.itemType != null) {
reader.setItemType(this.itemType);
}
return reader;
}
}

View File

@@ -1,10 +1,10 @@
/*
* Copyright 2017 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
@@ -22,6 +22,7 @@ import org.springframework.util.Assert;
/**
* A builder implementation for the {@link AmqpItemWriter}
*
* @author Glenn Renfro
* @since 4.0
* @see AmqpItemWriter
@@ -44,7 +45,6 @@ public class AmqpItemWriterBuilder<T> {
/**
* Validates and builds a {@link AmqpItemWriter}.
*
* @return a {@link AmqpItemWriter}
*/
public AmqpItemWriter<T> build() {

View File

@@ -1,180 +1,182 @@
/*
* Copyright 2019 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.avro;
import java.io.IOException;
import java.io.InputStream;
import org.apache.avro.Schema;
import org.apache.avro.file.DataFileStream;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.reflect.ReflectDatumReader;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificRecordBase;
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;
/**
* An {@link ItemReader} that deserializes data from a {@link Resource} containing serialized Avro objects.
*
* @author David Turanski
* @author Mahmoud Ben Hassine
* @since 4.2
*/
public class AvroItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> {
private boolean embeddedSchema = true;
private InputStreamReader<T> inputStreamReader;
private DataFileStream<T> dataFileReader;
private InputStream inputStream;
private DatumReader<T> datumReader;
/**
*
* @param resource the {@link Resource} containing objects serialized with Avro.
* @param clazz the data type to be deserialized.
*/
public AvroItemReader(Resource resource, Class<T> clazz) {
Assert.notNull(resource, "'resource' is required.");
Assert.notNull(clazz, "'class' is required.");
try {
this.inputStream = resource.getInputStream();
this.datumReader = datumReaderForClass(clazz);
}
catch (IOException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
/**
*
* @param data the {@link Resource} containing the data to be read.
* @param schema the {@link Resource} containing the Avro schema.
*/
public AvroItemReader(Resource data, Resource schema) {
Assert.notNull(data, "'data' is required.");
Assert.state(data.exists(), "'data' " + data.getFilename() +" does not exist.");
Assert.notNull(schema, "'schema' is required");
Assert.state(schema.exists(), "'schema' " + schema.getFilename() +" does not exist.");
try {
this.inputStream = data.getInputStream();
Schema avroSchema = new Schema.Parser().parse(schema.getInputStream());
this.datumReader = new GenericDatumReader<>(avroSchema);
}
catch (IOException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
/**
* 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.
*/
public void setEmbeddedSchema(boolean embeddedSchema) {
this.embeddedSchema = embeddedSchema;
}
@Nullable
@Override
protected T doRead() throws Exception {
if (this.inputStreamReader != null) {
return this.inputStreamReader.read();
}
return this.dataFileReader.hasNext()? this.dataFileReader.next(): null;
}
@Override
protected void doOpen() throws Exception {
initializeReader();
}
@Override
protected void doClose() throws Exception {
if (this.inputStreamReader != null) {
this.inputStreamReader.close();
return;
}
this.dataFileReader.close();
}
private void initializeReader() throws IOException {
if (this.embeddedSchema) {
this.dataFileReader = new DataFileStream<>(this.inputStream, this.datumReader);
} else {
this.inputStreamReader = createInputStreamReader(this.inputStream, this.datumReader);
}
}
private InputStreamReader<T> createInputStreamReader(InputStream inputStream, DatumReader<T> datumReader) {
return new InputStreamReader<>(inputStream, datumReader);
}
private static <T> DatumReader<T> datumReaderForClass(Class<T> clazz) {
if (SpecificRecordBase.class.isAssignableFrom(clazz)){
return new SpecificDatumReader<>(clazz);
}
if (GenericRecord.class.isAssignableFrom(clazz)) {
return new GenericDatumReader<>();
}
return new ReflectDatumReader<>(clazz);
}
private static class InputStreamReader<T> {
private final DatumReader<T> datumReader;
private final BinaryDecoder binaryDecoder;
private final InputStream inputStream;
private InputStreamReader(InputStream inputStream, DatumReader<T> datumReader) {
this.inputStream = inputStream;
this.datumReader = datumReader;
this.binaryDecoder = DecoderFactory.get().binaryDecoder(inputStream, null);
}
private T read() throws Exception {
if (!this.binaryDecoder.isEnd()) {
return this.datumReader.read(null, this.binaryDecoder);
}
return null;
}
private void close() {
try {
this.inputStream.close();
} catch (IOException e) {
throw new ItemStreamException(e.getMessage(), e);
}
}
}
}
/*
* Copyright 2019 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.avro;
import java.io.IOException;
import java.io.InputStream;
import org.apache.avro.Schema;
import org.apache.avro.file.DataFileStream;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.reflect.ReflectDatumReader;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificRecordBase;
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;
/**
* An {@link ItemReader} that deserializes data from a {@link Resource} containing
* serialized Avro objects.
*
* @author David Turanski
* @author Mahmoud Ben Hassine
* @since 4.2
*/
public class AvroItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> {
private boolean embeddedSchema = true;
private InputStreamReader<T> inputStreamReader;
private DataFileStream<T> dataFileReader;
private InputStream inputStream;
private DatumReader<T> datumReader;
/**
* @param resource the {@link Resource} containing objects serialized with Avro.
* @param clazz the data type to be deserialized.
*/
public AvroItemReader(Resource resource, Class<T> clazz) {
Assert.notNull(resource, "'resource' is required.");
Assert.notNull(clazz, "'class' is required.");
try {
this.inputStream = resource.getInputStream();
this.datumReader = datumReaderForClass(clazz);
}
catch (IOException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
/**
* @param data the {@link Resource} containing the data to be read.
* @param schema the {@link Resource} containing the Avro schema.
*/
public AvroItemReader(Resource data, Resource schema) {
Assert.notNull(data, "'data' is required.");
Assert.state(data.exists(), "'data' " + data.getFilename() + " does not exist.");
Assert.notNull(schema, "'schema' is required");
Assert.state(schema.exists(), "'schema' " + schema.getFilename() + " does not exist.");
try {
this.inputStream = data.getInputStream();
Schema avroSchema = new Schema.Parser().parse(schema.getInputStream());
this.datumReader = new GenericDatumReader<>(avroSchema);
}
catch (IOException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
/**
* 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.
*/
public void setEmbeddedSchema(boolean embeddedSchema) {
this.embeddedSchema = embeddedSchema;
}
@Nullable
@Override
protected T doRead() throws Exception {
if (this.inputStreamReader != null) {
return this.inputStreamReader.read();
}
return this.dataFileReader.hasNext() ? this.dataFileReader.next() : null;
}
@Override
protected void doOpen() throws Exception {
initializeReader();
}
@Override
protected void doClose() throws Exception {
if (this.inputStreamReader != null) {
this.inputStreamReader.close();
return;
}
this.dataFileReader.close();
}
private void initializeReader() throws IOException {
if (this.embeddedSchema) {
this.dataFileReader = new DataFileStream<>(this.inputStream, this.datumReader);
}
else {
this.inputStreamReader = createInputStreamReader(this.inputStream, this.datumReader);
}
}
private InputStreamReader<T> createInputStreamReader(InputStream inputStream, DatumReader<T> datumReader) {
return new InputStreamReader<>(inputStream, datumReader);
}
private static <T> DatumReader<T> datumReaderForClass(Class<T> clazz) {
if (SpecificRecordBase.class.isAssignableFrom(clazz)) {
return new SpecificDatumReader<>(clazz);
}
if (GenericRecord.class.isAssignableFrom(clazz)) {
return new GenericDatumReader<>();
}
return new ReflectDatumReader<>(clazz);
}
private static class InputStreamReader<T> {
private final DatumReader<T> datumReader;
private final BinaryDecoder binaryDecoder;
private final InputStream inputStream;
private InputStreamReader(InputStream inputStream, DatumReader<T> datumReader) {
this.inputStream = inputStream;
this.datumReader = datumReader;
this.binaryDecoder = DecoderFactory.get().binaryDecoder(inputStream, null);
}
private T read() throws Exception {
if (!this.binaryDecoder.isEnd()) {
return this.datumReader.read(null, this.binaryDecoder);
}
return null;
}
private void close() {
try {
this.inputStream.close();
}
catch (IOException e) {
throw new ItemStreamException(e.getMessage(), e);
}
}
}
}

View File

@@ -62,9 +62,7 @@ public class AvroItemWriter<T> extends AbstractItemStreamItemWriter<T> {
private boolean embedSchema = true;
/**
*
* @param resource a {@link WritableResource} to which the objects will be serialized.
* @param schema a {@link Resource} containing the Avro schema.
* @param clazz the data type to be serialized.
@@ -77,7 +75,6 @@ public class AvroItemWriter<T> extends AbstractItemStreamItemWriter<T> {
/**
* This constructor will create an ItemWriter that does not embedded Avro schema.
*
* @param resource a {@link WritableResource} to which the objects will be serialized.
* @param clazz the data type to be serialized.
*/
@@ -111,7 +108,8 @@ public class AvroItemWriter<T> extends AbstractItemStreamItemWriter<T> {
super.open(executionContext);
try {
initializeWriter();
} catch (IOException e) {
}
catch (IOException e) {
throw new ItemStreamException(e.getMessage(), e);
}
}
@@ -131,7 +129,7 @@ public class AvroItemWriter<T> extends AbstractItemStreamItemWriter<T> {
}
}
private void initializeWriter() throws IOException {
private void initializeWriter() throws IOException {
Assert.notNull(this.resource, "'resource' is required.");
Assert.notNull(this.clazz, "'class' is required.");
@@ -142,12 +140,14 @@ public class AvroItemWriter<T> extends AbstractItemStreamItemWriter<T> {
Schema schema;
try {
schema = new Schema.Parser().parse(this.schemaResource.getInputStream());
} catch (IOException e) {
}
catch (IOException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
this.dataFileWriter = new DataFileWriter<>(datumWriterForClass(this.clazz));
this.dataFileWriter.create(schema, this.resource.getOutputStream());
} else {
}
else {
this.outputStreamWriter = createOutputStreamWriter(this.resource.getOutputStream(),
datumWriterForClass(this.clazz));
}
@@ -155,7 +155,7 @@ public class AvroItemWriter<T> extends AbstractItemStreamItemWriter<T> {
}
private static <T> DatumWriter<T> datumWriterForClass(Class<T> clazz) {
if (SpecificRecordBase.class.isAssignableFrom(clazz)){
if (SpecificRecordBase.class.isAssignableFrom(clazz)) {
return new SpecificDatumWriter<>(clazz);
}
if (GenericRecord.class.isAssignableFrom(clazz)) {
@@ -170,6 +170,7 @@ public class AvroItemWriter<T> extends AbstractItemStreamItemWriter<T> {
}
private static class OutputStreamWriter<T> {
private final DatumWriter<T> datumWriter;
private final BinaryEncoder binaryEncoder;
@@ -195,5 +196,7 @@ public class AvroItemWriter<T> extends AbstractItemStreamItemWriter<T> {
throw new ItemStreamException(e.getMessage(), e);
}
}
}
}

View File

@@ -47,8 +47,7 @@ public class AvroItemReaderBuilder<T> {
private Class<T> type;
private boolean embeddedSchema =true;
private boolean embeddedSchema = true;
/**
* Configure a {@link Resource} containing Avro serialized objects.
@@ -62,7 +61,6 @@ public class AvroItemReaderBuilder<T> {
return this;
}
/**
* Configure an Avro {@link Schema} from a {@link Resource}.
* @param schema an existing schema Resource.
@@ -100,7 +98,7 @@ public class AvroItemReaderBuilder<T> {
/**
* Disable or enable reading an embedded Avro schema. True by default.
* @param embeddedSchema set to false to if the input does not contain an Avro schema.
* @return The current instance of the builder.
* @return The current instance of the builder.
*/
public AvroItemReaderBuilder<T> embeddedSchema(boolean embeddedSchema) {
this.embeddedSchema = embeddedSchema;
@@ -108,10 +106,9 @@ public class AvroItemReaderBuilder<T> {
}
/**
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
* for restart purposes.
*
* Configure if the state of the
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -124,7 +121,6 @@ public class AvroItemReaderBuilder<T> {
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -136,7 +132,6 @@ public class AvroItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -148,7 +143,6 @@ public class AvroItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -158,7 +152,6 @@ public class AvroItemReaderBuilder<T> {
return this;
}
/**
* Build an instance of {@link AvroItemReader}.
* @return the instance;
@@ -177,9 +170,8 @@ public class AvroItemReaderBuilder<T> {
avroItemReader.setSaveState(this.saveState);
if(this.saveState) {
Assert.state(StringUtils.hasText(this.name),
"A name is required when saveState is set to true.");
if (this.saveState) {
Assert.state(StringUtils.hasText(this.name), "A name is required when saveState is set to true.");
}
avroItemReader.setName(this.name);
@@ -190,7 +182,6 @@ public class AvroItemReaderBuilder<T> {
return avroItemReader;
}
private AvroItemReader<T> buildForType() {
Assert.isNull(this.schema, "You cannot specify a schema and 'type'.");
return new AvroItemReader<>(this.resource, this.type);
@@ -201,5 +192,4 @@ public class AvroItemReaderBuilder<T> {
return new AvroItemReader<>(this.resource, this.schema);
}
}

View File

@@ -30,16 +30,16 @@ import org.springframework.util.Assert;
* @since 4.2
*/
public class AvroItemWriterBuilder<T> {
private Class<T> type;
private WritableResource resource;
private Resource schema;
private String name = AvroItemWriter.class.getSimpleName();
private String name = AvroItemWriter.class.getSimpleName();
/**
*
* @param resource the {@link WritableResource} used to write the serialized data.
* @return The current instance of the builder.
*/
@@ -50,7 +50,6 @@ public class AvroItemWriterBuilder<T> {
}
/**
*
* @param schema the Resource containing the schema JSON used to serialize the output.
* @return The current instance of the builder.
*/
@@ -61,10 +60,9 @@ public class AvroItemWriterBuilder<T> {
return this;
}
/**
*
* @param schemaString the String containing the schema JSON used to serialize the output.
* @param schemaString the String containing the schema JSON used to serialize the
* output.
* @return The current instance of the builder.
*/
public AvroItemWriterBuilder<T> schema(String schemaString) {
@@ -73,9 +71,7 @@ public class AvroItemWriterBuilder<T> {
return this;
}
/**
*
* @param type the Class of objects to be serialized.
* @return The current instance of the builder.
*/
@@ -88,7 +84,6 @@ public class AvroItemWriterBuilder<T> {
/**
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -101,7 +96,6 @@ public class AvroItemWriterBuilder<T> {
/**
* Build an instance of {@link AvroItemWriter}.
*
* @return the instance;
*/
public AvroItemWriter<T> build() {
@@ -110,9 +104,9 @@ public class AvroItemWriterBuilder<T> {
Assert.notNull(this.type, "A 'type' is required.");
AvroItemWriter<T> avroItemWriter = this.schema != null ?
new AvroItemWriter<>(this.resource, this.schema, this.type):
new AvroItemWriter<>(this.resource, this.type);
AvroItemWriter<T> avroItemWriter = this.schema != null
? new AvroItemWriter<>(this.resource, this.schema, this.type)
: new AvroItemWriter<>(this.resource, this.type);
avroItemWriter.setName(this.name);
return avroItemWriter;
}

View File

@@ -24,17 +24,16 @@ import org.springframework.util.Assert;
import java.util.Iterator;
/**
* 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 restartability based on those facilities.
*
* 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
* restartability based on those facilities.
*
* @author Michael Minella
* @author Glenn Renfro
* @since 2.2
* @param <T> Type of item to be read
*/
public abstract class AbstractPaginatedDataItemReader<T> extends
AbstractItemCountingItemStreamItemReader<T> {
public abstract class AbstractPaginatedDataItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> {
protected volatile int page = 0;
@@ -46,8 +45,7 @@ AbstractItemCountingItemStreamItemReader<T> {
/**
* The number of items to be read with each page.
*
* @param pageSize the number of items. pageSize must be greater than zero.
* @param pageSize the number of items. pageSize must be greater than zero.
*/
public void setPageSize(int pageSize) {
Assert.isTrue(pageSize > 0, "pageSize must be greater than zero");
@@ -59,19 +57,18 @@ AbstractItemCountingItemStreamItemReader<T> {
protected T doRead() throws Exception {
synchronized (lock) {
if(results == null || !results.hasNext()) {
if (results == null || !results.hasNext()) {
results = doPageRead();
page ++;
page++;
if(results == null || !results.hasNext()) {
if (results == null || !results.hasNext()) {
return null;
}
}
if(results.hasNext()) {
if (results.hasNext()) {
return results.next();
}
else {
@@ -81,15 +78,12 @@ AbstractItemCountingItemStreamItemReader<T> {
}
/**
* Method this {@link ItemStreamReader} delegates to
* for the actual work of reading a page. Each time
* this method is called, the resulting {@link Iterator}
* should contain the items read within the next page.
* <br><br>
* If the {@link Iterator} is empty or null when it is
* returned, this {@link ItemReader} will assume that the
* input has been exhausted.
*
* Method this {@link ItemStreamReader} delegates to for the actual work of reading a
* page. Each time this method is called, the resulting {@link Iterator} should
* contain the items read within the next page. <br>
* <br>
* If the {@link Iterator} is empty or null 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<T> doPageRead();
@@ -110,9 +104,10 @@ AbstractItemCountingItemStreamItemReader<T> {
Iterator<T> initialPage = doPageRead();
for(; current >= 0; current--) {
for (; current >= 0; current--) {
initialPage.next();
}
}
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2013 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.
@@ -20,13 +20,15 @@ import org.springframework.util.Assert;
/**
* An {@link ItemWriter} that stores items in GemFire
*
*
* @author David Turanski
* @since 2.2
*
*/
public class GemfireItemWriter<K,V> extends KeyValueItemWriter<K,V> {
public class GemfireItemWriter<K, V> extends KeyValueItemWriter<K, V> {
private GemfireOperations gemfireTemplate;
/**
* @param gemfireTemplate the {@link GemfireTemplate} to set
*/
@@ -34,19 +36,26 @@ public class GemfireItemWriter<K,V> extends KeyValueItemWriter<K,V> {
this.gemfireTemplate = gemfireTemplate;
}
/* (non-Javadoc)
* @see org.springframework.batch.item.KeyValueItemWriter#writeKeyValue(java.lang.Object, java.lang.Object)
/*
* (non-Javadoc)
*
* @see
* org.springframework.batch.item.KeyValueItemWriter#writeKeyValue(java.lang.Object,
* java.lang.Object)
*/
@Override
protected void writeKeyValue(K key, V value) {
if (delete) {
gemfireTemplate.remove(key);
} else {
}
else {
gemfireTemplate.put(key, value);
}
}
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.springframework.batch.item.KeyValueItemWriter#init()
*/
@Override

View File

@@ -41,39 +41,38 @@ import org.springframework.util.StringUtils;
/**
* <p>
* Restartable {@link ItemReader} that reads documents from MongoDB
* via a paging technique.
* Restartable {@link ItemReader} that reads documents from MongoDB via a paging
* technique.
* </p>
*
* <p>
* If you set JSON String query {@link #setQuery(String)} then
* it executes the JSON to retrieve the requested documents.
* If you set JSON String query {@link #setQuery(String)} then it executes the JSON to
* retrieve the requested documents.
* </p>
*
*
* <p>
* If you set Query object {@link #setQuery(Query)} then
* it executes the Query to retrieve the requested documents.
* If you set Query object {@link #setQuery(Query)} then it executes the Query to retrieve
* the requested documents.
* </p>
*
*
* <p>
* The query is executed using paged requests specified in the
* {@link #setPageSize(int)}. Additional pages are requested as needed to
* provide data when the {@link #read()} method is called.
* The query is executed using paged requests specified in the {@link #setPageSize(int)}.
* Additional pages are requested as needed to provide data when the {@link #read()}
* method is called.
* </p>
*
* <p>
* The JSON String query provided supports parameter substitution via ?&lt;index&gt;
* placeholders where the &lt;index&gt; indicates the index of the
* parameterValue to substitute.
* placeholders where the &lt;index&gt; indicates the index of the parameterValue to
* substitute.
* </p>
*
* <p>
* The implementation is thread-safe between calls to
* {@link #open(ExecutionContext)}, but remember to use <code>saveState=false</code>
* if used in a multi-threaded client (no restart available).
* The implementation is thread-safe between calls to {@link #open(ExecutionContext)}, but
* remember to use <code>saveState=false</code> if used in a multi-threaded client (no
* restart available).
* </p>
*
*
* @author Michael Minella
* @author Takaaki Iida
* @author Mahmoud Ben Hassine
@@ -82,23 +81,30 @@ import org.springframework.util.StringUtils;
public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> implements InitializingBean {
private MongoOperations template;
private Query query;
private String queryString;
private Class<? extends T> type;
private Sort sort;
private String hint;
private String fields;
private String collection;
private List<Object> parameterValues = new ArrayList<>();
public MongoItemReader() {
super();
setName(ClassUtils.getShortName(MongoItemReader.class));
}
/**
* A Mongo Query to be used.
*
* @param query Mongo Query to be used.
*/
public void setQuery(Query query) {
@@ -106,9 +112,8 @@ public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
}
/**
* Used to perform operations against the MongoDB instance. Also
* handles the mapping of documents to objects.
*
* Used to perform operations against the MongoDB instance. Also handles the mapping
* of documents to objects.
* @param template the MongoOperations instance to use
* @see MongoOperations
*/
@@ -117,10 +122,9 @@ public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
}
/**
* A JSON formatted MongoDB query. Parameterization of the provided query is allowed
* A JSON formatted MongoDB query. Parameterization of the provided query is allowed
* via ?&lt;index&gt; placeholders where the &lt;index&gt; indicates the index of the
* parameterValue to substitute.
*
* @param queryString JSON formatted Mongo query
*/
public void setQuery(String queryString) {
@@ -129,7 +133,6 @@ public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
/**
* The type of object to be returned for each {@link #read()} call.
*
* @param type the type of object to return
*/
public void setTargetType(Class<? extends T> type) {
@@ -137,9 +140,8 @@ public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
}
/**
* {@link List} of values to be substituted in for each of the
* parameters in the query.
*
* {@link List} of values to be substituted in for each of the parameters in the
* query.
* @param parameterValues values
*/
public void setParameterValues(List<Object> parameterValues) {
@@ -148,9 +150,7 @@ public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
}
/**
* JSON defining the fields to be returned from the matching documents
* by MongoDB.
*
* JSON defining the fields to be returned from the matching documents by MongoDB.
* @param fields JSON string that identifies the fields to sort by.
*/
public void setFields(String fields) {
@@ -158,9 +158,9 @@ public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
}
/**
* {@link Map} of property names/{@link org.springframework.data.domain.Sort.Direction} values to
* sort the input by.
*
* {@link Map} of property
* names/{@link org.springframework.data.domain.Sort.Direction} values to sort the
* input by.
* @param sorts map of properties and direction to sort each.
*/
public void setSort(Map<String, Sort.Direction> sorts) {
@@ -177,7 +177,6 @@ public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
/**
* JSON String telling MongoDB what index to use.
*
* @param hint string indicating what index to use.
*/
public void setHint(String hint) {
@@ -189,37 +188,40 @@ public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
protected Iterator<T> doPageRead() {
if (queryString != null) {
Pageable pageRequest = PageRequest.of(page, pageSize, sort);
String populatedQuery = replacePlaceholders(queryString, parameterValues);
Query mongoQuery;
if(StringUtils.hasText(fields)) {
if (StringUtils.hasText(fields)) {
mongoQuery = new BasicQuery(populatedQuery, fields);
}
else {
mongoQuery = new BasicQuery(populatedQuery);
}
mongoQuery.with(pageRequest);
if(StringUtils.hasText(hint)) {
if (StringUtils.hasText(hint)) {
mongoQuery.withHint(hint);
}
if(StringUtils.hasText(collection)) {
if (StringUtils.hasText(collection)) {
return (Iterator<T>) template.find(mongoQuery, type, collection).iterator();
} else {
}
else {
return (Iterator<T>) template.find(mongoQuery, type).iterator();
}
} else {
}
else {
Pageable pageRequest = PageRequest.of(page, pageSize);
query.with(pageRequest);
if(StringUtils.hasText(collection)) {
if (StringUtils.hasText(collection)) {
return (Iterator<T>) template.find(query, type, collection).iterator();
} else {
}
else {
return (Iterator<T>) template.find(query, type).iterator();
}
}
@@ -235,7 +237,7 @@ public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
Assert.state(template != null, "An implementation of MongoOperations is required.");
Assert.state(type != null, "A type to convert the input into is required.");
Assert.state(queryString != null || query != null, "A query is required.");
if (queryString != null) {
Assert.state(sort != null, "A sort is required.");
}
@@ -257,4 +259,5 @@ public class MongoItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
return Sort.by(sortValues);
}
}

View File

@@ -40,15 +40,16 @@ import org.springframework.util.StringUtils;
/**
* <p>
* A {@link ItemWriter} implementation that writes to a MongoDB store using an implementation of Spring Data's
* {@link MongoOperations}. Since MongoDB is not a transactional store, a best effort is made to persist
* written data at the last moment, yet still honor job status contracts. No attempt to roll back is made
* if an error occurs during writing.
* A {@link ItemWriter} implementation that writes to a MongoDB store using an
* implementation of Spring Data's {@link MongoOperations}. Since MongoDB is not a
* transactional store, a best effort is made to persist written data at the last moment,
* yet still honor job status contracts. No attempt to roll back is made if an error
* occurs during writing.
* </p>
*
* <p>
* This writer is thread-safe once all properties are set (normal singleton behavior) so it can be used in multiple
* concurrent transactions.
* This writer is thread-safe once all properties are set (normal singleton behavior) so
* it can be used in multiple concurrent transactions.
* </p>
*
* @author Michael Minella
@@ -59,9 +60,13 @@ import org.springframework.util.StringUtils;
public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
private static final String ID_KEY = "_id";
private MongoOperations template;
private final Object bufferKey;
private String collection;
private boolean delete = false;
public MongoItemWriter() {
@@ -70,10 +75,9 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
/**
* Indicates if the items being passed to the writer are to be saved or
* removed from the data store. If set to false (default), the items will
* be saved. If set to true, the items will be removed.
*
* Indicates if the items being passed to the writer are to be saved or removed from
* the data store. If set to false (default), the items will be saved. If set to true,
* the items will be removed.
* @param delete removal indicator
*/
public void setDelete(boolean delete) {
@@ -82,7 +86,6 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
/**
* Set the {@link MongoOperations} to be used to save items to be written.
*
* @param template the template implementation to be used.
*/
public void setTemplate(MongoOperations template) {
@@ -90,9 +93,8 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
/**
* Get the {@link MongoOperations} to be used to save items to be written.
* This can be called by a subclass if necessary.
*
* Get the {@link MongoOperations} to be used to save items to be written. This can be
* called by a subclass if necessary.
* @return template the template implementation to be used.
*/
protected MongoOperations getTemplate() {
@@ -101,7 +103,6 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
/**
* Set the name of the Mongo collection to be written to.
*
* @param collection the name of the collection.
*/
public void setCollection(String collection) {
@@ -116,7 +117,7 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
*/
@Override
public void write(List<? extends T> items) throws Exception {
if(!transactionActive()) {
if (!transactionActive()) {
doWrite(items);
return;
}
@@ -126,9 +127,8 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
/**
* Performs the actual write to the store via the template.
* This can be overridden by a subclass if necessary.
*
* 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.
*/
protected void doWrite(List<? extends T> items) {
@@ -188,7 +188,7 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
@SuppressWarnings("unchecked")
private List<T> getCurrentBuffer() {
if(!TransactionSynchronizationManager.hasResource(bufferKey)) {
if (!TransactionSynchronizationManager.hasResource(bufferKey)) {
TransactionSynchronizationManager.bindResource(bufferKey, new ArrayList<T>());
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@@ -196,8 +196,8 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
public void beforeCommit(boolean readOnly) {
List<T> items = (List<T>) TransactionSynchronizationManager.getResource(bufferKey);
if(!CollectionUtils.isEmpty(items)) {
if(!readOnly) {
if (!CollectionUtils.isEmpty(items)) {
if (!readOnly) {
doWrite(items);
}
}
@@ -205,7 +205,7 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
@Override
public void afterCompletion(int status) {
if(TransactionSynchronizationManager.hasResource(bufferKey)) {
if (TransactionSynchronizationManager.hasResource(bufferKey)) {
TransactionSynchronizationManager.unbindResource(bufferKey);
}
}
@@ -219,4 +219,5 @@ public class MongoItemWriter<T> implements ItemWriter<T>, InitializingBean {
public void afterPropertiesSet() throws Exception {
Assert.state(template != null, "A MongoOperations implementation is required.");
}
}

View File

@@ -32,34 +32,33 @@ import org.springframework.util.StringUtils;
/**
* <p>
* Restartable {@link ItemReader} that reads objects from the graph database Neo4j
* via a paging technique.
* Restartable {@link ItemReader} that reads objects from the graph database Neo4j via a
* paging technique.
* </p>
*
* <p>
* It executes cypher queries built from the statement fragments provided to
* retrieve the requested data. The query is executed using paged requests of
* a size specified in {@link #setPageSize(int)}. Additional pages are requested
* as needed when the {@link #read()} method is called. On restart, the reader
* will begin again at the same number item it left off at.
* It executes cypher queries built from the statement fragments provided to retrieve the
* requested data. The query is executed using paged requests of a size specified in
* {@link #setPageSize(int)}. Additional pages are requested as needed when the
* {@link #read()} method is called. On restart, the reader will begin again at the same
* number item it left off at.
* </p>
*
* <p>
* Performance is dependent on your Neo4J configuration (embedded or remote) as
* well as page size. Setting a fairly large page size and using a commit
* interval that matches the page size should provide better performance.
* Performance is dependent on your Neo4J configuration (embedded or remote) as well as
* page size. Setting a fairly large page size and using a commit interval that matches
* the page size should provide better performance.
* </p>
*
* <p>
* This implementation is thread-safe between calls to
* {@link #open(org.springframework.batch.item.ExecutionContext)}, however you
* should set <code>saveState=false</code> if used in a multi-threaded
* environment (no restart available).
* {@link #open(org.springframework.batch.item.ExecutionContext)}, however you should set
* <code>saveState=false</code> if used in a multi-threaded environment (no restart
* available).
* </p>
*
* @author Michael Minella
* @author Mahmoud Ben Hassine
*
* @deprecated since 5.0 in favor of the item reader from
* https://github.com/spring-projects/spring-batch-extensions/blob/main/spring-batch-neo4j
*/
@@ -71,9 +70,13 @@ public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
private SessionFactory sessionFactory;
private String startStatement;
private String returnStatement;
private String matchStatement;
private String whereStatement;
private String orderByStatement;
private Class<T> targetType;
@@ -82,7 +85,6 @@ public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
/**
* Optional parameters to be used in the cypher query.
*
* @param parameterValues the parameter values to be used in the cypher query
*/
public void setParameterValues(Map<String, Object> parameterValues) {
@@ -94,10 +96,8 @@ public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
}
/**
* The start segment of the cypher query. START is prepended
* to the statement provided and should <em>not</em> be
* included.
*
* The start segment of the cypher query. START is prepended to the statement provided
* and should <em>not</em> be included.
* @param startStatement the start fragment of the cypher query.
*/
public void setStartStatement(String startStatement) {
@@ -105,10 +105,8 @@ public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
}
/**
* The return statement of the cypher query. RETURN is prepended
* to the statement provided and should <em>not</em> be
* included
*
* The return statement of the cypher query. RETURN is prepended to the statement
* provided and should <em>not</em> be included
* @param returnStatement the return fragment of the cypher query.
*/
public void setReturnStatement(String returnStatement) {
@@ -116,10 +114,8 @@ public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
}
/**
* An optional match fragment of the cypher query. MATCH is
* prepended to the statement provided and should <em>not</em>
* be included.
*
* An optional match fragment of the cypher query. MATCH is prepended to the statement
* provided and should <em>not</em> be included.
* @param matchStatement the match fragment of the cypher query
*/
public void setMatchStatement(String matchStatement) {
@@ -127,10 +123,8 @@ public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
}
/**
* An optional where fragment of the cypher query. WHERE is
* prepended to the statement provided and should <em>not</em>
* be included.
*
* An optional where fragment of the cypher query. WHERE is prepended to the statement
* provided and should <em>not</em> be included.
* @param whereStatement where fragment of the cypher query
*/
public void setWhereStatement(String whereStatement) {
@@ -138,11 +132,9 @@ public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
}
/**
* A list of properties to order the results by. This is
* required so that subsequent page requests pull back the
* segment of results correctly. ORDER BY is prepended to
* A list of properties to order the results by. This is required so that subsequent
* page requests pull back the segment of results correctly. ORDER BY is prepended to
* the statement provided and should <em>not</em> be included.
*
* @param orderByStatement order by fragment of the cypher query.
*/
public void setOrderByStatement(String orderByStatement) {
@@ -163,7 +155,6 @@ public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
/**
* The object type to be returned from each call to {@link #read()}
*
* @param targetType the type of object to return.
*/
public void setTargetType(Class<T> targetType) {
@@ -201,7 +192,7 @@ public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.state(sessionFactory != null,"A SessionFactory is required");
Assert.state(sessionFactory != null, "A SessionFactory is required");
Assert.state(targetType != null, "The type to be returned is required");
Assert.state(StringUtils.hasText(startStatement), "A START statement is required");
Assert.state(StringUtils.hasText(returnStatement), "A RETURN statement is required");
@@ -213,15 +204,14 @@ public class Neo4jItemReader<T> extends AbstractPaginatedDataItemReader<T> imple
protected Iterator<T> doPageRead() {
Session session = getSessionFactory().openSession();
Iterable<T> queryResults = session.query(getTargetType(),
generateLimitCypherQuery(),
getParameterValues());
Iterable<T> queryResults = session.query(getTargetType(), generateLimitCypherQuery(), getParameterValues());
if(queryResults != null) {
if (queryResults != null) {
return queryResults.iterator();
}
else {
return new ArrayList<T>().iterator();
}
}
}

View File

@@ -34,14 +34,13 @@ import org.springframework.util.CollectionUtils;
* </p>
*
* <p>
* This writer is thread-safe once all properties are set (normal singleton
* behavior) so it can be used in multiple concurrent transactions.
* This writer is thread-safe once all properties are set (normal singleton behavior) so
* it can be used in multiple concurrent transactions.
* </p>
*
* @author Michael Minella
* @author Glenn Renfro
* @author Mahmoud Ben Hassine
*
* @deprecated since 5.0 in favor of the item writer from
* https://github.com/spring-projects/spring-batch-extensions/blob/main/spring-batch-neo4j
*
@@ -49,8 +48,7 @@ import org.springframework.util.CollectionUtils;
@Deprecated
public class Neo4jItemWriter<T> implements ItemWriter<T>, InitializingBean {
protected static final Log logger = LogFactory
.getLog(Neo4jItemWriter.class);
protected static final Log logger = LogFactory.getLog(Neo4jItemWriter.class);
private boolean delete = false;
@@ -82,8 +80,7 @@ public class Neo4jItemWriter<T> implements ItemWriter<T>, InitializingBean {
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.state(this.sessionFactory != null,
"A SessionFactory is required");
Assert.state(this.sessionFactory != null, "A SessionFactory is required");
}
/**
@@ -93,19 +90,18 @@ public class Neo4jItemWriter<T> implements ItemWriter<T>, InitializingBean {
*/
@Override
public void write(List<? extends T> items) throws Exception {
if(!CollectionUtils.isEmpty(items)) {
if (!CollectionUtils.isEmpty(items)) {
doWrite(items);
}
}
/**
* Performs the actual write using the template. This can be overridden by
* a subclass if necessary.
*
* Performs the actual write using the template. This can be overridden by a subclass
* if necessary.
* @param items the list of items to be persisted.
*/
protected void doWrite(List<? extends T> items) {
if(delete) {
if (delete) {
delete(items);
}
else {
@@ -116,7 +112,7 @@ public class Neo4jItemWriter<T> implements ItemWriter<T>, InitializingBean {
private void delete(List<? extends T> items) {
Session session = this.sessionFactory.openSession();
for(T item : items) {
for (T item : items) {
session.delete(item);
}
}
@@ -128,4 +124,5 @@ public class Neo4jItemWriter<T> implements ItemWriter<T>, InitializingBean {
session.save(item);
}
}
}

View File

@@ -40,8 +40,8 @@ import org.springframework.util.MethodInvoker;
/**
* <p>
* A {@link org.springframework.batch.item.ItemReader} that reads records utilizing
* a {@link org.springframework.data.repository.PagingAndSortingRepository}.
* A {@link org.springframework.batch.item.ItemReader} that reads records utilizing a
* {@link org.springframework.data.repository.PagingAndSortingRepository}.
* </p>
*
* <p>
@@ -51,20 +51,24 @@ import org.springframework.util.MethodInvoker;
* </p>
*
* <p>
* The reader must be configured with a {@link org.springframework.data.repository.PagingAndSortingRepository},
* a {@link org.springframework.data.domain.Sort}, and a pageSize greater than 0.
* The reader must be configured with a
* {@link org.springframework.data.repository.PagingAndSortingRepository}, a
* {@link org.springframework.data.domain.Sort}, and a pageSize greater than 0.
* </p>
*
* <p>
* This implementation is thread-safe between calls to {@link #open(ExecutionContext)}, but remember to use
* <code>saveState=false</code> if used in a multi-threaded client (no restart available).
* This implementation is thread-safe between calls to {@link #open(ExecutionContext)},
* but remember to use <code>saveState=false</code> if used in a multi-threaded client (no
* restart available).
* </p>
*
* <p>It is important to note that this is a paging item reader and exceptions that are
* <p>
* It is important to note that this is a paging item reader and exceptions that are
* thrown while reading the page itself (mapping results to objects, etc in the
* {@link RepositoryItemReader#doPageRead()}) will not be skippable since this reader has
* no way of knowing if an exception should be skipped and therefore will continue to read
* the same page until the skip limit is exceeded.</p>
* the same page until the skip limit is exceeded.
* </p>
*
* <p>
* NOTE: The {@code RepositoryItemReader} only reads Java Objects i.e. non primitives.
@@ -102,7 +106,6 @@ public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemR
/**
* Arguments to be passed to the data providing method.
*
* @param arguments list of method arguments to be passed to the repository
*/
public void setArguments(List<?> arguments) {
@@ -111,7 +114,6 @@ public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemR
/**
* Provides ordering of the results so that order is maintained between paged queries
*
* @param sorts the fields to sort by and the directions
*/
public void setSort(Map<String, Sort.Direction> sorts) {
@@ -128,7 +130,6 @@ public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemR
/**
* The {@link org.springframework.data.repository.PagingAndSortingRepository}
* implementation used to read input from.
*
* @param repository underlying repository for input to be read from.
*/
public void setRepository(PagingAndSortingRepository<?, ?> repository) {
@@ -136,9 +137,8 @@ public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemR
}
/**
* Specifies what method on the repository to call. This method must take
* Specifies what method on the repository to call. This method must take
* {@link org.springframework.data.domain.Pageable} as the <em>last</em> argument.
*
* @param methodName name of the method to invoke
*/
public void setMethodName(String methodName) {
@@ -166,9 +166,9 @@ public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemR
}
results = doPageRead();
page ++;
page++;
if(results.size() <= 0) {
if (results.size() <= 0) {
return null;
}
@@ -177,7 +177,7 @@ public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemR
}
}
if(current < results.size()) {
if (current < results.size()) {
T curLine = results.get(current);
current++;
return curLine;
@@ -197,12 +197,11 @@ public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemR
}
/**
* Performs the actual reading of a page via the repository.
* Available for overriding as needed.
*
* Performs the actual reading of a page via the repository. Available for overriding
* as needed.
* @return the list of items that make up the page
* @throws Exception Based on what the underlying method throws or related to the
* calling of the method
* calling of the method
*/
@SuppressWarnings("unchecked")
protected List<T> doPageRead() throws Exception {
@@ -212,7 +211,7 @@ public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemR
List<Object> parameters = new ArrayList<>();
if(arguments != null && arguments.size() > 0) {
if (arguments != null && arguments.size() > 0) {
parameters.addAll(arguments);
}
@@ -248,7 +247,7 @@ public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemR
return Sort.by(sortValues);
}
private Object doInvoke(MethodInvoker invoker) throws Exception{
private Object doInvoke(MethodInvoker invoker) throws Exception {
try {
invoker.prepare();
}
@@ -278,4 +277,5 @@ public class RepositoryItemReader<T> extends AbstractItemCountingItemStreamItemR
invoker.setTargetMethod(targetMethod);
return invoker;
}
}

View File

@@ -36,17 +36,18 @@ import org.springframework.util.MethodInvoker;
* </p>
*
* <p>
* By default, this writer will use {@link CrudRepository#saveAll(Iterable)}
* to save items, unless another method is selected with {@link #setMethodName(java.lang.String)}.
* It depends on {@link org.springframework.data.repository.CrudRepository#saveAll(Iterable)}
* method to store the items for the chunk. Performance will be determined by that
* implementation more than this writer.
* By default, this writer will use {@link CrudRepository#saveAll(Iterable)} to save
* items, unless another method is selected with {@link #setMethodName(java.lang.String)}.
* It depends on
* {@link org.springframework.data.repository.CrudRepository#saveAll(Iterable)} method to
* store the items for the chunk. Performance will be determined by that implementation
* more than this writer.
* </p>
*
* <p>
* As long as the repository provided is thread-safe, this writer is also thread-safe once
* properties are set (normal singleton behavior), so it can be used in multiple concurrent
* transactions.
* properties are set (normal singleton behavior), so it can be used in multiple
* concurrent transactions.
* </p>
*
* <p>
@@ -66,9 +67,8 @@ public class RepositoryItemWriter<T> implements ItemWriter<T>, InitializingBean
private String methodName;
/**
* Specifies what method on the repository to call. This method must have the type of
* Specifies what method on the repository to call. This method must have the type of
* object passed to this writer as the <em>sole</em> argument.
*
* @param methodName {@link String} containing the method name.
*/
public void setMethodName(String methodName) {
@@ -78,7 +78,6 @@ public class RepositoryItemWriter<T> implements ItemWriter<T>, InitializingBean
/**
* Set the {@link org.springframework.data.repository.CrudRepository} implementation
* for persistence
*
* @param repository the Spring Data repository to be set
*/
public void setRepository(CrudRepository<T, ?> repository) {
@@ -92,24 +91,22 @@ public class RepositoryItemWriter<T> implements ItemWriter<T>, InitializingBean
*/
@Override
public void write(List<? extends T> items) throws Exception {
if(!CollectionUtils.isEmpty(items)) {
if (!CollectionUtils.isEmpty(items)) {
doWrite(items);
}
}
/**
* Performs the actual write to the repository. This can be overridden by
* a subclass if necessary.
*
* Performs the actual write to the repository. This can be overridden by a subclass
* if necessary.
* @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 {
if (logger.isDebugEnabled()) {
logger.debug("Writing to the repository with " + items.size() + " items.");
}
if (this.methodName == null) {
this.repository.saveAll(items);
return;
@@ -118,7 +115,7 @@ public class RepositoryItemWriter<T> implements ItemWriter<T>, InitializingBean
MethodInvoker invoker = createMethodInvoker(repository, methodName);
for (T object : items) {
invoker.setArguments(new Object [] {object});
invoker.setArguments(new Object[] { object });
doInvoke(invoker);
}
}
@@ -137,8 +134,7 @@ public class RepositoryItemWriter<T> implements ItemWriter<T>, InitializingBean
}
}
private Object doInvoke(MethodInvoker invoker) throws Exception{
private Object doInvoke(MethodInvoker invoker) throws Exception {
try {
invoker.prepare();
}
@@ -171,4 +167,5 @@ public class RepositoryItemWriter<T> implements ItemWriter<T>, InitializingBean
invoker.setTargetMethod(targetMethod);
return invoker;
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2002-2013 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.
@@ -16,12 +16,14 @@ import org.springframework.batch.item.SpELItemKeyMapper;
import org.springframework.util.Assert;
/**
* A convenient {@link GemfireItemWriter} implementation that uses a {@link SpELItemKeyMapper}
*
* A convenient {@link GemfireItemWriter} implementation that uses a
* {@link SpELItemKeyMapper}
*
* @author David Turanski
* @since 2.2
*/
public class SpELMappingGemfireItemWriter<K, V> extends GemfireItemWriter<K, V> {
/**
* A constructor that accepts a SpEL expression used to derive the key
* @param keyExpression
@@ -31,4 +33,5 @@ public class SpELMappingGemfireItemWriter<K, V> extends GemfireItemWriter<K, V>
Assert.hasText(keyExpression, "a valid keyExpression is required.");
setItemKeyMapper(new SpELItemKeyMapper<>(keyExpression));
}
}

View File

@@ -50,7 +50,6 @@ public class GemfireItemWriterBuilder<K, V> {
/**
* Set the {@link Converter} to use to derive the key from the item.
*
* @param itemKeyMapper the Converter to use.
* @return The current instance of the builder.
* @see GemfireItemWriter#setItemKeyMapper(Converter)
@@ -65,7 +64,6 @@ public class GemfireItemWriterBuilder<K, V> {
* Indicates if the items being passed to the writer are to be saved or removed from
* the data store. If set to false (default), the items will be saved. If set to true,
* the items will be removed.
*
* @param delete removal indicator.
* @return The current instance of the builder.
* @see GemfireItemWriter#setDelete(boolean)
@@ -76,10 +74,8 @@ public class GemfireItemWriterBuilder<K, V> {
return this;
}
/**
* Validates and builds a {@link GemfireItemWriter}.
*
* @return a {@link GemfireItemWriter}
*/
public GemfireItemWriter<K, V> build() {
@@ -92,4 +88,5 @@ public class GemfireItemWriterBuilder<K, V> {
writer.setDelete(this.delete);
return writer;
}
}

View File

@@ -1,10 +1,10 @@
/*
* 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.
* 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
@@ -39,6 +39,7 @@ import org.springframework.util.StringUtils;
* @see MongoItemReader
*/
public class MongoItemReaderBuilder<T> {
private MongoOperations template;
private String jsonQuery;
@@ -68,10 +69,9 @@ public class MongoItemReaderBuilder<T> {
private Query query;
/**
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
* for restart purposes.
*
* Configure if the state of the
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -85,7 +85,6 @@ public class MongoItemReaderBuilder<T> {
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -98,7 +97,6 @@ public class MongoItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -111,7 +109,6 @@ public class MongoItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -125,7 +122,6 @@ public class MongoItemReaderBuilder<T> {
/**
* Used to perform operations against the MongoDB instance. Also handles the mapping
* of documents to objects.
*
* @param template the MongoOperations instance to use
* @see MongoOperations
* @return The current instance of the builder
@@ -138,10 +134,9 @@ public class MongoItemReaderBuilder<T> {
}
/**
* A JSON formatted MongoDB jsonQuery. Parameterization of the provided jsonQuery is allowed
* via ?&lt;index&gt; placeholders where the &lt;index&gt; indicates the index of the
* parameterValue to substitute.
*
* A JSON formatted MongoDB jsonQuery. Parameterization of the provided jsonQuery is
* allowed via ?&lt;index&gt; placeholders where the &lt;index&gt; indicates the index
* of the parameterValue to substitute.
* @param query JSON formatted Mongo jsonQuery
* @return The current instance of the builder
* @see MongoItemReader#setQuery(String)
@@ -154,7 +149,6 @@ public class MongoItemReaderBuilder<T> {
/**
* The type of object to be returned for each {@link MongoItemReader#read()} call.
*
* @param targetType the type of object to return
* @return The current instance of the builder
* @see MongoItemReader#setTargetType(Class)
@@ -168,7 +162,6 @@ public class MongoItemReaderBuilder<T> {
/**
* {@link List} of values to be substituted in for each of the parameters in the
* query.
*
* @param parameterValues values
* @return The current instance of the builder
* @see MongoItemReader#setParameterValues(List)
@@ -181,7 +174,6 @@ public class MongoItemReaderBuilder<T> {
/**
* Values to be substituted in for each of the parameters in the query.
*
* @param parameterValues values
* @return The current instance of the builder
* @see MongoItemReader#setParameterValues(List)
@@ -192,7 +184,6 @@ public class MongoItemReaderBuilder<T> {
/**
* JSON defining the fields to be returned from the matching documents by MongoDB.
*
* @param fields JSON string that identifies the fields to sort by.
* @return The current instance of the builder
* @see MongoItemReader#setFields(String)
@@ -207,7 +198,6 @@ public class MongoItemReaderBuilder<T> {
* {@link Map} of property
* names/{@link org.springframework.data.domain.Sort.Direction} values to sort the
* input by.
*
* @param sorts map of properties and direction to sort each.
* @return The current instance of the builder
* @see MongoItemReader#setSort(Map)
@@ -220,7 +210,6 @@ public class MongoItemReaderBuilder<T> {
/**
* Establish an optional collection that can be queried.
*
* @param collection Mongo collection to be queried.
* @return The current instance of the builder
* @see MongoItemReader#setCollection(String)
@@ -233,7 +222,6 @@ public class MongoItemReaderBuilder<T> {
/**
* JSON String telling MongoDB what index to use.
*
* @param hint string indicating what index to use.
* @return The current instance of the builder
* @see MongoItemReader#setHint(String)
@@ -246,7 +234,6 @@ public class MongoItemReaderBuilder<T> {
/**
* The number of items to be read with each page.
*
* @param pageSize the number of items
* @return this instance for method chaining
* @see MongoItemReader#setPageSize(int)
@@ -258,9 +245,8 @@ public class MongoItemReaderBuilder<T> {
}
/**
* Provide a Spring Data Mongo {@link Query}. This will take precedence over a JSON
* Provide a Spring Data Mongo {@link Query}. This will take precedence over a JSON
* configured query.
*
* @param query Query to execute
* @return this instance for method chaining
* @see MongoItemReader#setQuery(Query)
@@ -273,7 +259,6 @@ public class MongoItemReaderBuilder<T> {
/**
* Validates and builds a {@link MongoItemReader}.
*
* @return a {@link MongoItemReader}
*/
public MongoItemReader<T> build() {
@@ -307,4 +292,5 @@ public class MongoItemReaderBuilder<T> {
return reader;
}
}

View File

@@ -39,7 +39,6 @@ public class MongoItemWriterBuilder<T> {
* Indicates if the items being passed to the writer are to be saved or removed from
* the data store. If set to false (default), the items will be saved. If set to true,
* the items will be removed.
*
* @param delete removal indicator
* @return The current instance of the builder
* @see MongoItemWriter#setDelete(boolean)
@@ -52,7 +51,6 @@ public class MongoItemWriterBuilder<T> {
/**
* Set the {@link MongoOperations} to be used to save items to be written.
*
* @param template the template implementation to be used.
* @return The current instance of the builder
* @see MongoItemWriter#setTemplate(MongoOperations)
@@ -65,11 +63,10 @@ public class MongoItemWriterBuilder<T> {
/**
* Set the name of the Mongo collection to be written to.
*
* @param collection the name of the collection.
* @return The current instance of the builder
* @see MongoItemWriter#setCollection(String)
*
*
*/
public MongoItemWriterBuilder<T> collection(String collection) {
this.collection = collection;
@@ -79,7 +76,6 @@ public class MongoItemWriterBuilder<T> {
/**
* Validates and builds a {@link MongoItemWriter}.
*
* @return a {@link MongoItemWriter}
*/
public MongoItemWriter<T> build() {

View File

@@ -30,7 +30,6 @@ import org.springframework.util.Assert;
* @author Mahmoud Ben Hassine
* @since 4.0
* @see Neo4jItemReader
*
* @deprecated since 5.0 in favor of the item reader builder from
* https://github.com/spring-projects/spring-batch-extensions/blob/main/spring-batch-neo4j
*/
@@ -64,10 +63,9 @@ public class Neo4jItemReaderBuilder<T> {
private int currentItemCount;
/**
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
* for restart purposes.
*
* Configure if the state of the
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -81,7 +79,6 @@ public class Neo4jItemReaderBuilder<T> {
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -94,7 +91,6 @@ public class Neo4jItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -107,7 +103,6 @@ public class Neo4jItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -132,7 +127,6 @@ public class Neo4jItemReaderBuilder<T> {
/**
* The number of items to be read with each page.
*
* @param pageSize the number of items
* @return this instance for method chaining
* @see Neo4jItemReader#setPageSize(int)
@@ -145,7 +139,6 @@ public class Neo4jItemReaderBuilder<T> {
/**
* Optional parameters to be used in the cypher query.
*
* @param parameterValues the parameter values to be used in the cypher query
* @return this instance for method chaining
* @see Neo4jItemReader#setParameterValues(Map)
@@ -159,7 +152,6 @@ public class Neo4jItemReaderBuilder<T> {
/**
* The start segment of the cypher query. START is prepended to the statement provided
* and should <em>not</em> be included.
*
* @param startStatement the start fragment of the cypher query.
* @return this instance for method chaining
* @see Neo4jItemReader#setStartStatement(String)
@@ -173,7 +165,6 @@ public class Neo4jItemReaderBuilder<T> {
/**
* The return statement of the cypher query. RETURN is prepended to the statement
* provided and should <em>not</em> be included
*
* @param returnStatement the return fragment of the cypher query.
* @return this instance for method chaining
* @see Neo4jItemReader#setReturnStatement(String)
@@ -187,7 +178,6 @@ public class Neo4jItemReaderBuilder<T> {
/**
* An optional match fragment of the cypher query. MATCH is prepended to the statement
* provided and should <em>not</em> be included.
*
* @param matchStatement the match fragment of the cypher query
* @return this instance for method chaining
* @see Neo4jItemReader#setMatchStatement(String)
@@ -201,7 +191,6 @@ public class Neo4jItemReaderBuilder<T> {
/**
* An optional where fragment of the cypher query. WHERE is prepended to the statement
* provided and should <em>not</em> be included.
*
* @param whereStatement where fragment of the cypher query
* @return this instance for method chaining
* @see Neo4jItemReader#setWhereStatement(String)
@@ -216,7 +205,6 @@ public class Neo4jItemReaderBuilder<T> {
* A list of properties to order the results by. This is required so that subsequent
* page requests pull back the segment of results correctly. ORDER BY is prepended to
* the statement provided and should <em>not</em> be included.
*
* @param orderByStatement order by fragment of the cypher query.
* @return this instance for method chaining
* @see Neo4jItemReader#setOrderByStatement(String)
@@ -229,7 +217,6 @@ public class Neo4jItemReaderBuilder<T> {
/**
* The object type to be returned from each call to {@link Neo4jItemReader#read()}
*
* @param targetType the type of object to return.
* @return this instance for method chaining
* @see Neo4jItemReader#setTargetType(Class)
@@ -242,7 +229,6 @@ public class Neo4jItemReaderBuilder<T> {
/**
* Returns a fully constructed {@link Neo4jItemReader}.
*
* @return a new {@link Neo4jItemReader}
*/
public Neo4jItemReader<T> build() {
@@ -256,7 +242,7 @@ public class Neo4jItemReaderBuilder<T> {
Assert.hasText(this.orderByStatement, "orderByStatement is required.");
Assert.isTrue(this.pageSize > 0, "pageSize must be greater than zero");
Assert.isTrue(this.maxItemCount > 0, "maxItemCount must be greater than zero");
Assert.isTrue(this.maxItemCount > this.currentItemCount , "maxItemCount must be greater than currentItemCount");
Assert.isTrue(this.maxItemCount > this.currentItemCount, "maxItemCount must be greater than currentItemCount");
Neo4jItemReader<T> reader = new Neo4jItemReader<>();
reader.setMatchStatement(this.matchStatement);

View File

@@ -1,10 +1,10 @@
/*
* Copyright 2017-2021 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
@@ -29,7 +29,6 @@ import org.springframework.util.Assert;
* @author Mahmoud Ben Hassine
* @since 4.0
* @see Neo4jItemWriter
*
* @deprecated since 5.0 in favor of the item writer builder from
* https://github.com/spring-projects/spring-batch-extensions/blob/main/spring-batch-neo4j
*/
@@ -69,7 +68,6 @@ public class Neo4jItemWriterBuilder<T> {
/**
* Validates and builds a {@link org.springframework.batch.item.data.Neo4jItemWriter}.
*
* @return a {@link Neo4jItemWriter}
*/
public Neo4jItemWriter<T> build() {
@@ -79,4 +77,5 @@ public class Neo4jItemWriterBuilder<T> {
writer.setSessionFactory(this.sessionFactory);
return writer;
}
}

View File

@@ -64,10 +64,9 @@ public class RepositoryItemReaderBuilder<T> {
private int currentItemCount;
/**
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
* for restart purposes.
*
* Configure if the state of the
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -81,7 +80,6 @@ public class RepositoryItemReaderBuilder<T> {
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -94,7 +92,6 @@ public class RepositoryItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -107,7 +104,6 @@ public class RepositoryItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -120,7 +116,6 @@ public class RepositoryItemReaderBuilder<T> {
/**
* Arguments to be passed to the data providing method.
*
* @param arguments list of method arguments to be passed to the repository.
* @return The current instance of the builder.
* @see RepositoryItemReader#setArguments(List)
@@ -133,7 +128,6 @@ public class RepositoryItemReaderBuilder<T> {
/**
* Arguments to be passed to the data providing method.
*
* @param arguments the method arguments to be passed to the repository.
* @return The current instance of the builder.
* @see RepositoryItemReader#setArguments(List)
@@ -144,7 +138,6 @@ public class RepositoryItemReaderBuilder<T> {
/**
* Provides ordering of the results so that order is maintained between paged queries.
*
* @param sorts the fields to sort by and the directions.
* @return The current instance of the builder.
* @see RepositoryItemReader#setSort(Map)
@@ -157,7 +150,6 @@ public class RepositoryItemReaderBuilder<T> {
/**
* Establish the pageSize for the generated RepositoryItemReader.
*
* @param pageSize The number of items to retrieve per page.
* @return The current instance of the builder.
* @see RepositoryItemReader#setPageSize(int)
@@ -171,7 +163,6 @@ public class RepositoryItemReaderBuilder<T> {
/**
* The {@link org.springframework.data.repository.PagingAndSortingRepository}
* implementation used to read input from.
*
* @param repository underlying repository for input to be read from.
* @return The current instance of the builder.
* @see RepositoryItemReader#setRepository(PagingAndSortingRepository)
@@ -185,7 +176,6 @@ public class RepositoryItemReaderBuilder<T> {
/**
* Specifies what method on the repository to call. This method must take
* {@link org.springframework.data.domain.Pageable} as the <em>last</em> argument.
*
* @param methodName name of the method to invoke.
* @return The current instance of the builder.
* @see RepositoryItemReader#setMethodName(String)
@@ -199,13 +189,13 @@ public class RepositoryItemReaderBuilder<T> {
/**
* Specifies a repository and the type-safe method to call for the reader. The method
* configured via this mechanism must take
* {@link org.springframework.data.domain.Pageable} as the <em>last</em>
* argument. This method can be used in place of {@link #repository(PagingAndSortingRepository)},
* {@link #methodName(String)}, and {@link #arguments(List)}.
* {@link org.springframework.data.domain.Pageable} as the <em>last</em> argument.
* This method can be used in place of
* {@link #repository(PagingAndSortingRepository)}, {@link #methodName(String)}, and
* {@link #arguments(List)}.
*
* Note: The repository that is used by the repositoryMethodReference must be
* non-final.
*
* @param repositoryMethodReference of the used to get a repository and type-safe
* method for use by the reader.
* @return The current instance of the builder.
@@ -221,7 +211,6 @@ public class RepositoryItemReaderBuilder<T> {
/**
* Builds the {@link RepositoryItemReader}.
*
* @return a {@link RepositoryItemReader}
*/
public RepositoryItemReader<T> build() {
@@ -229,7 +218,7 @@ public class RepositoryItemReaderBuilder<T> {
this.methodName = this.repositoryMethodReference.getMethodName();
this.repository = this.repositoryMethodReference.getRepository();
if(CollectionUtils.isEmpty(this.arguments)) {
if (CollectionUtils.isEmpty(this.arguments)) {
this.arguments = this.repositoryMethodReference.getArguments();
}
}
@@ -257,10 +246,12 @@ public class RepositoryItemReaderBuilder<T> {
/**
* Establishes a proxy that will capture a the Repository and the associated
* methodName that will be used by the reader.
* @param <T> The type of repository that will be used by the reader. The class must
*
* @param <T> The type of repository that will be used by the reader. The class must
* not be final.
*/
public static class RepositoryMethodReference<T> {
private RepositoryMethodInterceptor repositoryInvocationHandler;
private PagingAndSortingRepository<?, ?> repository;
@@ -294,9 +285,11 @@ public class RepositoryItemReaderBuilder<T> {
List<Object> getArguments() {
return this.repositoryInvocationHandler.getArguments();
}
}
private static class RepositoryMethodInterceptor implements MethodInterceptor {
private String methodName;
private List<Object> arguments;
@@ -320,5 +313,7 @@ public class RepositoryItemReaderBuilder<T> {
List<Object> getArguments() {
return arguments;
}
}
}

View File

@@ -16,7 +16,6 @@
package org.springframework.batch.item.data.builder;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
@@ -50,7 +49,6 @@ public class RepositoryItemWriterBuilder<T> {
/**
* Specifies what method on the repository to call. This method must have the type of
* object passed to this writer as the <em>sole</em> argument.
*
* @param methodName the name of the method to be used for saving the item.
* @return The current instance of the builder.
* @see RepositoryItemWriter#setMethodName(String)
@@ -64,7 +62,6 @@ public class RepositoryItemWriterBuilder<T> {
/**
* Set the {@link org.springframework.data.repository.CrudRepository} implementation
* for persistence
*
* @param repository the Spring Data repository to be set
* @return The current instance of the builder.
* @see RepositoryItemWriter#setRepository(CrudRepository)
@@ -78,13 +75,12 @@ public class RepositoryItemWriterBuilder<T> {
/**
* Specifies a repository and the type-safe method to call for the writer. The method
* configured via this mechanism must take
* {@link org.springframework.data.domain.Pageable} as the <em>last</em>
* argument. This method can be used in place of {@link #repository(CrudRepository)},
* {@link org.springframework.data.domain.Pageable} as the <em>last</em> argument.
* This method can be used in place of {@link #repository(CrudRepository)},
* {@link #methodName(String)}}.
*
* Note: The repository that is used by the repositoryMethodReference must be
* non-final.
*
* @param repositoryMethodReference of the used to get a repository and type-safe
* method for use by the writer.
* @return The current instance of the builder.
@@ -92,7 +88,8 @@ public class RepositoryItemWriterBuilder<T> {
* @see RepositoryItemWriter#setRepository(CrudRepository)
*
*/
public RepositoryItemWriterBuilder<T> repository(RepositoryItemWriterBuilder.RepositoryMethodReference repositoryMethodReference) {
public RepositoryItemWriterBuilder<T> repository(
RepositoryItemWriterBuilder.RepositoryMethodReference repositoryMethodReference) {
this.repositoryMethodReference = repositoryMethodReference;
return this;
@@ -100,7 +97,6 @@ public class RepositoryItemWriterBuilder<T> {
/**
* Builds the {@link RepositoryItemWriter}.
*
* @return a {@link RepositoryItemWriter}
*/
public RepositoryItemWriter<T> build() {
@@ -116,7 +112,8 @@ public class RepositoryItemWriterBuilder<T> {
if (this.methodName != null) {
Assert.hasText(this.methodName, "methodName must not be empty.");
writer.setMethodName(this.methodName);
} else {
}
else {
logger.debug("No method name provided, CrudRepository.saveAll will be used.");
}
return writer;
@@ -125,10 +122,12 @@ public class RepositoryItemWriterBuilder<T> {
/**
* Establishes a proxy that will capture a the Repository and the associated
* methodName that will be used by the writer.
* @param <T> The type of repository that will be used by the writer. The class must
*
* @param <T> The type of repository that will be used by the writer. The class must
* not be final.
*/
public static class RepositoryMethodReference<T> {
private RepositoryMethodInterceptor repositoryInvocationHandler;
private CrudRepository<?, ?> repository;
@@ -158,14 +157,15 @@ public class RepositoryItemWriterBuilder<T> {
String getMethodName() {
return this.repositoryInvocationHandler.getMethodName();
}
}
private static class RepositoryMethodInterceptor implements MethodInterceptor {
private String methodName;
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
this.methodName = method.getName();
return null;
}
@@ -175,4 +175,5 @@ public class RepositoryItemWriterBuilder<T> {
}
}
}

View File

@@ -48,57 +48,57 @@ import org.springframework.util.Assert;
/**
* <p>
* Abstract base class for any simple item reader that opens a database cursor and continually retrieves
* the next row in the ResultSet.
* Abstract base class for any simple item reader that opens a database cursor and
* continually retrieves the next row in the ResultSet.
* </p>
*
* <p>
* By default the cursor will be opened using a separate connection. The ResultSet for the cursor
* is held open regardless of commits or roll backs in a surrounding transaction. Clients of this
* reader are responsible for buffering the items in the case that they need to be re-presented on a
* rollback. This buffering is handled by the step implementations provided and is only a concern for
* anyone writing their own step implementations.
* By default the cursor will be opened using a separate connection. The ResultSet for the
* cursor is held open regardless of commits or roll backs in a surrounding transaction.
* Clients of this reader are responsible for buffering the items in the case that they
* need to be re-presented on a rollback. This buffering is handled by the step
* implementations provided and is only a concern for anyone writing their own step
* implementations.
* </p>
*
* <p>
* There is an option ({@link #setUseSharedExtendedConnection(boolean)} that will share the connection
* used for the cursor with the rest of the step processing. If you set this flag to <code>true</code>
* then you must wrap the DataSource in a {@link ExtendedConnectionDataSourceProxy} to prevent the
* connection from being closed and released after each commit performed as part of the step processing.
* You must also use a JDBC driver supporting JDBC 3.0 or later since the cursor will be opened with the
* There is an option ({@link #setUseSharedExtendedConnection(boolean)} that will share
* the connection used for the cursor with the rest of the step processing. If you set
* this flag to <code>true</code> then you must wrap the DataSource in a
* {@link ExtendedConnectionDataSourceProxy} to prevent the connection from being closed
* and released after each commit performed as part of the step processing. You must also
* use a JDBC driver supporting JDBC 3.0 or later since the cursor will be opened with the
* additional option of 'HOLD_CURSORS_OVER_COMMIT' enabled.
* </p>
*
* <p>
* Each call to {@link #read()} will attempt to map the row at the current position in the
* ResultSet. There is currently no wrapping of the ResultSet to suppress calls
* to next(). However, if the RowMapper (mistakenly) increments the current row,
* the next call to read will verify that the current row is at the expected
* position and throw a DataAccessException if it is not. The reason for such strictness on the
* ResultSet is due to the need to maintain control for transactions and
* restartability. This ensures that each call to {@link #read()} returns the
* ResultSet at the correct row, regardless of rollbacks or restarts.
* ResultSet. There is currently no wrapping of the ResultSet to suppress calls to next().
* However, if the RowMapper (mistakenly) increments the current row, the next call to
* read will verify that the current row is at the expected position and throw a
* DataAccessException if it is not. The reason for such strictness on the ResultSet is
* due to the need to maintain control for transactions and restartability. This ensures
* that each call to {@link #read()} returns the ResultSet at the correct row, regardless
* of rollbacks or restarts.
* </p>
*
* <p>
* {@link ExecutionContext}: The current row is returned as restart data, and
* when restored from that same data, the cursor is opened and the current row
* set to the value within the restart data. See
* {@link #setDriverSupportsAbsolute(boolean)} for improving restart
* performance.
* {@link ExecutionContext}: The current row is returned as restart data, and when
* restored from that same data, the cursor is opened and the current row set to the value
* within the restart data. See {@link #setDriverSupportsAbsolute(boolean)} for improving
* restart performance.
* </p>
*
* <p>
* Calling close on this {@link ItemStream} will cause all resources it is
* currently using to be freed. (Connection, ResultSet, etc). It is then illegal
* to call {@link #read()} again until it has been re-opened.
* Calling close on this {@link ItemStream} will cause all resources it is currently using
* to be freed. (Connection, ResultSet, etc). It is then illegal to call {@link #read()}
* again until it has been re-opened.
* </p>
*
* <p>
* Known limitation: when used with Derby
* {@link #setVerifyCursorPosition(boolean)} needs to be <code>false</code>
* because {@link ResultSet#getRow()} call used for cursor position verification
* is not available for 'TYPE_FORWARD_ONLY' result sets.
* Known limitation: when used with Derby {@link #setVerifyCursorPosition(boolean)} needs
* to be <code>false</code> because {@link ResultSet#getRow()} call used for cursor
* position verification is not available for 'TYPE_FORWARD_ONLY' result sets.
* </p>
*
* @author Lucas Ward
@@ -109,12 +109,13 @@ import org.springframework.util.Assert;
* @author Mahmoud Ben Hassine
*/
public abstract class AbstractCursorItemReader<T> extends AbstractItemCountingItemStreamItemReader<T>
implements InitializingBean {
implements InitializingBean {
/** Logger available to subclasses */
protected final Log log = LogFactory.getLog(getClass());
public static final int VALUE_NOT_SET = -1;
private Connection con;
protected ResultSet rs;
@@ -149,9 +150,7 @@ implements InitializingBean {
/**
* Assert that mandatory properties are set.
*
* @throws IllegalArgumentException if either data source or SQL properties
* not set.
* @throws IllegalArgumentException if either data source or SQL properties not set.
*/
@Override
public void afterPropertiesSet() throws Exception {
@@ -160,7 +159,6 @@ implements InitializingBean {
/**
* Public setter for the data source for injection purposes.
*
* @param dataSource {@link javax.sql.DataSource} to be used
*/
public void setDataSource(DataSource dataSource) {
@@ -169,7 +167,6 @@ implements InitializingBean {
/**
* Public getter for the data source.
*
* @return the dataSource
*/
public DataSource getDataSource() {
@@ -177,12 +174,10 @@ implements InitializingBean {
}
/**
* Prepare the given JDBC Statement (or PreparedStatement or
* CallableStatement), applying statement settings such as fetch size, max
* rows, and query timeout. @param stmt the JDBC Statement to prepare
*
* Prepare the given JDBC Statement (or PreparedStatement or CallableStatement),
* applying statement settings such as fetch size, max rows, and query timeout. @param
* stmt the JDBC Statement to prepare
* @param stmt {@link java.sql.PreparedStatement} to be configured
*
* @throws SQLException if interactions with provided stmt fail
*
* @see #setFetchSize
@@ -203,13 +198,12 @@ implements InitializingBean {
}
/**
* Creates a default SQLErrorCodeSQLExceptionTranslator for the specified
* DataSource if none is set.
*
* Creates a default SQLErrorCodeSQLExceptionTranslator for the specified DataSource
* if none is set.
* @return the exception translator for this instance.
*/
protected SQLExceptionTranslator getExceptionTranslator() {
synchronized(this) {
synchronized (this) {
if (exceptionTranslator == null) {
if (dataSource != null) {
exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource);
@@ -231,16 +225,15 @@ implements InitializingBean {
}
/**
* Throw a SQLWarningException if we're not ignoring warnings, else log the
* warnings (at debug level).
*
* @param statement the current statement to obtain the warnings from, if there are any.
* Throw a SQLWarningException if we're not ignoring warnings, else log the warnings
* (at debug level).
* @param statement the current statement to obtain the warnings from, if there are
* any.
* @throws SQLException if interaction with provided statement fails.
*
* @see org.springframework.jdbc.SQLWarningException
*/
protected void handleWarnings(Statement statement) throws SQLWarningException,
SQLException {
protected void handleWarnings(Statement statement) throws SQLWarningException, SQLException {
if (ignoreWarnings) {
if (log.isDebugEnabled()) {
SQLWarning warningToLog = statement.getWarnings();
@@ -260,8 +253,8 @@ implements InitializingBean {
}
/**
* Moves the cursor in the ResultSet to the position specified by the row
* parameter by traversing the ResultSet.
* Moves the cursor in the ResultSet to the position specified by the row parameter by
* traversing the ResultSet.
* @param row The index of the row to move to
*/
private void moveCursorToRow(int row) {
@@ -277,11 +270,9 @@ implements InitializingBean {
}
/**
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for this
* <code>ResultSet</code> object. If the fetch size specified is zero, the
* JDBC driver ignores the value.
*
* Gives the JDBC driver a hint as to the number of rows that should be fetched from
* the database when more rows are needed for this <code>ResultSet</code> object. If
* the fetch size specified is zero, the JDBC driver ignores the value.
* @param fetchSize the number of rows to fetch
* @see ResultSet#setFetchSize(int)
*/
@@ -290,9 +281,8 @@ implements InitializingBean {
}
/**
* Sets the limit for the maximum number of rows that any
* <code>ResultSet</code> object can contain to the given number.
*
* Sets the limit for the maximum number of rows that any <code>ResultSet</code>
* object can contain to the given number.
* @param maxRows the new max rows limit; zero means there is no limit
* @see Statement#setMaxRows(int)
*/
@@ -301,12 +291,11 @@ implements InitializingBean {
}
/**
* Sets the number of seconds the driver will wait for a
* <code>Statement</code> object to execute to the given number of seconds.
* If the limit is exceeded, an <code>SQLException</code> is thrown.
*
* @param queryTimeout seconds the new query timeout limit in seconds; zero
* means there is no limit
* Sets the number of seconds the driver will wait for a <code>Statement</code> object
* to execute to the given number of seconds. If the limit is exceeded, an
* <code>SQLException</code> is thrown.
* @param queryTimeout seconds the new query timeout limit in seconds; zero means
* there is no limit
* @see Statement#setQueryTimeout(int)
*/
public void setQueryTimeout(int queryTimeout) {
@@ -314,9 +303,8 @@ implements InitializingBean {
}
/**
* Set whether SQLWarnings should be ignored (only logged) or exception
* should be thrown.
*
* Set whether SQLWarnings should be ignored (only logged) or exception should be
* thrown.
* @param ignoreWarnings if TRUE, warnings are ignored
*/
public void setIgnoreWarnings(boolean ignoreWarnings) {
@@ -324,9 +312,8 @@ implements InitializingBean {
}
/**
* Allow verification of cursor position after current row is processed by
* RowMapper or RowCallbackHandler. Default value is TRUE.
*
* Allow verification of cursor position after current row is processed by RowMapper
* or RowCallbackHandler. Default value is TRUE.
* @param verifyCursorPosition if true, cursor position is verified
*/
public void setVerifyCursorPosition(boolean verifyCursorPosition) {
@@ -335,13 +322,11 @@ implements InitializingBean {
/**
* Indicate whether the JDBC driver supports setting the absolute row on a
* {@link ResultSet}. It is recommended that this is set to
* <code>true</code> for JDBC drivers that supports ResultSet.absolute() as
* it may improve performance, especially if a step fails while working with
* a large data set.
* {@link ResultSet}. It is recommended that this is set to <code>true</code> for JDBC
* drivers that supports ResultSet.absolute() as it may improve performance,
* especially if a step fails while working with a large data set.
*
* @see ResultSet#absolute(int)
*
* @param driverSupportsAbsolute <code>false</code> by default
*/
public void setDriverSupportsAbsolute(boolean driverSupportsAbsolute) {
@@ -349,19 +334,19 @@ implements InitializingBean {
}
/**
* Indicate whether the connection used for the cursor should be used by all other processing
* thus sharing the same transaction. If this is set to false, which is the default, then the
* cursor will be opened using in its connection and will not participate in any transactions
* started for the rest of the step processing. If you set this flag to true then you must
* wrap the DataSource in a {@link ExtendedConnectionDataSourceProxy} to prevent the
* connection from being closed and released after each commit.
*
* When you set this option to <code>true</code> then the statement used to open the cursor
* will be created with both 'READ_ONLY' and 'HOLD_CURSORS_OVER_COMMIT' options. This allows
* holding the cursor open over transaction start and commits performed in the step processing.
* To use this feature you need a database that supports this and a JDBC driver supporting
* JDBC 3.0 or later.
* Indicate whether the connection used for the cursor should be used by all other
* processing thus sharing the same transaction. If this is set to false, which is the
* default, then the cursor will be opened using in its connection and will not
* participate in any transactions started for the rest of the step processing. If you
* set this flag to true then you must wrap the DataSource in a
* {@link ExtendedConnectionDataSourceProxy} to prevent the connection from being
* closed and released after each commit.
*
* When you set this option to <code>true</code> then the statement used to open the
* cursor will be created with both 'READ_ONLY' and 'HOLD_CURSORS_OVER_COMMIT'
* options. This allows holding the cursor open over transaction start and commits
* performed in the step processing. To use this feature you need a database that
* supports this and a JDBC driver supporting JDBC 3.0 or later.
* @param useSharedExtendedConnection <code>false</code> by default
*/
public void setUseSharedExtendedConnection(boolean useSharedExtendedConnection) {
@@ -373,9 +358,8 @@ implements InitializingBean {
}
/**
* Set whether "autoCommit" should be overridden for the connection used by the cursor. If not set, defaults to
* Connection / Datasource default configuration.
*
* Set whether "autoCommit" should be overridden for the connection used by the
* cursor. If not set, defaults to Connection / Datasource default configuration.
* @param autoCommit value used for {@link Connection#setAutoCommit(boolean)}.
* @since 4.0
*/
@@ -386,8 +370,8 @@ implements InitializingBean {
public abstract String getSql();
/**
* Check the result set is in sync with the currentRow attribute. This is
* important to ensure that the user hasn't modified the current row.
* Check the result set is in sync with the currentRow attribute. This is important to
* ensure that the user hasn't modified the current row.
*/
private void verifyCursorPosition(long expectedCurrentRow) throws SQLException {
if (verifyCursorPosition) {
@@ -398,8 +382,8 @@ implements InitializingBean {
}
/**
* Close the cursor and database connection. Make call to cleanupOnClose so sub classes can cleanup
* any resources they have allocated.
* Close the cursor and database connection. Make call to cleanupOnClose so sub
* classes can cleanup any resources they have allocated.
*/
@Override
protected void doClose() throws Exception {
@@ -408,12 +392,12 @@ implements InitializingBean {
rs = null;
cleanupOnClose(con);
if(this.con != null && !this.con.isClosed()) {
if (this.con != null && !this.con.isClosed()) {
this.con.setAutoCommit(this.initialConnectionAutoCommit);
}
if (useSharedExtendedConnection && dataSource instanceof ExtendedConnectionDataSourceProxy) {
((ExtendedConnectionDataSourceProxy)dataSource).stopCloseSuppression(this.con);
((ExtendedConnectionDataSourceProxy) dataSource).stopCloseSuppression(this.con);
if (!TransactionSynchronizationManager.isActualTransactionActive()) {
DataSourceUtils.releaseConnection(con, dataSource);
}
@@ -428,7 +412,7 @@ implements InitializingBean {
* @param connection to the database
* @throws Exception If unable to clean up resources
*/
protected abstract void cleanupOnClose(Connection connection) throws Exception;
protected abstract void cleanupOnClose(Connection connection) throws Exception;
/**
* Execute the statement to open the cursor.
@@ -452,11 +436,11 @@ implements InitializingBean {
if (useSharedExtendedConnection) {
if (!(getDataSource() instanceof ExtendedConnectionDataSourceProxy)) {
throw new InvalidDataAccessApiUsageException(
"You must use a ExtendedConnectionDataSourceProxy for the dataSource when " +
"useSharedExtendedConnection is set to true.");
"You must use a ExtendedConnectionDataSourceProxy for the dataSource when "
+ "useSharedExtendedConnection is set to true.");
}
this.con = DataSourceUtils.getConnection(dataSource);
((ExtendedConnectionDataSourceProxy)dataSource).startCloseSuppression(this.con);
((ExtendedConnectionDataSourceProxy) dataSource).startCloseSuppression(this.con);
}
else {
this.con = dataSource.getConnection();
@@ -502,9 +486,8 @@ implements InitializingBean {
}
/**
* Read the cursor and map to the type of object this reader should return. This method must be
* overridden by subclasses.
*
* Read the cursor and map to the type of object this reader should return. This
* method must be overridden by subclasses.
* @param rs The current result set
* @param currentRow Current position of the result set
* @return the mapped object at the cursor position
@@ -514,8 +497,8 @@ implements InitializingBean {
protected abstract T readCursor(ResultSet rs, int currentRow) throws SQLException;
/**
* Use {@link ResultSet#absolute(int)} if possible, otherwise scroll by
* calling {@link ResultSet#next()}.
* Use {@link ResultSet#absolute(int)} if possible, otherwise scroll by calling
* {@link ResultSet#next()}.
*/
@Override
protected void jumpToItem(int itemIndex) throws Exception {

View File

@@ -30,18 +30,18 @@ import org.springframework.util.ClassUtils;
* reading database records in a paging fashion.
*
* <p>
* Implementations should execute queries using paged requests of a size
* specified in {@link #setPageSize(int)}. Additional pages are requested when
* needed as {@link #read()} method is called, returning an object corresponding
* to current position.
* Implementations should execute queries using paged requests of a size specified in
* {@link #setPageSize(int)}. Additional pages are requested when needed as
* {@link #read()} method is called, returning an object corresponding to current
* position.
* </p>
*
* @author Thomas Risberg
* @author Dave Syer
* @since 2.0
*/
public abstract class AbstractPagingItemReader<T> extends AbstractItemCountingItemStreamItemReader<T>
implements InitializingBean {
public abstract class AbstractPagingItemReader<T> extends AbstractItemCountingItemStreamItemReader<T>
implements InitializingBean {
protected Log logger = LogFactory.getLog(getClass());
@@ -79,7 +79,6 @@ public abstract class AbstractPagingItemReader<T> extends AbstractItemCountingIt
/**
* The number of rows to retrieve at a time.
*
* @param pageSize the number of rows to fetch per page
*/
public void setPageSize(int pageSize) {

View File

@@ -19,8 +19,9 @@ import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
/**
* A convenient implementation for providing BeanPropertySqlParameterSource when the item has JavaBean properties
* that correspond to names used for parameters in the SQL statement.
* A convenient implementation for providing BeanPropertySqlParameterSource when the item
* has JavaBean properties that correspond to names used for parameters in the SQL
* statement.
*
* @author Thomas Risberg
* @since 2.0
@@ -28,8 +29,8 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
public class BeanPropertyItemSqlParameterSourceProvider<T> implements ItemSqlParameterSourceProvider<T> {
/**
* Provide parameter values in an {@link BeanPropertySqlParameterSource} based on values from
* the provided item.
* Provide parameter values in an {@link BeanPropertySqlParameterSource} based on
* values from the provided item.
* @param item the item to use for parameter values
*/
@Override

View File

@@ -37,43 +37,39 @@ import org.springframework.util.Assert;
import org.springframework.util.MethodInvoker;
/**
* Implementation of {@link SmartDataSource} that is capable of keeping a single
* JDBC Connection which is NOT closed after each use even if
* {@link Connection#close()} is called.
* Implementation of {@link SmartDataSource} that is capable of keeping a single JDBC
* Connection which is NOT closed after each use even if {@link Connection#close()} is
* called.
*
* The connection can be kept open over multiple transactions when used together
* with any of Spring's
* {@link org.springframework.transaction.PlatformTransactionManager}
* The connection can be kept open over multiple transactions when used together with any
* of Spring's {@link org.springframework.transaction.PlatformTransactionManager}
* implementations.
*
* <p>
* Loosely based on the SingleConnectionDataSource implementation in Spring
* Core. Intended to be used with the {@link JdbcCursorItemReader} to provide a
* connection that remains open across transaction boundaries, It remains open
* for the life of the cursor, and can be shared with the main transaction of
* the rest of the step processing.
* Loosely based on the SingleConnectionDataSource implementation in Spring Core. Intended
* to be used with the {@link JdbcCursorItemReader} to provide a connection that remains
* open across transaction boundaries, It remains open for the life of the cursor, and can
* be shared with the main transaction of the rest of the step processing.
*
* <p>
* Once close suppression has been turned on for a connection, it will be
* returned for the first {@link #getConnection()} call. Any subsequent calls to
* {@link #getConnection()} will retrieve a new connection from the wrapped
* {@link DataSource} until the {@link DataSourceUtils} queries whether the
* connection should be closed or not by calling
* {@link #shouldClose(Connection)} for the close-suppressed {@link Connection}.
* At that point the cycle starts over again, and the next
* {@link #getConnection()} call will have the {@link Connection} that is being
* close-suppressed returned. This allows the use of the close-suppressed
* {@link Connection} to be the main {@link Connection} for an extended data
* access process. The close suppression is turned off by calling
* Once close suppression has been turned on for a connection, it will be returned for the
* first {@link #getConnection()} call. Any subsequent calls to {@link #getConnection()}
* will retrieve a new connection from the wrapped {@link DataSource} until the
* {@link DataSourceUtils} queries whether the connection should be closed or not by
* calling {@link #shouldClose(Connection)} for the close-suppressed {@link Connection}.
* At that point the cycle starts over again, and the next {@link #getConnection()} call
* will have the {@link Connection} that is being close-suppressed returned. This allows
* the use of the close-suppressed {@link Connection} to be the main {@link Connection}
* for an extended data access process. The close suppression is turned off by calling
* {@link #stopCloseSuppression(Connection)}.
*
* <p>
* This class is not multi-threading capable.
*
* <p>
* The connection returned will be a close-suppressing proxy instead of the
* physical {@link Connection}. Be aware that you will not be able to cast this
* to a native <code>OracleConnection</code> or the like anymore; you'd be required to use
* The connection returned will be a close-suppressing proxy instead of the physical
* {@link Connection}. Be aware that you will not be able to cast this to a native
* <code>OracleConnection</code> or the like anymore; you'd be required to use
* {@link java.sql.Connection#unwrap(Class)}.
*
* @author Thomas Risberg
@@ -104,9 +100,7 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
}
/**
* Constructor that takes as a parameter with the {@link DataSource} to be
* wrapped.
*
* Constructor that takes as a parameter with the {@link DataSource} to be wrapped.
* @param dataSource DataSource to be used
*/
public ExtendedConnectionDataSourceProxy(DataSource dataSource) {
@@ -115,7 +109,6 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
/**
* Setter for the {@link DataSource} that is to be wrapped.
*
* @param dataSource the DataSource
*/
public void setDataSource(DataSource dataSource) {
@@ -137,9 +130,8 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
/**
* Return the status of close suppression being activated for a given
* {@link Connection}
*
* @param connection the {@link Connection} that the close suppression
* status is requested for
* @param connection the {@link Connection} that the close suppression status is
* requested for
* @return true or false
*/
public boolean isCloseSuppressionActive(Connection connection) {
@@ -147,9 +139,7 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
}
/**
*
* @param connection the {@link Connection} that close suppression is
* requested for
* @param connection the {@link Connection} that close suppression is requested for
*/
public void startCloseSuppression(Connection connection) {
synchronized (this.connectionMonitor) {
@@ -161,9 +151,8 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
}
/**
*
* @param connection the {@link Connection} that close suppression should be
* turned off for
* @param connection the {@link Connection} that close suppression should be turned
* off for
*/
public void stopCloseSuppression(Connection connection) {
synchronized (this.connectionMonitor) {
@@ -232,8 +221,8 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
}
/**
* Wrap the given Connection with a proxy that delegates every method call
* to it but suppresses close calls.
* Wrap the given Connection with a proxy that delegates every method call to it but
* suppresses close calls.
* @param target the original Connection to wrap
* @return the wrapped Connection
*/
@@ -243,9 +232,9 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
}
/**
* Invocation handler that suppresses close calls on JDBC Connections until
* the associated instance of the ExtendedConnectionDataSourceProxy
* determines the connection should actually be closed.
* Invocation handler that suppresses close calls on JDBC Connections until the
* associated instance of the ExtendedConnectionDataSourceProxy determines the
* connection should actually be closed.
*/
private static class CloseSuppressingInvocationHandler implements InvocationHandler {
@@ -263,26 +252,26 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
// Invocation on ConnectionProxy interface coming in...
switch (method.getName()) {
case "equals":
// Only consider equal when proxies are identical.
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
case "hashCode":
// Use hashCode of Connection proxy.
return System.identityHashCode(proxy);
case "close":
// Handle close method: don't pass the call on if we are
// suppressing close calls.
if (dataSource.completeCloseCall((Connection) proxy)) {
return null;
}
else {
target.close();
return null;
}
case "getTargetConnection":
// Handle getTargetConnection method: return underlying
// Connection.
return this.target;
case "equals":
// Only consider equal when proxies are identical.
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
case "hashCode":
// Use hashCode of Connection proxy.
return System.identityHashCode(proxy);
case "close":
// Handle close method: don't pass the call on if we are
// suppressing close calls.
if (dataSource.completeCloseCall((Connection) proxy)) {
return null;
}
else {
target.close();
return null;
}
case "getTargetConnection":
// Handle getTargetConnection method: return underlying
// Connection.
return this.target;
}
// Invoke method on target Connection.
@@ -293,11 +282,12 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
throw ex.getTargetException();
}
}
}
/**
* Performs only a 'shallow' non-recursive check of self's and delegate's
* class to retain Java 5 compatibility.
* Performs only a 'shallow' non-recursive check of self's and delegate's class to
* retain Java 5 compatibility.
*/
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
@@ -305,9 +295,9 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
}
/**
* Returns either self or delegate (in this order) if one of them can be
* cast to supplied parameter class. Does *not* support recursive unwrapping
* of the delegate to retain Java 5 compatibility.
* Returns either self or delegate (in this order) if one of them can be cast to
* supplied parameter class. Does *not* support recursive unwrapping of the delegate
* to retain Java 5 compatibility.
*/
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
@@ -332,7 +322,7 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
/**
* Added due to JDK 7 compatibility.
*/
public Logger getParentLogger() throws SQLFeatureNotSupportedException{
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
MethodInvoker invoker = new MethodInvoker();
invoker.setTargetObject(dataSource);
invoker.setTargetMethod("getParentLogger");
@@ -340,8 +330,11 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi
try {
invoker.prepare();
return (Logger) invoker.invoke();
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException nsme) {
}
catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
| InvocationTargetException nsme) {
throw new SQLFeatureNotSupportedException(nsme);
}
}
}

View File

@@ -33,21 +33,19 @@ import org.springframework.util.ClassUtils;
/**
* {@link ItemStreamReader} for reading database records built on top of Hibernate. It
* executes the HQL query when initialized iterates over the result set as
* {@link #read()} method is called, returning an object corresponding to
* current row. The query can be set directly using
* {@link #setQueryString(String)}, a named query can be used by
* {@link #setQueryName(String)}, or a query provider strategy can be supplied
* via {@link #setQueryProvider(HibernateQueryProvider)}.
* executes the HQL query when initialized iterates over the result set as {@link #read()}
* method is called, returning an object corresponding to current row. The query can be
* set directly using {@link #setQueryString(String)}, a named query can be used by
* {@link #setQueryName(String)}, or a query provider strategy can be supplied via
* {@link #setQueryProvider(HibernateQueryProvider)}.
*
*
* <p>
* The reader can be configured to use either {@link StatelessSession}
* sufficient for simple mappings without the need to cascade to associated
* objects or standard hibernate {@link Session} for more advanced mappings or
* when caching is desired. When stateful session is used it will be cleared in
* the {@link #update(ExecutionContext)} method without being flushed (no data
* modifications are expected).
* The reader can be configured to use either {@link StatelessSession} sufficient for
* simple mappings without the need to cascade to associated objects or standard hibernate
* {@link Session} for more advanced mappings or when caching is desired. When stateful
* session is used it will be cleared in the {@link #update(ExecutionContext)} method
* without being flushed (no data modifications are expected).
* </p>
*
* The implementation is <b>not</b> thread-safe.
@@ -55,8 +53,8 @@ import org.springframework.util.ClassUtils;
* @author Robert Kasanicky
* @author Dave Syer
*/
public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStreamItemReader<T>
implements InitializingBean {
public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStreamItemReader<T>
implements InitializingBean {
private HibernateItemReaderHelper<T> helper = new HibernateItemReaderHelper<>();
@@ -80,7 +78,6 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
/**
* The parameter values to apply to a query (map of name:value).
*
* @param parameterValues the parameter values to set
*/
public void setParameterValues(Map<String, Object> parameterValues) {
@@ -90,9 +87,7 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
/**
* A query name for an externalized query. Either this or the {
* {@link #setQueryString(String) query string} or the {
* {@link #setQueryProvider(HibernateQueryProvider) query provider} should
* be set.
*
* {@link #setQueryProvider(HibernateQueryProvider) query provider} should be set.
* @param queryName name of a hibernate named query
*/
public void setQueryName(String queryName) {
@@ -100,9 +95,8 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
}
/**
* Fetch size used internally by Hibernate to limit amount of data fetched
* from database per round trip.
*
* Fetch size used internally by Hibernate to limit amount of data fetched from
* database per round trip.
* @param fetchSize the fetch size to pass down to Hibernate
*/
public void setFetchSize(int fetchSize) {
@@ -110,10 +104,8 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
}
/**
* A query provider. Either this or the {{@link #setQueryString(String)
* query string} or the {{@link #setQueryName(String) query name} should be
* set.
*
* A query provider. Either this or the {{@link #setQueryString(String) query string}
* or the {{@link #setQueryName(String) query name} should be set.
* @param queryProvider Hibernate query provider
*/
public void setQueryProvider(HibernateQueryProvider<T> queryProvider) {
@@ -124,7 +116,6 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
* A query string in HQL. Either this or the {
* {@link #setQueryProvider(HibernateQueryProvider) query provider} or the {
* {@link #setQueryName(String) query name} should be set.
*
* @param queryString HQL query string
*/
public void setQueryString(String queryString) {
@@ -133,7 +124,6 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
/**
* The Hibernate SessionFactory to use the create a session.
*
* @param sessionFactory the {@link SessionFactory} to set
*/
public void setSessionFactory(SessionFactory sessionFactory) {
@@ -142,10 +132,8 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
/**
* Can be set only in uninitialized state.
*
* @param useStatelessSession <code>true</code> to use
* {@link StatelessSession} <code>false</code> to use standard hibernate
* {@link Session}
* @param useStatelessSession <code>true</code> to use {@link StatelessSession}
* <code>false</code> to use standard hibernate {@link Session}
*/
public void setUseStatelessSession(boolean useStatelessSession) {
helper.setUseStatelessSession(useStatelessSession);
@@ -190,7 +178,6 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
/**
* Update the context and clear the session if stateful.
*
* @param executionContext the current {@link ExecutionContext}
* @throws ItemStreamException if there is a problem
*/
@@ -201,11 +188,9 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
}
/**
* Wind forward through the result set to the item requested. Also clears
* the session every now and then (if stateful) to avoid memory problems.
* The frequency of session clearing is the larger of the fetch size (if
* set) and 100.
*
* Wind forward through the result set to the item requested. Also clears the session
* every now and then (if stateful) to avoid memory problems. The frequency of session
* clearing is the larger of the fetch size (if set) and 100.
* @param itemIndex the first item to read
* @throws Exception if there is a problem
* @see AbstractItemCountingItemStreamItemReader#jumpToItem(int)
@@ -222,7 +207,7 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
@Override
protected void doClose() throws Exception {
if(initialized) {
if (initialized) {
if (cursor != null) {
cursor.close();
}
@@ -232,4 +217,5 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
initialized = false;
}
}

View File

@@ -32,8 +32,7 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* Internal shared state helper for hibernate readers managing sessions and
* queries.
* Internal shared state helper for hibernate readers managing sessions and queries.
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
@@ -78,14 +77,12 @@ public class HibernateItemReaderHelper<T> implements InitializingBean {
/**
* Can be set only in uninitialized state.
*
* @param useStatelessSession <code>true</code> to use
* {@link StatelessSession} <code>false</code> to use standard hibernate
* {@link Session}
* @param useStatelessSession <code>true</code> to use {@link StatelessSession}
* <code>false</code> to use standard hibernate {@link Session}
*/
public void setUseStatelessSession(boolean useStatelessSession) {
Assert.state(statefulSession == null && statelessSession == null,
"The useStatelessSession flag can only be set before a session is initialized.");
"The useStatelessSession flag can only be set before a session is initialized.");
this.useStatelessSession = useStatelessSession;
}
@@ -104,16 +101,14 @@ public class HibernateItemReaderHelper<T> implements InitializingBean {
if (queryProvider == null) {
Assert.notNull(sessionFactory, "session factory must be set");
Assert.state(StringUtils.hasText(queryString) ^ StringUtils.hasText(queryName),
"queryString or queryName must be set");
"queryString or queryName must be set");
}
}
/**
* Get a cursor over all of the results, with the forward-only flag set.
*
* @param fetchSize the fetch size to use retrieving the results
* @param parameterValues the parameter values to use (or null if none).
*
* @return a forward-only {@link ScrollableResults}
*/
public ScrollableResults getForwardOnlyCursor(int fetchSize, Map<String, Object> parameterValues) {
@@ -126,7 +121,6 @@ public class HibernateItemReaderHelper<T> implements InitializingBean {
/**
* Open appropriate type of hibernate session and create the query.
*
* @return a Hibernate Query
*/
@SuppressWarnings("unchecked") // Hibernate APIs do not use a typed Query
@@ -172,7 +166,6 @@ public class HibernateItemReaderHelper<T> implements InitializingBean {
/**
* Scroll through the results up to the item specified.
*
* @param cursor the results to scroll over
* @param itemIndex index to scroll to
* @param flushInterval the number of items to scroll past before flushing
@@ -201,17 +194,16 @@ public class HibernateItemReaderHelper<T> implements InitializingBean {
}
/**
* Read a page of data, clearing the existing session (if necessary) first,
* and creating a new session before executing the query.
*
* Read a page of data, clearing the existing session (if necessary) first, and
* creating a new session before executing the query.
* @param page the page to read (starting at 0)
* @param pageSize the size of the page or maximum number of items to read
* @param fetchSize the fetch size to use
* @param parameterValues the parameter values to use (if any, otherwise
* null)
* @param parameterValues the parameter values to use (if any, otherwise null)
* @return a collection of items
*/
public Collection<? extends T> readPage(int page, int pageSize, int fetchSize, Map<String, Object> parameterValues) {
public Collection<? extends T> readPage(int page, int pageSize, int fetchSize,
Map<String, Object> parameterValues) {
clear();

View File

@@ -28,16 +28,15 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* {@link ItemWriter} that uses a Hibernate session to save or update entities
* that are not part of the current Hibernate session. It will also flush the
* session after writing (i.e. at chunk boundaries if used in a Spring Batch
* TaskletStep). It will also clear the session on write
* default (see {@link #setClearSession(boolean) clearSession} property).<br>
* {@link ItemWriter} that uses a Hibernate session to save or update entities that are
* not part of the current Hibernate session. It will also flush the session after writing
* (i.e. at chunk boundaries if used in a Spring Batch TaskletStep). It will also clear
* the session on write default (see {@link #setClearSession(boolean) clearSession}
* property).<br>
* <br>
*
* The writer is thread-safe once properties are set (normal singleton behavior)
* if a {@link CurrentSessionContext} that uses only one session per thread is
* used.
* The writer is thread-safe once properties are set (normal singleton behavior) if a
* {@link CurrentSessionContext} that uses only one session per thread is used.
*
* @author Dave Syer
* @author Thomas Risberg
@@ -47,19 +46,16 @@ import org.springframework.util.Assert;
*/
public class HibernateItemWriter<T> implements ItemWriter<T>, InitializingBean {
protected static final Log logger = LogFactory
.getLog(HibernateItemWriter.class);
protected static final Log logger = LogFactory.getLog(HibernateItemWriter.class);
private SessionFactory sessionFactory;
private boolean clearSession = true;
/**
* Flag to indicate that the session should be cleared and flushed at the
* end of the write (default true).
*
* @param clearSession
* the flag value to set
* Flag to indicate that the session should be cleared and flushed at the end of the
* write (default true).
* @param clearSession the flag value to set
*/
public void setClearSession(boolean clearSession) {
this.clearSession = clearSession;
@@ -67,7 +63,6 @@ public class HibernateItemWriter<T> implements ItemWriter<T>, InitializingBean {
/**
* Set the Hibernate SessionFactory to be used internally.
*
* @param sessionFactory session factory to be used by the writer
*/
public void setSessionFactory(SessionFactory sessionFactory) {
@@ -79,13 +74,12 @@ public class HibernateItemWriter<T> implements ItemWriter<T>, InitializingBean {
*/
@Override
public void afterPropertiesSet() {
Assert.state(sessionFactory != null,
"SessionFactory must be provided");
Assert.state(sessionFactory != null, "SessionFactory must be provided");
}
/**
* Save or update any entities not in the current hibernate session and then
* flush the hibernate session.
* 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)
*/
@@ -93,22 +87,20 @@ public class HibernateItemWriter<T> implements ItemWriter<T>, InitializingBean {
public void write(List<? extends T> items) {
doWrite(sessionFactory, items);
sessionFactory.getCurrentSession().flush();
if(clearSession) {
if (clearSession) {
sessionFactory.getCurrentSession().clear();
}
}
/**
* Do perform the actual write operation using Hibernate's API.
* This can be overridden in a subclass if necessary.
*
* Do perform the actual write operation using Hibernate's API. This can be overridden
* in a subclass if necessary.
* @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) {
if (logger.isDebugEnabled()) {
logger.debug("Writing to Hibernate with " + items.size()
+ " items.");
logger.debug("Writing to Hibernate with " + items.size() + " items.");
}
Session currentSession = sessionFactory.getCurrentSession();
@@ -123,8 +115,7 @@ public class HibernateItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
if (logger.isDebugEnabled()) {
logger.debug(saveOrUpdateCount + " entities saved/updated.");
logger.debug((items.size() - saveOrUpdateCount)
+ " entities found in session.");
logger.debug((items.size() - saveOrUpdateCount) + " entities found in session.");
}
}
}

View File

@@ -29,36 +29,31 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* {@link ItemReader} for reading database records built on top of Hibernate and
* reading only up to a fixed number of items at a time. It executes an HQL
* query when initialized is paged as the {@link #read()} method is called. The
* query can be set directly using {@link #setQueryString(String)}, a named
* query can be used by {@link #setQueryName(String)}, or a query provider
* strategy can be supplied via
* {@link ItemReader} for reading database records built on top of Hibernate and reading
* only up to a fixed number of items at a time. It executes an HQL query when initialized
* is paged as the {@link #read()} method is called. The query can be set directly using
* {@link #setQueryString(String)}, a named query can be used by
* {@link #setQueryName(String)}, or a query provider strategy can be supplied via
* {@link #setQueryProvider(HibernateQueryProvider)}.
*
* <p>
* The reader can be configured to use either {@link StatelessSession}
* sufficient for simple mappings without the need to cascade to associated
* objects or standard hibernate {@link Session} for more advanced mappings or
* when caching is desired. When stateful session is used it will be cleared in
* the {@link #update(ExecutionContext)} method without being flushed (no data
* modifications are expected).
* The reader can be configured to use either {@link StatelessSession} sufficient for
* simple mappings without the need to cascade to associated objects or standard hibernate
* {@link Session} for more advanced mappings or when caching is desired. When stateful
* session is used it will be cleared in the {@link #update(ExecutionContext)} method
* without being flushed (no data modifications are expected).
* </p>
*
* <p>
* The implementation is thread-safe in between calls to
* {@link #open(ExecutionContext)}, but remember to use
* <code>saveState=false</code> if used in a multi-threaded client (no restart
* available).
* The implementation is thread-safe in between calls to {@link #open(ExecutionContext)},
* but remember to use <code>saveState=false</code> if used in a multi-threaded client (no
* restart available).
* </p>
*
* @author Dave Syer
*
* @since 2.1
*/
public class HibernatePagingItemReader<T> extends AbstractPagingItemReader<T>
implements InitializingBean {
public class HibernatePagingItemReader<T> extends AbstractPagingItemReader<T> implements InitializingBean {
private HibernateItemReaderHelper<T> helper = new HibernateItemReaderHelper<>();
@@ -72,7 +67,6 @@ public class HibernatePagingItemReader<T> extends AbstractPagingItemReader<T>
/**
* The parameter values to apply to a query (map of name:value).
*
* @param parameterValues the parameter values to set
*/
public void setParameterValues(Map<String, Object> parameterValues) {
@@ -82,9 +76,7 @@ public class HibernatePagingItemReader<T> extends AbstractPagingItemReader<T>
/**
* A query name for an externalized query. Either this or the {
* {@link #setQueryString(String) query string} or the {
* {@link #setQueryProvider(HibernateQueryProvider) query provider} should
* be set.
*
* {@link #setQueryProvider(HibernateQueryProvider) query provider} should be set.
* @param queryName name of a hibernate named query
*/
public void setQueryName(String queryName) {
@@ -92,9 +84,8 @@ public class HibernatePagingItemReader<T> extends AbstractPagingItemReader<T>
}
/**
* Fetch size used internally by Hibernate to limit amount of data fetched
* from database per round trip.
*
* Fetch size used internally by Hibernate to limit amount of data fetched from
* database per round trip.
* @param fetchSize the fetch size to pass down to Hibernate
*/
public void setFetchSize(int fetchSize) {
@@ -102,10 +93,8 @@ public class HibernatePagingItemReader<T> extends AbstractPagingItemReader<T>
}
/**
* A query provider. Either this or the {{@link #setQueryString(String)
* query string} or the {{@link #setQueryName(String) query name} should be
* set.
*
* A query provider. Either this or the {{@link #setQueryString(String) query string}
* or the {{@link #setQueryName(String) query name} should be set.
* @param queryProvider Hibernate query provider
*/
public void setQueryProvider(HibernateQueryProvider<? extends T> queryProvider) {
@@ -116,7 +105,6 @@ public class HibernatePagingItemReader<T> extends AbstractPagingItemReader<T>
* A query string in HQL. Either this or the {
* {@link #setQueryProvider(HibernateQueryProvider) query provider} or the {
* {@link #setQueryName(String) query name} should be set.
*
* @param queryString HQL query string
*/
public void setQueryString(String queryString) {
@@ -125,7 +113,6 @@ public class HibernatePagingItemReader<T> extends AbstractPagingItemReader<T>
/**
* The Hibernate SessionFactory to use the create a session.
*
* @param sessionFactory the {@link SessionFactory} to set
*/
public void setSessionFactory(SessionFactory sessionFactory) {
@@ -134,10 +121,8 @@ public class HibernatePagingItemReader<T> extends AbstractPagingItemReader<T>
/**
* Can be set only in uninitialized state.
*
* @param useStatelessSession <code>true</code> to use
* {@link StatelessSession} <code>false</code> to use standard hibernate
* {@link Session}
* @param useStatelessSession <code>true</code> to use {@link StatelessSession}
* <code>false</code> to use standard hibernate {@link Session}
*/
public void setUseStatelessSession(boolean useStatelessSession) {
helper.setUseStatelessSession(useStatelessSession);

View File

@@ -23,18 +23,19 @@ import org.springframework.jdbc.core.RowMapper;
/**
* A convenient strategy for SQL updates, acting effectively as the inverse of
* {@link RowMapper}.
*
*
* @author Dave Syer
*
*
*/
public interface ItemPreparedStatementSetter<T> {
/**
* Set parameter values on the given PreparedStatement as determined from
* the provided item.
* Set parameter values on the given PreparedStatement as determined from the provided
* item.
* @param item the item to obtain the values from
* @param ps the PreparedStatement to invoke setter methods on
* @throws SQLException if a SQLException is encountered (i.e. there is no
* need to catch SQLException)
* @throws SQLException if a SQLException is encountered (i.e. there is no need to
* catch SQLException)
*/
void setValues(T item, PreparedStatement ps) throws SQLException;

View File

@@ -19,15 +19,15 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
/**
* A convenient strategy for providing SqlParameterSource for named parameter SQL updates.
*
*
* @author Thomas Risberg
* @since 2.0
*/
public interface ItemSqlParameterSourceProvider<T> {
/**
* Provide parameter values in an {@link SqlParameterSource} based on values from
* the provided item.
* Provide parameter values in an {@link SqlParameterSource} based on values from the
* provided item.
* @param item the item to use for parameter values
* @return parameters extracted from the item
*/

View File

@@ -37,22 +37,24 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.util.Assert;
/**
* <p>{@link ItemWriter} that uses the batching features from
* <p>
* {@link ItemWriter} that uses the batching features from
* {@link NamedParameterJdbcTemplate} to execute a batch of statements for all items
* provided.</p>
* provided.
* </p>
*
* The user must provide an SQL query and a special callback for either of
* {@link ItemPreparedStatementSetter} or {@link ItemSqlParameterSourceProvider}.
* You can use either named parameters or the traditional '?' placeholders. If you use the
* named parameter support then you should provide a {@link ItemSqlParameterSourceProvider},
* otherwise you should provide a {@link ItemPreparedStatementSetter}.
* This callback would be responsible for mapping the item to the parameters needed to
* execute the SQL statement.<br>
* {@link ItemPreparedStatementSetter} or {@link ItemSqlParameterSourceProvider}. You can
* use either named parameters or the traditional '?' placeholders. If you use the named
* parameter support then you should provide a {@link ItemSqlParameterSourceProvider},
* otherwise you should provide a {@link ItemPreparedStatementSetter}. This callback would
* 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>
*
* The writer is thread-safe after its properties are set (normal singleton
* behavior), so it can be used to write in multiple concurrent transactions.
* The writer is thread-safe after its properties are set (normal singleton behavior), so
* it can be used to write in multiple concurrent transactions.
*
* @author Dave Syer
* @author Thomas Risberg
@@ -78,8 +80,8 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
protected boolean usingNamedParameters;
/**
* Public setter for the flag that determines whether an assertion is made
* that all items cause at least one row to be updated.
* Public setter for the flag that determines whether an assertion is made that all
* items cause at least one row to be updated.
* @param assertUpdates the flag to set. Defaults to true;
*/
public void setAssertUpdates(boolean assertUpdates) {
@@ -87,9 +89,8 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
/**
* Public setter for the query string to execute on write. The parameters
* should correspond to those known to the
* {@link ItemPreparedStatementSetter}.
* Public setter for the query string to execute on write. The parameters should
* correspond to those known to the {@link ItemPreparedStatementSetter}.
* @param sql the query to set
*/
public void setSql(String sql) {
@@ -98,8 +99,8 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
/**
* Public setter for the {@link ItemPreparedStatementSetter}.
* @param preparedStatementSetter the {@link ItemPreparedStatementSetter} to
* set. This is required when using traditional '?' placeholders for the SQL statement.
* @param preparedStatementSetter the {@link ItemPreparedStatementSetter} to set. This
* is required when using traditional '?' placeholders for the SQL statement.
*/
public void setItemPreparedStatementSetter(ItemPreparedStatementSetter<T> preparedStatementSetter) {
this.itemPreparedStatementSetter = preparedStatementSetter;
@@ -108,8 +109,8 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
/**
* Public setter for the {@link ItemSqlParameterSourceProvider}.
* @param itemSqlParameterSourceProvider the {@link ItemSqlParameterSourceProvider} to
* set. This is required when using named parameters for the SQL statement and the type
* to be written does not implement {@link Map}.
* set. This is required when using named parameters for the SQL statement and the
* type to be written does not implement {@link Map}.
*/
public void setItemSqlParameterSourceProvider(ItemSqlParameterSourceProvider<T> itemSqlParameterSourceProvider) {
this.itemSqlParameterSourceProvider = itemSqlParameterSourceProvider;
@@ -117,7 +118,6 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
/**
* Public setter for the data source for injection purposes.
*
* @param dataSource {@link javax.sql.DataSource} to use for querying against
*/
public void setDataSource(DataSource dataSource) {
@@ -135,8 +135,8 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
/**
* Check mandatory properties - there must be a SimpleJdbcTemplate and an SQL statement plus a
* parameter source.
* Check mandatory properties - there must be a SimpleJdbcTemplate and an SQL
* statement plus a parameter source.
*/
@Override
public void afterPropertiesSet() {
@@ -146,16 +146,20 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
parameterCount = JdbcParameterUtils.countParameterPlaceholders(sql, namedParameters);
if (namedParameters.size() > 0) {
if (parameterCount != namedParameters.size()) {
throw new InvalidDataAccessApiUsageException("You can't use both named parameters and classic \"?\" placeholders: " + sql);
throw new InvalidDataAccessApiUsageException(
"You can't use both named parameters and classic \"?\" placeholders: " + sql);
}
usingNamedParameters = true;
}
if (!usingNamedParameters) {
Assert.notNull(itemPreparedStatementSetter, "Using SQL statement with '?' placeholders requires an ItemPreparedStatementSetter");
Assert.notNull(itemPreparedStatementSetter,
"Using SQL statement with '?' placeholders requires an ItemPreparedStatementSetter");
}
}
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
*/
@SuppressWarnings("unchecked")
@@ -171,9 +175,10 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
int[] updateCounts;
if (usingNamedParameters) {
if(items.get(0) instanceof Map && this.itemSqlParameterSourceProvider == null) {
if (items.get(0) instanceof Map && this.itemSqlParameterSourceProvider == null) {
updateCounts = namedParameterJdbcTemplate.batchUpdate(sql, items.toArray(new Map[items.size()]));
} else {
}
else {
SqlParameterSource[] batchArgs = new SqlParameterSource[items.size()];
int i = 0;
for (T item : items) {
@@ -183,16 +188,18 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
}
else {
updateCounts = namedParameterJdbcTemplate.getJdbcOperations().execute(sql, new PreparedStatementCallback<int[]>() {
@Override
public int[] doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
for (T item : items) {
itemPreparedStatementSetter.setValues(item, ps);
ps.addBatch();
}
return ps.executeBatch();
}
});
updateCounts = namedParameterJdbcTemplate.getJdbcOperations().execute(sql,
new PreparedStatementCallback<int[]>() {
@Override
public int[] doInPreparedStatement(PreparedStatement ps)
throws SQLException, DataAccessException {
for (T item : items) {
itemPreparedStatementSetter.setValues(item, ps);
ps.addBatch();
}
return ps.executeBatch();
}
});
}
if (assertUpdates) {
@@ -206,4 +213,5 @@ public class JdbcBatchItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
}
}
}

View File

@@ -30,15 +30,16 @@ import org.springframework.util.ClassUtils;
/**
* <p>
* Simple item reader implementation that opens a JDBC cursor and continually retrieves the
* next row in the ResultSet.
* Simple item reader implementation that opens a JDBC cursor and continually retrieves
* the next row in the ResultSet.
* </p>
*
* <p>
* The statement used to open the cursor is created with the 'READ_ONLY' option since a non read-only
* cursor may unnecessarily lock tables or rows. It is also opened with 'TYPE_FORWARD_ONLY' option.
* By default the cursor will be opened using a separate connection which means that it will not participate
* in any transactions created as part of the step processing.
* The statement used to open the cursor is created with the 'READ_ONLY' option since a
* non read-only cursor may unnecessarily lock tables or rows. It is also opened with
* 'TYPE_FORWARD_ONLY' option. By default the cursor will be opened using a separate
* connection which means that it will not participate in any transactions created as part
* of the step processing.
* </p>
*
* <p>
@@ -69,7 +70,6 @@ public class JdbcCursorItemReader<T> extends AbstractCursorItemReader<T> {
/**
* Set the RowMapper to be used for all calls to read().
*
* @param rowMapper the mapper used to map each item
*/
public void setRowMapper(RowMapper<T> rowMapper) {
@@ -77,10 +77,9 @@ public class JdbcCursorItemReader<T> extends AbstractCursorItemReader<T> {
}
/**
* Set the SQL statement to be used when creating the cursor. This statement
* should be a complete and valid SQL statement, as it will be run directly
* without any modification.
*
* Set the SQL statement to be used when creating the cursor. This statement should be
* a complete and valid SQL statement, as it will be run directly without any
* modification.
* @param sql SQL statement
*/
public void setSql(String sql) {
@@ -88,10 +87,10 @@ public class JdbcCursorItemReader<T> extends AbstractCursorItemReader<T> {
}
/**
* Set the PreparedStatementSetter to use if any parameter values that need
* to be set in the supplied query.
*
* @param preparedStatementSetter PreparedStatementSetter responsible for filling out the statement
* Set the PreparedStatementSetter to use if any parameter values that need to be set
* in the supplied query.
* @param preparedStatementSetter PreparedStatementSetter responsible for filling out
* the statement
*/
public void setPreparedStatementSetter(PreparedStatementSetter preparedStatementSetter) {
this.preparedStatementSetter = preparedStatementSetter;
@@ -99,9 +98,7 @@ public class JdbcCursorItemReader<T> extends AbstractCursorItemReader<T> {
/**
* Assert that mandatory properties are set.
*
* @throws IllegalArgumentException if either data source or SQL properties
* not set.
* @throws IllegalArgumentException if either data source or SQL properties not set.
*/
@Override
public void afterPropertiesSet() throws Exception {
@@ -110,7 +107,6 @@ public class JdbcCursorItemReader<T> extends AbstractCursorItemReader<T> {
Assert.notNull(rowMapper, "RowMapper must be provided");
}
@Override
protected void openCursor(Connection con) {
try {
@@ -135,7 +131,6 @@ public class JdbcCursorItemReader<T> extends AbstractCursorItemReader<T> {
}
@Nullable
@Override
protected T readCursor(ResultSet rs, int currentRow) throws SQLException {
@@ -156,4 +151,5 @@ public class JdbcCursorItemReader<T> extends AbstractCursorItemReader<T> {
public String getSql() {
return this.sql;
}
}

View File

@@ -40,35 +40,33 @@ import org.springframework.util.ClassUtils;
/**
* <p>
* {@link org.springframework.batch.item.ItemReader} for reading database
* records using JDBC in a paging fashion.
* {@link org.springframework.batch.item.ItemReader} for reading database records using
* JDBC in a paging fashion.
* </p>
*
*
* <p>
* It executes the SQL built by the {@link PagingQueryProvider} to retrieve
* requested data. The query is executed using paged requests of a size
* specified in {@link #setPageSize(int)}. Additional pages are requested when
* needed as {@link #read()} method is called, returning an object corresponding
* to current position. On restart it uses the last sort key value to locate the
* first page to read (so it doesn't matter if the successfully processed items
* have been removed or modified). It is important to have a unique key constraint
* on the sort key to guarantee that no data is lost between executions.
* It executes the SQL built by the {@link PagingQueryProvider} to retrieve requested
* data. The query is executed using paged requests of a size specified in
* {@link #setPageSize(int)}. Additional pages are requested when needed as
* {@link #read()} method is called, returning an object corresponding to current
* position. On restart it uses the last sort key value to locate the first page to read
* (so it doesn't matter if the successfully processed items have been removed or
* modified). It is important to have a unique key constraint on the sort key to guarantee
* that no data is lost between executions.
* </p>
*
*
* <p>
* The performance of the paging depends on the database specific features
* available to limit the number of returned rows. Setting a fairly large page
* size and using a commit interval that matches the page size should provide
* better performance.
* The performance of the paging depends on the database specific features available to
* limit the number of returned rows. Setting a fairly large page size and using a commit
* interval that matches the page size should provide better performance.
* </p>
*
*
* <p>
* The implementation is thread-safe in between calls to
* {@link #open(ExecutionContext)}, but remember to use
* <code>saveState=false</code> if used in a multi-threaded client (no restart
* available).
* The implementation is thread-safe in between calls to {@link #open(ExecutionContext)},
* but remember to use <code>saveState=false</code> if used in a multi-threaded client (no
* restart available).
* </p>
*
*
* @author Thomas Risberg
* @author Dave Syer
* @author Michael Minella
@@ -76,6 +74,7 @@ import org.springframework.util.ClassUtils;
* @since 2.0
*/
public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> implements InitializingBean {
private static final String START_AFTER_VALUE = "start.after";
public static final int VALUE_NOT_SET = -1;
@@ -95,7 +94,7 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
private String remainingPagesSql;
private Map<String, Object> startAfterValues;
private Map<String, Object> previousStartAfterValues;
private int fetchSize = VALUE_NOT_SET;
@@ -109,11 +108,9 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
}
/**
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for this
* <code>ResultSet</code> object. If the fetch size specified is zero, the
* JDBC driver ignores the value.
*
* Gives the JDBC driver a hint as to the number of rows that should be fetched from
* the database when more rows are needed for this <code>ResultSet</code> object. If
* the fetch size specified is zero, the JDBC driver ignores the value.
* @param fetchSize the number of rows to fetch
* @see ResultSet#setFetchSize(int)
*/
@@ -122,9 +119,8 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
}
/**
* A {@link PagingQueryProvider}. Supplies all the platform dependent query
* generation capabilities needed by the reader.
*
* A {@link PagingQueryProvider}. Supplies all the platform dependent query generation
* capabilities needed by the reader.
* @param queryProvider the {@link PagingQueryProvider} to use
*/
public void setQueryProvider(PagingQueryProvider queryProvider) {
@@ -132,13 +128,9 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
}
/**
* The row mapper implementation to be used by this reader. The row mapper
* is used to convert result set rows into objects, which are then returned
* by the reader.
*
* @param rowMapper a
* {@link RowMapper}
* implementation
* The row mapper implementation to be used by this reader. The row mapper is used to
* convert result set rows into objects, which are then returned by the reader.
* @param rowMapper a {@link RowMapper} implementation
*/
public void setRowMapper(RowMapper<T> rowMapper) {
this.rowMapper = rowMapper;
@@ -146,13 +138,11 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
/**
* The parameter values to be used for the query execution. If you use named
* parameters then the key should be the name used in the query clause. If
* you use "?" placeholders then the key should be the relative index that
* the parameter appears in the query string built using the select, from
* and where clauses specified.
*
* @param parameterValues the values keyed by the parameter named/index used
* in the query string.
* parameters then the key should be the name used in the query clause. If you use "?"
* placeholders then the key should be the relative index that the parameter appears
* in the query string built using the select, from and where clauses specified.
* @param parameterValues the values keyed by the parameter named/index used in the
* query string.
*/
public void setParameterValues(Map<String, Object> parameterValues) {
this.parameterValues = parameterValues;
@@ -197,8 +187,8 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
}
if (parameterValues != null && parameterValues.size() > 0) {
if (this.queryProvider.isUsingNamedParameters()) {
query = namedParameterJdbcTemplate.query(firstPageSql,
getParameterMap(parameterValues, null), rowCallback);
query = namedParameterJdbcTemplate.query(firstPageSql, getParameterMap(parameterValues, null),
rowCallback);
}
else {
query = getJdbcTemplate().query(firstPageSql, rowCallback,
@@ -237,14 +227,15 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
if (isSaveState()) {
if (isAtEndOfPage() && startAfterValues != null) {
// restart on next page
executionContext.put(getExecutionContextKey(START_AFTER_VALUE), startAfterValues);
} else if (previousStartAfterValues != null) {
executionContext.put(getExecutionContextKey(START_AFTER_VALUE), startAfterValues);
}
else if (previousStartAfterValues != null) {
// restart on current page
executionContext.put(getExecutionContextKey(START_AFTER_VALUE), previousStartAfterValues);
}
}
}
private boolean isAtEndOfPage() {
return getCurrentItemCount() % getPageSize() == 0;
}
@@ -255,7 +246,7 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
if (isSaveState()) {
startAfterValues = (Map<String, Object>) executionContext.get(getExecutionContextKey(START_AFTER_VALUE));
if(startAfterValues == null) {
if (startAfterValues == null) {
startAfterValues = new LinkedHashMap<>();
}
}
@@ -266,10 +257,11 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
@Override
protected void doJumpToPage(int itemIndex) {
/*
* Normally this would be false (the startAfterValue is enough
* information to restart from.
* Normally this would be false (the startAfterValue is enough information to
* restart from.
*/
// TODO: this is dead code, startAfterValues is never null - see #open(ExecutionContext)
// TODO: this is dead code, startAfterValues is never null - see
// #open(ExecutionContext)
if (startAfterValues == null && getPage() > 0) {
String jumpToItemSql = queryProvider.generateJumpToItemQuery(itemIndex, getPageSize());
@@ -277,12 +269,14 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
if (logger.isDebugEnabled()) {
logger.debug("SQL used for jumping: [" + jumpToItemSql + "]");
}
if (this.queryProvider.isUsingNamedParameters()) {
startAfterValues = namedParameterJdbcTemplate.queryForMap(jumpToItemSql, getParameterMap(parameterValues, null));
startAfterValues = namedParameterJdbcTemplate.queryForMap(jumpToItemSql,
getParameterMap(parameterValues, null));
}
else {
startAfterValues = getJdbcTemplate().queryForMap(jumpToItemSql, getParameterList(parameterValues, null).toArray());
startAfterValues = getJdbcTemplate().queryForMap(jumpToItemSql,
getParameterList(parameterValues, null).toArray());
}
}
}
@@ -313,8 +307,8 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
if (sortKeyValue != null && sortKeyValue.size() > 0) {
List<Map.Entry<String, Object>> keys = new ArrayList<>(sortKeyValue.entrySet());
for(int i = 0; i < keys.size(); i++) {
for(int j = 0; j < i; j++) {
for (int i = 0; i < keys.size(); i++) {
for (int j = 0; j < i; j++) {
parameterList.add(keys.get(j).getValue());
}
@@ -329,6 +323,7 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
}
private class PagingRowMapper implements RowMapper<T> {
@Override
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
startAfterValues = new LinkedHashMap<>();
@@ -338,9 +333,11 @@ public class JdbcPagingItemReader<T> extends AbstractPagingItemReader<T> impleme
return rowMapper.mapRow(rs, rowNum);
}
}
private JdbcTemplate getJdbcTemplate() {
return (JdbcTemplate) namedParameterJdbcTemplate.getJdbcOperations();
}
}

View File

@@ -34,22 +34,21 @@ public class JdbcParameterUtils {
/**
* Count the occurrences of the character placeholder in an SQL string
* <code>sql</code>. The character placeholder is not counted if it appears
* within a literal, that is, surrounded by single or double quotes. This method will
* count traditional placeholders in the form of a question mark ('?') as well as
* named parameters indicated with a leading ':' or '&amp;'.
* <code>sql</code>. The character placeholder is not counted if it appears within a
* literal, that is, surrounded by single or double quotes. This method will count
* traditional placeholders in the form of a question mark ('?') as well as named
* parameters indicated with a leading ':' or '&amp;'.
*
* The code for this method is taken from an early version of the
* {@link org.springframework.jdbc.core.namedparam.NamedParameterUtils}
* class. That method was later removed after some refactoring, but the code
* is useful here for the Spring Batch project. The code has been altered to better
* suite the batch processing requirements.
*
* {@link org.springframework.jdbc.core.namedparam.NamedParameterUtils} class. That
* method was later removed after some refactoring, but the code is useful here for
* the Spring Batch project. The code has been altered to better suite the batch
* processing requirements.
* @param sql String to search in. Returns 0 if the given String is <code>null</code>.
* @param namedParameterHolder holder for the named parameters
* @return the number of named parameter placeholders
*/
public static int countParameterPlaceholders(String sql, List<String> namedParameterHolder ) {
public static int countParameterPlaceholders(String sql, List<String> namedParameterHolder) {
if (sql == null) {
return 0;
}
@@ -103,16 +102,15 @@ public class JdbcParameterUtils {
}
/**
* Determine whether a parameter name continues at the current position,
* that is, does not end delimited by any whitespace character yet.
* Determine whether a parameter name continues at the current position, that is, does
* not end delimited by any whitespace character yet.
* @param statement the SQL statement
* @param pos the position within the statement
*/
private static boolean parameterNameContinues(String statement, int pos) {
char character = statement.charAt(pos);
return (character != ' ' && character != ',' && character != ')' &&
character != '"' && character != '\'' && character != '|' &&
character != ';' && character != '\n' && character != '\r');
return (character != ' ' && character != ',' && character != ')' && character != '"' && character != '\''
&& character != '|' && character != ';' && character != '\n' && character != '\r');
}
}

View File

@@ -32,27 +32,31 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* {@link org.springframework.batch.item.ItemStreamReader} implementation based
* on JPA {@link Query#getResultStream()}. It executes the JPQL query when
* initialized and iterates over the result set as {@link #read()} method is called,
* returning an object corresponding to the current row. The query can be set
* directly using {@link #setQueryString(String)}, or using a query provider via
* {@link #setQueryProvider(JpaQueryProvider)}.
*
* {@link org.springframework.batch.item.ItemStreamReader} implementation based on JPA
* {@link Query#getResultStream()}. It executes the JPQL query when initialized and
* iterates over the result set as {@link #read()} method is called, returning an object
* corresponding to the current row. The query can be set directly using
* {@link #setQueryString(String)}, or using a query provider via
* {@link #setQueryProvider(JpaQueryProvider)}.
*
* The implementation is <b>not</b> thread-safe.
*
*
* @author Mahmoud Ben Hassine
* @param <T> type of items to read
* @since 4.3
*/
public class JpaCursorItemReader<T> extends AbstractItemCountingItemStreamItemReader<T>
implements InitializingBean {
public class JpaCursorItemReader<T> extends AbstractItemCountingItemStreamItemReader<T> implements InitializingBean {
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
private String queryString;
private JpaQueryProvider queryProvider;
private Map<String, Object> parameterValues;
private Iterator<T> iterator;
/**
@@ -64,7 +68,6 @@ public class JpaCursorItemReader<T> extends AbstractItemCountingItemStreamItemRe
/**
* Set the JPA entity manager factory.
*
* @param entityManagerFactory JPA entity manager factory
*/
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
@@ -73,7 +76,6 @@ public class JpaCursorItemReader<T> extends AbstractItemCountingItemStreamItemRe
/**
* Set the JPA query provider.
*
* @param queryProvider JPA query provider
*/
public void setQueryProvider(JpaQueryProvider queryProvider) {
@@ -82,7 +84,6 @@ public class JpaCursorItemReader<T> extends AbstractItemCountingItemStreamItemRe
/**
* Set the JPQL query string.
*
* @param queryString JPQL query string
*/
public void setQueryString(String queryString) {
@@ -91,9 +92,8 @@ public class JpaCursorItemReader<T> extends AbstractItemCountingItemStreamItemRe
/**
* Set the parameter values to be used for the query execution.
*
* @param parameterValues the values keyed by parameter names used in
* the query string.
* @param parameterValues the values keyed by parameter names used in the query
* string.
*/
public void setParameterValues(Map<String, Object> parameterValues) {
this.parameterValues = parameterValues;
@@ -150,4 +150,5 @@ public class JpaCursorItemReader<T> extends AbstractItemCountingItemStreamItemRe
this.entityManager.close();
}
}
}

View File

@@ -30,17 +30,15 @@ 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.
* 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>
*
* The reader must be configured with an
* {@link jakarta.persistence.EntityManagerFactory} that is capable of
* participating in Spring managed transactions.
* The reader must be configured with an {@link jakarta.persistence.EntityManagerFactory}
* that is capable of participating in Spring managed transactions.
*
* The writer is thread-safe after its properties are set (normal singleton
* behaviour), so it can be used to write in multiple concurrent transactions.
* The writer is thread-safe after its properties are set (normal singleton behaviour), so
* it can be used to write in multiple concurrent transactions.
*
* @author Thomas Risberg
* @author Mahmoud Ben Hassine
@@ -51,20 +49,19 @@ public class JpaItemWriter<T> implements ItemWriter<T>, InitializingBean {
protected static final Log logger = LogFactory.getLog(JpaItemWriter.class);
private EntityManagerFactory entityManagerFactory;
private boolean usePersist = false;
/**
* Set the EntityManager to be used internally.
*
* @param entityManagerFactory the entityManagerFactory to set
*/
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
/**
* Set whether the EntityManager should perform a persist instead of a merge.
*
* @param usePersist whether to use persist instead of merge.
*/
public void setUsePersist(boolean usePersist) {
@@ -80,8 +77,8 @@ 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.
* 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)
*/
@@ -96,9 +93,8 @@ public class JpaItemWriter<T> implements ItemWriter<T>, InitializingBean {
}
/**
* Do perform the actual write operation. This can be overridden in a
* subclass if necessary.
*
* Do perform the actual write operation. This can be overridden in a subclass if
* necessary.
* @param entityManager the EntityManager to use for the operation
* @param items the list of items to use for the write
*/
@@ -112,12 +108,12 @@ public class JpaItemWriter<T> implements ItemWriter<T>, InitializingBean {
long addedToContextCount = 0;
for (T item : items) {
if (!entityManager.contains(item)) {
if(usePersist) {
if (usePersist) {
entityManager.persist(item);
}
else {
entityManager.merge(item);
}
}
addedToContextCount++;
}
}

View File

@@ -34,50 +34,47 @@ import org.springframework.util.ClassUtils;
/**
* <p>
* {@link org.springframework.batch.item.ItemReader} for reading database
* records built on top of JPA.
* {@link org.springframework.batch.item.ItemReader} for reading database records built on
* top of JPA.
* </p>
*
* <p>
* It executes the JPQL {@link #setQueryString(String)} to retrieve requested
* data. The query is executed using paged requests of a size specified in
* It executes the JPQL {@link #setQueryString(String)} to retrieve requested data. The
* query is executed using paged requests of a size specified in
* {@link #setPageSize(int)}. Additional pages are requested when needed as
* {@link #read()} method is called, returning an object corresponding to
* current position.
* {@link #read()} method is called, returning an object corresponding to current
* position.
* </p>
*
* <p>
* The performance of the paging depends on the JPA implementation and its use
* of database specific features to limit the number of returned rows.
* The performance of the paging depends on the JPA implementation and its use of database
* specific features to limit the number of returned rows.
* </p>
*
* <p>
* Setting a fairly large page size and using a commit interval that matches the
* page size should provide better performance.
* Setting a fairly large page size and using a commit interval that matches the page size
* should provide better performance.
* </p>
*
* <p>
* In order to reduce the memory usage for large results the persistence context
* is flushed and cleared after each page is read. This causes any entities read
* to be detached. If you make changes to the entities and want the changes
* persisted then you must explicitly merge the entities.
* In order to reduce the memory usage for large results the persistence context is
* flushed and cleared after each page is read. This causes any entities read to be
* detached. If you make changes to the entities and want the changes persisted then you
* must explicitly merge the entities.
* </p>
*
* <p>
* The reader must be configured with an
* {@link jakarta.persistence.EntityManagerFactory}. All entity access is
* performed within a new transaction, independent of any existing Spring
* managed transactions.
* The reader must be configured with an {@link jakarta.persistence.EntityManagerFactory}.
* All entity access is performed within a new transaction, independent of any existing
* Spring managed transactions.
* </p>
*
* <p>
* The implementation is thread-safe in between calls to
* {@link #open(ExecutionContext)}, but remember to use
* <code>saveState=false</code> if used in a multi-threaded client (no restart
* available).
* The implementation is thread-safe in between calls to {@link #open(ExecutionContext)},
* but remember to use <code>saveState=false</code> if used in a multi-threaded client (no
* restart available).
* </p>
*
*
* @author Thomas Risberg
* @author Dave Syer
* @author Will Schipp
@@ -97,8 +94,8 @@ public class JpaPagingItemReader<T> extends AbstractPagingItemReader<T> {
private JpaQueryProvider queryProvider;
private Map<String, Object> parameterValues;
private boolean transacted = true;//default value
private boolean transacted = true;// default value
public JpaPagingItemReader() {
setName(ClassUtils.getShortName(JpaPagingItemReader.class));
@@ -123,25 +120,24 @@ public class JpaPagingItemReader<T> extends AbstractPagingItemReader<T> {
/**
* The parameter values to be used for the query execution.
*
* @param parameterValues the values keyed by the parameter named used in
* the query string.
* @param parameterValues the values keyed by the parameter named used in the query
* string.
*/
public void setParameterValues(Map<String, Object> parameterValues) {
this.parameterValues = parameterValues;
}
/**
* By default (true) the EntityTransaction will be started and committed around the read.
* Can be overridden (false) in cases where the JPA implementation doesn't support a
* particular transaction. (e.g. Hibernate with a JTA transaction). NOTE: may cause
* problems in guaranteeing the object consistency in the EntityManagerFactory.
*
* By default (true) the EntityTransaction will be started and committed around the
* read. Can be overridden (false) in cases where the JPA implementation doesn't
* support a particular transaction. (e.g. Hibernate with a JTA transaction). NOTE:
* may cause problems in guaranteeing the object consistency in the
* EntityManagerFactory.
* @param transacted indicator
*/
public void setTransacted(boolean transacted) {
this.transacted = transacted;
}
}
@Override
public void afterPropertiesSet() throws Exception {
@@ -188,14 +184,14 @@ public class JpaPagingItemReader<T> extends AbstractPagingItemReader<T> {
protected void doReadPage() {
EntityTransaction tx = null;
if (transacted) {
tx = entityManager.getTransaction();
tx.begin();
entityManager.flush();
entityManager.clear();
}//end if
} // end if
Query query = createQuery().setFirstResult(getPage() * getPageSize()).setMaxResults(getPageSize());
@@ -211,17 +207,18 @@ public class JpaPagingItemReader<T> extends AbstractPagingItemReader<T> {
else {
results.clear();
}
if (!transacted) {
List<T> queryResult = query.getResultList();
for (T entity : queryResult) {
entityManager.detach(entity);
results.add(entity);
}//end if
} else {
} // end if
}
else {
results.addAll(query.getResultList());
tx.commit();
}//end if
} // end if
}
@Override

View File

@@ -17,9 +17,11 @@ package org.springframework.batch.item.database;
/**
* The direction of the sort in an ORDER BY clause.
*
*
* @author Michael Minella
*/
public enum Order {
ASCENDING, DESCENDING
}

View File

@@ -19,10 +19,9 @@ package org.springframework.batch.item.database;
import java.util.Map;
import javax.sql.DataSource;
/**
* Interface defining the functionality to be provided for generating paging queries for use with Paging
* Item Readers.
* Interface defining the functionality to be provided for generating paging queries for
* use with Paging Item Readers.
*
* @author Thomas Risberg
* @author Michael Minella
@@ -32,7 +31,6 @@ public interface PagingQueryProvider {
/**
* Initialize the query provider using the provided {@link DataSource} if necessary.
*
* @param dataSource DataSource to use for any initialization
* @throws Exception for errors when initializing
*/
@@ -40,7 +38,6 @@ public interface PagingQueryProvider {
/**
* Generate the query that will provide the first page, limited by the page size.
*
* @param pageSize number of rows to read for each page
* @return the generated query
*/
@@ -48,7 +45,6 @@ public interface PagingQueryProvider {
/**
* Generate the query that will provide the first page, limited by the page size.
*
* @param pageSize number of rows to read for each page
* @return the generated query
*/
@@ -56,10 +52,10 @@ public interface PagingQueryProvider {
/**
*
* Generate the query that will provide the jump to item query. The itemIndex provided could be in the middle of
* the page and together with the page size it will be used to calculate the last index of the preceding page
* to be able to retrieve the sort key for this row.
*
* Generate the query that will provide the jump to item query. The itemIndex provided
* could be in the middle of the page and together with the page size it will be used
* to calculate the last index of the preceding page to be able to retrieve the sort
* key for this row.
* @param itemIndex the index for the next item to be read
* @param pageSize number of rows to read for each page
* @return the generated query
@@ -74,23 +70,20 @@ public interface PagingQueryProvider {
/**
* Indicate whether the generated queries use named parameter syntax.
*
* @return true if named parameter syntax is used
*/
boolean isUsingNamedParameters();
/**
* The sort keys. A Map of the columns that make up the key and a Boolean indicating ascending or descending
* (ascending = true).
*
* The sort keys. A Map of the columns that make up the key and a Boolean indicating
* ascending or descending (ascending = true).
* @return the sort keys used to order the query
*/
Map<String, Order> getSortKeys();
/**
* Returns either a String to be used as the named placeholder for a sort key value (based on the column name)
* or a ? for unnamed parameters.
*
* Returns either a String to be used as the named placeholder for a sort key value
* (based on the column name) or a ? for unnamed parameters.
* @param keyName The sort key name
* @return The string to be used for a parameterized query.
*/
@@ -98,8 +91,8 @@ public interface PagingQueryProvider {
/**
* The sort key (unique single column name) without alias.
*
* @return the sort key used to order the query (without alias)
*/
Map<String, Order> getSortKeysWithoutAliases();
}

View File

@@ -35,14 +35,15 @@ import org.springframework.util.ClassUtils;
/**
* <p>
* Item reader implementation that executes a stored procedure and then reads the returned cursor
* and continually retrieves the next row in the <code>ResultSet</code>.
* Item reader implementation that executes a stored procedure and then reads the returned
* cursor and continually retrieves the next row in the <code>ResultSet</code>.
* </p>
*
* <p>
* The callable statement used to open the cursor is created with the 'READ_ONLY' option as well as with the
* 'TYPE_FORWARD_ONLY' option. By default the cursor will be opened using a separate connection which means
* that it will not participate in any transactions created as part of the step processing.
* The callable statement used to open the cursor is created with the 'READ_ONLY' option
* as well as with the 'TYPE_FORWARD_ONLY' option. By default the cursor will be opened
* using a separate connection which means that it will not participate in any
* transactions created as part of the step processing.
* </p>
*
* <p>
@@ -82,7 +83,6 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
/**
* Set the RowMapper to be used for all calls to read().
*
* @param rowMapper the RowMapper to use to map the results
*/
public void setRowMapper(RowMapper<T> rowMapper) {
@@ -90,10 +90,9 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
}
/**
* Set the SQL statement to be used when creating the cursor. This statement
* should be a complete and valid SQL statement, as it will be run directly
* without any modification.
*
* Set the SQL statement to be used when creating the cursor. This statement should be
* a complete and valid SQL statement, as it will be run directly without any
* modification.
* @param sprocedureName the SQL used to call the statement
*/
public void setProcedureName(String sprocedureName) {
@@ -101,9 +100,8 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
}
/**
* Set the PreparedStatementSetter to use if any parameter values that need
* to be set in the supplied query.
*
* Set the PreparedStatementSetter to use if any parameter values that need to be set
* in the supplied query.
* @param preparedStatementSetter used to populate the SQL
*/
public void setPreparedStatementSetter(PreparedStatementSetter preparedStatementSetter) {
@@ -111,9 +109,9 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
}
/**
* Add one or more declared parameters. Used for configuring this operation when used in a
* bean factory. Each parameter will specify SQL type and (optionally) the parameter's name.
*
* Add one or more declared parameters. Used for configuring this operation when used
* in a bean factory. Each parameter will specify SQL type and (optionally) the
* parameter's name.
* @param parameters Array containing the declared <code>SqlParameter</code> objects
*/
public void setParameters(SqlParameter[] parameters) {
@@ -122,7 +120,6 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
/**
* Set whether this stored procedure is a function.
*
* @param function indicator
*/
public void setFunction(boolean function) {
@@ -130,10 +127,9 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
}
/**
* Set the parameter position of the REF CURSOR. Only used for Oracle and
* PostgreSQL that use REF CURSORs. For any other database this should be
* kept as 0 which is the default.
*
* Set the parameter position of the REF CURSOR. Only used for Oracle and PostgreSQL
* that use REF CURSORs. For any other database this should be kept as 0 which is the
* default.
* @param refCursorPosition The parameter position of the REF CURSOR
*/
public void setRefCursorPosition(int refCursorPosition) {
@@ -142,9 +138,7 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
/**
* Assert that mandatory properties are set.
*
* @throws IllegalArgumentException if either data source or SQL properties
* not set.
* @throws IllegalArgumentException if either data source or SQL properties not set.
*/
@Override
public void afterPropertiesSet() throws Exception {
@@ -157,12 +151,10 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
protected void openCursor(Connection con) {
Assert.state(procedureName != null, "Procedure Name must not be null.");
Assert.state(refCursorPosition >= 0,
"invalid refCursorPosition specified as " + refCursorPosition + "; it can't be " +
"specified as a negative number.");
Assert.state(refCursorPosition == 0 || refCursorPosition > 0,
"invalid refCursorPosition specified as " + refCursorPosition + "; there are " +
parameters.length + " parameters defined.");
Assert.state(refCursorPosition >= 0, "invalid refCursorPosition specified as " + refCursorPosition
+ "; it can't be " + "specified as a negative number.");
Assert.state(refCursorPosition == 0 || refCursorPosition > 0, "invalid refCursorPosition specified as "
+ refCursorPosition + "; there are " + parameters.length + " parameters defined.");
CallMetaDataContext callContext = new CallMetaDataContext();
callContext.setAccessCallParameterMetaData(false);
@@ -173,7 +165,6 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
SqlParameter cursorParameter = callContext.createReturnResultSetParameter("cursor", rowMapper);
this.callString = callContext.createCallString();
if (log.isDebugEnabled()) {
log.debug("Call string is: " + callString);
}
@@ -196,7 +187,8 @@ public class StoredProcedureItemReader<T> extends AbstractCursorItemReader<T> {
ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
else {
callableStatement = con.prepareCall(callString, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
callableStatement = con.prepareCall(callString, ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
}
applyStatementSettings(callableStatement);
if (this.preparedStatementSetter != null) {

View File

@@ -26,13 +26,13 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* This is a builder for the {@link HibernateCursorItemReader}. When configuring, one of
* This is a builder for the {@link HibernateCursorItemReader}. When configuring, one of
* the following should be provided (listed in order of precedence):
* <ul>
* <li>{@link #queryProvider(HibernateQueryProvider)}</li>
* <li>{@link #queryName(String)}</li>
* <li>{@link #queryString(String)}</li>
* <li>{@link #nativeQuery(String)} and {@link #entityClass(Class)}</li>
* <li>{@link #queryProvider(HibernateQueryProvider)}</li>
* <li>{@link #queryName(String)}</li>
* <li>{@link #queryString(String)}</li>
* <li>{@link #nativeQuery(String)} and {@link #entityClass(Class)}</li>
* </ul>
*
* @author Michael Minella
@@ -70,10 +70,9 @@ public class HibernateCursorItemReaderBuilder<T> {
private int currentItemCount;
/**
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
* for restart purposes.
*
* Configure if the state of the
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -87,7 +86,6 @@ public class HibernateCursorItemReaderBuilder<T> {
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -100,7 +98,6 @@ public class HibernateCursorItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -113,7 +110,6 @@ public class HibernateCursorItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -125,9 +121,8 @@ public class HibernateCursorItemReaderBuilder<T> {
}
/**
* A map of parameter values to be set on the query. The key of the map is the name
* of the parameter to be set with the value being the value to be set.
*
* A map of parameter values to be set on the query. The key of the map is the name of
* the parameter to be set with the value being the value to be set.
* @param parameterValues map of values
* @return this instance for method chaining
* @see HibernateCursorItemReader#setParameterValues(Map)
@@ -140,7 +135,6 @@ public class HibernateCursorItemReaderBuilder<T> {
/**
* The name of the Hibernate named query to be executed for this reader.
*
* @param queryName name of the query to execute
* @return this instance for method chaining
* @see HibernateCursorItemReader#setQueryName(String)
@@ -152,9 +146,8 @@ public class HibernateCursorItemReaderBuilder<T> {
}
/**
* The number of items to be returned with each round trip to the database. Used
* The number of items to be returned with each round trip to the database. Used
* internally by Hibernate.
*
* @param fetchSize number of records to return per fetch
* @return this instance for method chaining
* @see HibernateCursorItemReader#setFetchSize(int)
@@ -166,9 +159,8 @@ public class HibernateCursorItemReaderBuilder<T> {
}
/**
* A query provider. This should be set only if {@link #queryString(String)} and
* A query provider. This should be set only if {@link #queryString(String)} and
* {@link #queryName(String)} have not been set.
*
* @param queryProvider the query provider
* @return this instance for method chaining
* @see HibernateCursorItemReader#setQueryProvider(HibernateQueryProvider)
@@ -180,10 +172,9 @@ public class HibernateCursorItemReaderBuilder<T> {
}
/**
* The HQL query string to execute. This should only be set if
* The HQL query string to execute. This should only be set if
* {@link #queryProvider(HibernateQueryProvider)} and {@link #queryName(String)} have
* not been set.
*
* @param queryString the HQL query
* @return this instance for method chaining
* @see HibernateCursorItemReader#setQueryString(String)
@@ -196,7 +187,6 @@ public class HibernateCursorItemReaderBuilder<T> {
/**
* The Hibernate {@link SessionFactory} to execute the query against.
*
* @param sessionFactory the session factory
* @return this instance for method chaining
* @see HibernateCursorItemReader#setSessionFactory(SessionFactory)
@@ -210,7 +200,6 @@ public class HibernateCursorItemReaderBuilder<T> {
/**
* Indicator for whether to use a {@link org.hibernate.StatelessSession}
* (<code>true</code>) or a {@link org.hibernate.Session} (<code>false</code>).
*
* @param useStatelessSession Defaults to false
* @return this instance for method chaining
* @see HibernateCursorItemReader#setUseStatelessSession(boolean)
@@ -222,8 +211,7 @@ public class HibernateCursorItemReaderBuilder<T> {
}
/**
* Used to configure a {@link HibernateNativeQueryProvider}. This is ignored if
*
* Used to configure a {@link HibernateNativeQueryProvider}. This is ignored if
* @param nativeQuery {@link String} containing the native query.
* @return this instance for method chaining
*/
@@ -241,16 +229,14 @@ public class HibernateCursorItemReaderBuilder<T> {
/**
* Returns a fully constructed {@link HibernateCursorItemReader}.
*
* @return a new {@link HibernateCursorItemReader}
*/
public HibernateCursorItemReader<T> build() {
Assert.state(this.fetchSize >= 0, "fetchSize must not be negative");
Assert.state(this.sessionFactory != null, "A SessionFactory must be provided");
if(this.saveState) {
Assert.state(StringUtils.hasText(this.name),
"A name is required when saveState is set to true.");
if (this.saveState) {
Assert.state(StringUtils.hasText(this.name), "A name is required when saveState is set to true.");
}
HibernateCursorItemReader<T> reader = new HibernateCursorItemReader<>();
@@ -258,16 +244,16 @@ public class HibernateCursorItemReaderBuilder<T> {
reader.setFetchSize(this.fetchSize);
reader.setParameterValues(this.parameterValues);
if(this.queryProvider != null) {
if (this.queryProvider != null) {
reader.setQueryProvider(this.queryProvider);
}
else if(StringUtils.hasText(this.queryName)) {
else if (StringUtils.hasText(this.queryName)) {
reader.setQueryName(this.queryName);
}
else if(StringUtils.hasText(this.queryString)) {
else if (StringUtils.hasText(this.queryString)) {
reader.setQueryString(this.queryString);
}
else if(StringUtils.hasText(this.nativeQuery) && this.nativeClass != null) {
else if (StringUtils.hasText(this.nativeQuery) && this.nativeClass != null) {
HibernateNativeQueryProvider<T> provider = new HibernateNativeQueryProvider<>();
provider.setSqlQuery(this.nativeQuery);
provider.setEntityClass(this.nativeClass);
@@ -282,8 +268,8 @@ public class HibernateCursorItemReaderBuilder<T> {
reader.setQueryProvider(provider);
}
else {
throw new IllegalStateException("A HibernateQueryProvider, queryName, queryString, " +
"or both the nativeQuery and entityClass must be configured");
throw new IllegalStateException("A HibernateQueryProvider, queryName, queryString, "
+ "or both the nativeQuery and entityClass must be configured");
}
reader.setSessionFactory(this.sessionFactory);
@@ -296,4 +282,4 @@ public class HibernateCursorItemReaderBuilder<T> {
return reader;
}
}
}

View File

@@ -36,7 +36,6 @@ public class HibernateItemWriterBuilder<T> {
/**
* If set to false, the {@link org.hibernate.Session} will not be cleared at the end
* of the chunk.
*
* @param clearSession defaults to true
* @return this instance for method chaining
* @see HibernateItemWriter#setClearSession(boolean)
@@ -48,8 +47,7 @@ public class HibernateItemWriterBuilder<T> {
}
/**
* The Hibernate {@link SessionFactory} to obtain a session from. Required.
*
* The Hibernate {@link SessionFactory} to obtain a session from. Required.
* @param sessionFactory the {@link SessionFactory}
* @return this instance for method chaining
* @see HibernateItemWriter#setSessionFactory(SessionFactory)
@@ -62,12 +60,10 @@ public class HibernateItemWriterBuilder<T> {
/**
* Returns a fully built {@link HibernateItemWriter}
*
* @return the writer
*/
public HibernateItemWriter<T> build() {
Assert.state(this.sessionFactory != null,
"SessionFactory must be provided");
Assert.state(this.sessionFactory != null, "SessionFactory must be provided");
HibernateItemWriter<T> writer = new HibernateItemWriter<>();
writer.setSessionFactory(this.sessionFactory);
@@ -75,4 +71,5 @@ public class HibernateItemWriterBuilder<T> {
return writer;
}
}

View File

@@ -25,12 +25,12 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* A builder for the {@link HibernatePagingItemReader}. When configuring, only one of the
* A builder for the {@link HibernatePagingItemReader}. When configuring, only one of the
* following should be provided:
* <ul>
* <li>{@link #queryString(String)}</li>
* <li>{@link #queryName(String)}</li>
* <li>{@link #queryProvider(HibernateQueryProvider)}</li>
* <li>{@link #queryString(String)}</li>
* <li>{@link #queryName(String)}</li>
* <li>{@link #queryProvider(HibernateQueryProvider)}</li>
* </ul>
*
* @author Michael Minella
@@ -66,10 +66,9 @@ public class HibernatePagingItemReaderBuilder<T> {
private int currentItemCount;
/**
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
* for restart purposes.
*
* Configure if the state of the
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -83,7 +82,6 @@ public class HibernatePagingItemReaderBuilder<T> {
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -96,7 +94,6 @@ public class HibernatePagingItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -109,7 +106,6 @@ public class HibernatePagingItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -121,9 +117,8 @@ public class HibernatePagingItemReaderBuilder<T> {
}
/**
* The number of records to request per page/query. Defaults to 10. Must be greater
* The number of records to request per page/query. Defaults to 10. Must be greater
* than zero.
*
* @param pageSize number of items
* @return this instance for method chaining
* @see HibernatePagingItemReader#setPageSize(int)
@@ -135,9 +130,8 @@ public class HibernatePagingItemReaderBuilder<T> {
}
/**
* A map of parameter values to be set on the query. The key of the map is the name
* of the parameter to be set with the value being the value to be set.
*
* A map of parameter values to be set on the query. The key of the map is the name of
* the parameter to be set with the value being the value to be set.
* @param parameterValues map of values
* @return this instance for method chaining
* @see HibernatePagingItemReader#setParameterValues(Map)
@@ -150,7 +144,6 @@ public class HibernatePagingItemReaderBuilder<T> {
/**
* The name of the Hibernate named query to be executed for this reader.
*
* @param queryName name of the query to execute
* @return this instance for method chaining
* @see HibernatePagingItemReader#setQueryName(String)
@@ -162,9 +155,8 @@ public class HibernatePagingItemReaderBuilder<T> {
}
/**
* Fetch size used internally by Hibernate to limit amount of data fetched
* from database per round trip.
*
* Fetch size used internally by Hibernate to limit amount of data fetched from
* database per round trip.
* @param fetchSize number of records
* @return this instance for method chaining
* @see HibernatePagingItemReader#setFetchSize(int)
@@ -176,9 +168,8 @@ public class HibernatePagingItemReaderBuilder<T> {
}
/**
* A query provider. This should be set only if {@link #queryString(String)} and
* A query provider. This should be set only if {@link #queryString(String)} and
* {@link #queryName(String)} have not been set.
*
* @param queryProvider the query provider
* @return this instance for method chaining
* @see HibernatePagingItemReader#setQueryProvider(HibernateQueryProvider)
@@ -190,10 +181,9 @@ public class HibernatePagingItemReaderBuilder<T> {
}
/**
* The HQL query string to execute. This should only be set if
* The HQL query string to execute. This should only be set if
* {@link #queryProvider(HibernateQueryProvider)} and {@link #queryName(String)} have
* not been set.
*
* @param queryString the HQL query
* @return this instance for method chaining
* @see HibernatePagingItemReader#setQueryString(String)
@@ -206,7 +196,6 @@ public class HibernatePagingItemReaderBuilder<T> {
/**
* The Hibernate {@link SessionFactory} to execute the query against.
*
* @param sessionFactory the session factory
* @return this instance for method chaining
* @see HibernatePagingItemReader#setSessionFactory(SessionFactory)
@@ -220,7 +209,6 @@ public class HibernatePagingItemReaderBuilder<T> {
/**
* Indicator for whether to use a {@link org.hibernate.StatelessSession}
* (<code>true</code>) or a {@link org.hibernate.Session} (<code>false</code>).
*
* @param useStatelessSession Defaults to false
* @return this instance for method chaining
* @see HibernatePagingItemReader#setUseStatelessSession(boolean)
@@ -233,19 +221,17 @@ public class HibernatePagingItemReaderBuilder<T> {
/**
* Returns a fully constructed {@link HibernatePagingItemReader}.
*
* @return a new {@link HibernatePagingItemReader}
*/
public HibernatePagingItemReader<T> build() {
Assert.notNull(this.sessionFactory, "A SessionFactory must be provided");
Assert.state(this.fetchSize >= 0, "fetchSize must not be negative");
if(this.saveState) {
Assert.hasText(this.name,
"A name is required when saveState is set to true");
if (this.saveState) {
Assert.hasText(this.name, "A name is required when saveState is set to true");
}
if(this.queryProvider == null) {
if (this.queryProvider == null) {
Assert.state(StringUtils.hasText(queryString) ^ StringUtils.hasText(queryName),
"queryString or queryName must be set");
}
@@ -267,4 +253,5 @@ public class HibernatePagingItemReaderBuilder<T> {
return reader;
}
}

View File

@@ -53,7 +53,6 @@ public class JdbcBatchItemWriterBuilder<T> {
/**
* Configure the {@link DataSource} to be used.
*
* @param dataSource the DataSource
* @return The current instance of the builder for chaining.
* @see JdbcBatchItemWriter#setDataSource(DataSource)
@@ -66,8 +65,7 @@ public class JdbcBatchItemWriterBuilder<T> {
/**
* If set to true, confirms that every insert results in the update of at least one
* row in the database. Defaults to true.
*
* row in the database. Defaults to true.
* @param assertUpdates boolean indicator
* @return The current instance of the builder for chaining
* @see JdbcBatchItemWriter#setAssertUpdates(boolean)
@@ -79,9 +77,7 @@ public class JdbcBatchItemWriterBuilder<T> {
}
/**
* Set the SQL statement to be used for each item's updates. This is a required
* field.
*
* Set the SQL statement to be used for each item's updates. This is a required field.
* @param sql SQL string
* @return The current instance of the builder for chaining
* @see JdbcBatchItemWriter#setSql(String)
@@ -93,41 +89,41 @@ public class JdbcBatchItemWriterBuilder<T> {
}
/**
* Configures a {@link ItemPreparedStatementSetter} for use by the writer. This
* should only be used if {@link #columnMapped()} isn't called.
*
* Configures a {@link ItemPreparedStatementSetter} for use by the writer. This should
* only be used if {@link #columnMapped()} isn't called.
* @param itemPreparedStatementSetter The {@link ItemPreparedStatementSetter}
* @return The current instance of the builder for chaining
* @see JdbcBatchItemWriter#setItemPreparedStatementSetter(ItemPreparedStatementSetter)
*/
public JdbcBatchItemWriterBuilder<T> itemPreparedStatementSetter(ItemPreparedStatementSetter<T> itemPreparedStatementSetter) {
public JdbcBatchItemWriterBuilder<T> itemPreparedStatementSetter(
ItemPreparedStatementSetter<T> itemPreparedStatementSetter) {
this.itemPreparedStatementSetter = itemPreparedStatementSetter;
return this;
}
/**
* Configures a {@link ItemSqlParameterSourceProvider} for use by the writer. This
* Configures a {@link ItemSqlParameterSourceProvider} for use by the writer. This
* should only be used if {@link #beanMapped()} isn't called.
*
* @param itemSqlParameterSourceProvider The {@link ItemSqlParameterSourceProvider}
* @return The current instance of the builder for chaining
* @see JdbcBatchItemWriter#setItemSqlParameterSourceProvider(ItemSqlParameterSourceProvider)
*/
public JdbcBatchItemWriterBuilder<T> itemSqlParameterSourceProvider(ItemSqlParameterSourceProvider<T> itemSqlParameterSourceProvider) {
public JdbcBatchItemWriterBuilder<T> itemSqlParameterSourceProvider(
ItemSqlParameterSourceProvider<T> itemSqlParameterSourceProvider) {
this.itemSqlParameterSourceProvider = itemSqlParameterSourceProvider;
return this;
}
/**
* The {@link NamedParameterJdbcOperations} instance to use. If one isn't provided,
* a {@link DataSource} is required.
*
* The {@link NamedParameterJdbcOperations} instance to use. If one isn't provided, a
* {@link DataSource} is required.
* @param namedParameterJdbcOperations The template
* @return The current instance of the builder for chaining
*/
public JdbcBatchItemWriterBuilder<T> namedParametersJdbcTemplate(NamedParameterJdbcOperations namedParameterJdbcOperations) {
public JdbcBatchItemWriterBuilder<T> namedParametersJdbcTemplate(
NamedParameterJdbcOperations namedParameterJdbcOperations) {
this.namedParameterJdbcTemplate = namedParameterJdbcOperations;
return this;
@@ -139,7 +135,6 @@ public class JdbcBatchItemWriterBuilder<T> {
*
* NOTE: The item type for this {@link org.springframework.batch.item.ItemWriter} must
* be castable to <code>Map&lt;String,Object&gt;&gt;</code>.
*
* @return The current instance of the builder for chaining
* @see ColumnMapItemPreparedStatementSetter
*/
@@ -152,7 +147,6 @@ public class JdbcBatchItemWriterBuilder<T> {
/**
* Creates a {@link BeanPropertyItemSqlParameterSourceProvider} to be used as your
* {@link ItemSqlParameterSourceProvider}.
*
* @return The current instance of the builder for chaining
* @see BeanPropertyItemSqlParameterSourceProvider
*/
@@ -164,7 +158,6 @@ public class JdbcBatchItemWriterBuilder<T> {
/**
* Validates configuration and builds the {@link JdbcBatchItemWriter}.
*
* @return a {@link JdbcBatchItemWriter}
*/
@SuppressWarnings("unchecked")
@@ -174,8 +167,7 @@ public class JdbcBatchItemWriterBuilder<T> {
Assert.notNull(this.sql, "A SQL statement is required");
int mappedValue = this.mapped.intValue();
Assert.state(mappedValue != 3,
"Either an item can be mapped via db column or via bean spec, can't be both");
Assert.state(mappedValue != 3, "Either an item can be mapped via db column or via bean spec, can't be both");
JdbcBatchItemWriter<T> writer = new JdbcBatchItemWriter<>();
writer.setSql(this.sql);
@@ -183,13 +175,15 @@ public class JdbcBatchItemWriterBuilder<T> {
writer.setItemSqlParameterSourceProvider(this.itemSqlParameterSourceProvider);
writer.setItemPreparedStatementSetter(this.itemPreparedStatementSetter);
if(mappedValue == 1) {
((JdbcBatchItemWriter<Map<String,Object>>)writer).setItemPreparedStatementSetter(new ColumnMapItemPreparedStatementSetter());
} else if(mappedValue == 2) {
if (mappedValue == 1) {
((JdbcBatchItemWriter<Map<String, Object>>) writer)
.setItemPreparedStatementSetter(new ColumnMapItemPreparedStatementSetter());
}
else if (mappedValue == 2) {
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>());
}
if(this.dataSource != null) {
if (this.dataSource != null) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(this.dataSource);
}
@@ -197,4 +191,5 @@ public class JdbcBatchItemWriterBuilder<T> {
return writer;
}
}

View File

@@ -74,10 +74,9 @@ public class JdbcCursorItemReaderBuilder<T> {
private boolean connectionAutoCommit;
/**
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
* for restart purposes.
*
* Configure if the state of the
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -91,7 +90,6 @@ public class JdbcCursorItemReaderBuilder<T> {
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -104,7 +102,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -117,7 +114,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -130,7 +126,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* The {@link DataSource} to read from
*
* @param dataSource a relational data base
* @return this instance for method chaining
* @see JdbcCursorItemReader#setDataSource(DataSource)
@@ -143,7 +138,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* A hint to the driver as to how many rows to return with each fetch.
*
* @param fetchSize the hint
* @return this instance for method chaining
* @see JdbcCursorItemReader#setFetchSize(int)
@@ -156,7 +150,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* The max number of rows the {@link java.sql.ResultSet} can contain
*
* @param maxRows the max
* @return this instance for method chaining
* @see JdbcCursorItemReader#setMaxRows(int)
@@ -169,7 +162,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* The time in milliseconds for the query to timeout
*
* @param queryTimeout timeout
* @return this instance for method chaining
* @see JdbcCursorItemReader#setQueryTimeout(int)
@@ -188,9 +180,8 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* Indicates if the reader should verify the current position of the
* {@link java.sql.ResultSet} after being passed to the {@link RowMapper}. Defaults
* to true.
*
* {@link java.sql.ResultSet} after being passed to the {@link RowMapper}. Defaults to
* true.
* @param verifyCursorPosition indicator
* @return this instance for method chaining
* @see JdbcCursorItemReader#setVerifyCursorPosition(boolean)
@@ -204,7 +195,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* Indicates if the JDBC driver supports setting the absolute row on the
* {@link java.sql.ResultSet}.
*
* @param driverSupportsAbsolute indicator
* @return this instance for method chaining
* @see JdbcCursorItemReader#setDriverSupportsAbsolute(boolean)
@@ -218,7 +208,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* Indicates that the connection used for the cursor is being used by all other
* processing, therefor part of the same transaction.
*
* @param useSharedExtendedConnection indicator
* @return this instance for method chaining
* @see JdbcCursorItemReader#setUseSharedExtendedConnection(boolean)
@@ -232,7 +221,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* Configures the provided {@link PreparedStatementSetter} to be used to populate any
* arguments in the SQL query to be executed for the reader.
*
* @param preparedStatementSetter setter
* @return this instance for method chaining
* @see JdbcCursorItemReader#setPreparedStatementSetter(PreparedStatementSetter)
@@ -246,7 +234,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* Configures a {@link PreparedStatementSetter} that will use the array as the values
* to be set on the query to be executed for this reader.
*
* @param args values to set on the reader query
* @return this instance for method chaining
*/
@@ -258,9 +245,8 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* Configures a {@link PreparedStatementSetter} that will use the Object [] as the
* values to be set on the query to be executed for this reader. The int[] will
* values to be set on the query to be executed for this reader. The int[] will
* provide the types ({@link java.sql.Types}) for each of the values provided.
*
* @param args values to set on the query
* @param types the type for each value in the args array
* @return this instance for method chaining
@@ -274,7 +260,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* Configures a {@link PreparedStatementSetter} that will use the List as the values
* to be set on the query to be executed for this reader.
*
* @param args values to set on the query
* @return this instance for method chaining
*/
@@ -287,7 +272,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* The query to be executed for this reader
*
* @param sql query
* @return this instance for method chaining
* @see JdbcCursorItemReader#setSql(String)
@@ -300,7 +284,6 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* The {@link RowMapper} used to map the results of the cursor to each item.
*
* @param rowMapper {@link RowMapper}
* @return this instance for method chaining
* @see JdbcCursorItemReader#setRowMapper(RowMapper)
@@ -312,9 +295,7 @@ public class JdbcCursorItemReaderBuilder<T> {
}
/**
* Creates a {@link BeanPropertyRowMapper} to be used as your
* {@link RowMapper}.
*
* Creates a {@link BeanPropertyRowMapper} to be used as your {@link RowMapper}.
* @param mappedClass the class for the row mapper
* @return this instance for method chaining
* @see BeanPropertyRowMapper
@@ -326,9 +307,8 @@ public class JdbcCursorItemReaderBuilder<T> {
}
/**
* Set whether "autoCommit" should be overridden for the connection used by the cursor.
* If not set, defaults to Connection / Datasource default configuration.
*
* Set whether "autoCommit" should be overridden for the connection used by the
* cursor. If not set, defaults to Connection / Datasource default configuration.
* @param connectionAutoCommit value to set on underlying JDBC connection
* @return this instance for method chaining
* @see JdbcCursorItemReader#setConnectionAutoCommit(boolean)
@@ -341,13 +321,11 @@ public class JdbcCursorItemReaderBuilder<T> {
/**
* Validates configuration and builds a new reader instance.
*
* @return a fully constructed {@link JdbcCursorItemReader}
*/
public JdbcCursorItemReader<T> build() {
if(this.saveState) {
Assert.hasText(this.name,
"A name is required when saveState is set to true");
if (this.saveState) {
Assert.hasText(this.name, "A name is required when saveState is set to true");
}
Assert.hasText(this.sql, "A query is required");
@@ -356,7 +334,7 @@ public class JdbcCursorItemReaderBuilder<T> {
JdbcCursorItemReader<T> reader = new JdbcCursorItemReader<>();
if(StringUtils.hasText(this.name)) {
if (StringUtils.hasText(this.name)) {
reader.setName(this.name);
}
@@ -378,4 +356,5 @@ public class JdbcCursorItemReaderBuilder<T> {
return reader;
}
}
}

View File

@@ -40,10 +40,10 @@ import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.util.Assert;
/**
* This is a builder for the {@link JdbcPagingItemReader}. When configuring, either a
* {@link PagingQueryProvider} or the SQL fragments should be provided. If the SQL
* This is a builder for the {@link JdbcPagingItemReader}. When configuring, either a
* {@link PagingQueryProvider} or the SQL fragments should be provided. If the SQL
* fragments are provided, the metadata from the provided {@link DataSource} will be used
* to create a PagingQueryProvider for you. If both are provided, the PagingQueryProvider
* to create a PagingQueryProvider for you. If both are provided, the PagingQueryProvider
* will be used.
*
* @author Michael Minella
@@ -85,10 +85,9 @@ public class JdbcPagingItemReaderBuilder<T> {
private int currentItemCount;
/**
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
* for restart purposes.
*
* Configure if the state of the
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -102,7 +101,6 @@ public class JdbcPagingItemReaderBuilder<T> {
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -115,7 +113,6 @@ public class JdbcPagingItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -128,7 +125,6 @@ public class JdbcPagingItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -140,8 +136,7 @@ public class JdbcPagingItemReaderBuilder<T> {
}
/**
* The {@link DataSource} to query against. Required.
*
* The {@link DataSource} to query against. Required.
* @param dataSource the {@link DataSource}
* @return this instance for method chaining
* @see JdbcPagingItemReader#setDataSource(DataSource)
@@ -154,7 +149,6 @@ public class JdbcPagingItemReaderBuilder<T> {
/**
* A hint to the underlying RDBMS as to how many records to return with each fetch.
*
* @param fetchSize number of records
* @return this instance for method chaining
* @see JdbcPagingItemReader#setFetchSize(int)
@@ -166,8 +160,7 @@ public class JdbcPagingItemReaderBuilder<T> {
}
/**
* The {@link RowMapper} used to map the query results to objects. Required.
*
* The {@link RowMapper} used to map the query results to objects. Required.
* @param rowMapper a {@link RowMapper} implementation
* @return this instance for method chaining
* @see JdbcPagingItemReader#setRowMapper(RowMapper)
@@ -179,9 +172,7 @@ public class JdbcPagingItemReaderBuilder<T> {
}
/**
* Creates a {@link BeanPropertyRowMapper} to be used as your
* {@link RowMapper}.
*
* Creates a {@link BeanPropertyRowMapper} to be used as your {@link RowMapper}.
* @param mappedClass the class for the row mapper
* @return this instance for method chaining
* @see BeanPropertyRowMapper
@@ -194,7 +185,6 @@ public class JdbcPagingItemReaderBuilder<T> {
/**
* A {@link Map} of values to set on the SQL's prepared statement.
*
* @param parameterValues Map of values
* @return this instance for method chaining
* @see JdbcPagingItemReader#setParameterValues(Map)
@@ -206,9 +196,8 @@ public class JdbcPagingItemReaderBuilder<T> {
}
/**
* The number of records to request per page/query. Defaults to 10. Must be greater
* The number of records to request per page/query. Defaults to 10. Must be greater
* than zero.
*
* @param pageSize number of items
* @return this instance for method chaining
* @see JdbcPagingItemReader#setPageSize(int)
@@ -220,9 +209,9 @@ public class JdbcPagingItemReaderBuilder<T> {
}
/**
* The SQL <code>GROUP BY</code> clause for a db specific @{@link PagingQueryProvider}.
* This is only used if a PagingQueryProvider is not provided.
*
* The SQL <code>GROUP BY</code> clause for a db
* specific @{@link PagingQueryProvider}. This is only used if a PagingQueryProvider
* is not provided.
* @param groupClause the SQL clause
* @return this instance for method chaining
* @see AbstractSqlPagingQueryProvider#setGroupClause(String)
@@ -236,7 +225,6 @@ public class JdbcPagingItemReaderBuilder<T> {
/**
* The SQL <code>SELECT</code> clause for a db specific {@link PagingQueryProvider}.
* This is only used if a PagingQueryProvider is not provided.
*
* @param selectClause the SQL clause
* @return this instance for method chaining
* @see AbstractSqlPagingQueryProvider#setSelectClause(String)
@@ -250,7 +238,6 @@ public class JdbcPagingItemReaderBuilder<T> {
/**
* The SQL <code>FROM</code> clause for a db specific {@link PagingQueryProvider}.
* This is only used if a PagingQueryProvider is not provided.
*
* @param fromClause the SQL clause
* @return this instance for method chaining
* @see AbstractSqlPagingQueryProvider#setFromClause(String)
@@ -264,7 +251,6 @@ public class JdbcPagingItemReaderBuilder<T> {
/**
* The SQL <code>WHERE</code> clause for a db specific {@link PagingQueryProvider}.
* This is only used if a PagingQueryProvider is not provided.
*
* @param whereClause the SQL clause
* @return this instance for method chaining
* @see AbstractSqlPagingQueryProvider#setWhereClause(String)
@@ -276,8 +262,7 @@ public class JdbcPagingItemReaderBuilder<T> {
}
/**
* The keys to sort by. These keys <em>must</em> create a unique key.
*
* The keys to sort by. These keys <em>must</em> create a unique key.
* @param sortKeys keys to sort by and the direction for each.
* @return this instance for method chaining
* @see AbstractSqlPagingQueryProvider#setSortKeys(Map)
@@ -289,11 +274,10 @@ public class JdbcPagingItemReaderBuilder<T> {
}
/**
* A {@link PagingQueryProvider} to provide the queries required. If provided, the
* SQL fragments configured via {@link #selectClause(String)},
* A {@link PagingQueryProvider} to provide the queries required. If provided, the SQL
* fragments configured via {@link #selectClause(String)},
* {@link #fromClause(String)}, {@link #whereClause(String)}, {@link #groupClause},
* and {@link #sortKeys(Map)} are ignored.
*
* @param provider the db specific query provider
* @return this instance for method chaining
* @see JdbcPagingItemReader#setQueryProvider(PagingQueryProvider)
@@ -306,16 +290,14 @@ public class JdbcPagingItemReaderBuilder<T> {
/**
* Provides a completely built instance of the {@link JdbcPagingItemReader}
*
* @return a {@link JdbcPagingItemReader}
*/
public JdbcPagingItemReader<T> build() {
Assert.isTrue(this.pageSize > 0, "pageSize must be greater than zero");
Assert.notNull(this.dataSource, "dataSource is required");
if(this.saveState) {
Assert.hasText(this.name,
"A name is required when saveState is set to true");
if (this.saveState) {
Assert.hasText(this.name, "A name is required when saveState is set to true");
}
JdbcPagingItemReader<T> reader = new JdbcPagingItemReader<>();
@@ -328,7 +310,7 @@ public class JdbcPagingItemReaderBuilder<T> {
reader.setFetchSize(this.fetchSize);
reader.setParameterValues(this.parameterValues);
if(this.queryProvider == null) {
if (this.queryProvider == null) {
Assert.hasLength(this.selectClause, "selectClause is required when not providing a PagingQueryProvider");
Assert.hasLength(this.fromClause, "fromClause is required when not providing a PagingQueryProvider");
Assert.notEmpty(this.sortKeys, "sortKeys are required when not providing a PagingQueryProvider");
@@ -354,23 +336,45 @@ public class JdbcPagingItemReaderBuilder<T> {
switch (databaseType) {
case DERBY: provider = new DerbyPagingQueryProvider(); break;
case DB2:
case DB2VSE:
case DB2ZOS:
case DB2AS400: provider = new Db2PagingQueryProvider(); break;
case H2: provider = new H2PagingQueryProvider(); break;
case HANA: provider = new HanaPagingQueryProvider(); break;
case HSQL: provider = new HsqlPagingQueryProvider(); break;
case SQLSERVER: provider = new SqlServerPagingQueryProvider(); break;
case MYSQL: provider = new MySqlPagingQueryProvider(); break;
case ORACLE: provider = new OraclePagingQueryProvider(); break;
case POSTGRES: provider = new PostgresPagingQueryProvider(); break;
case SYBASE: provider = new SybasePagingQueryProvider(); break;
case SQLITE: provider = new SqlitePagingQueryProvider(); break;
default:
throw new IllegalArgumentException("Unable to determine PagingQueryProvider type " +
"from database type: " + databaseType);
case DERBY:
provider = new DerbyPagingQueryProvider();
break;
case DB2:
case DB2VSE:
case DB2ZOS:
case DB2AS400:
provider = new Db2PagingQueryProvider();
break;
case H2:
provider = new H2PagingQueryProvider();
break;
case HANA:
provider = new HanaPagingQueryProvider();
break;
case HSQL:
provider = new HsqlPagingQueryProvider();
break;
case SQLSERVER:
provider = new SqlServerPagingQueryProvider();
break;
case MYSQL:
provider = new MySqlPagingQueryProvider();
break;
case ORACLE:
provider = new OraclePagingQueryProvider();
break;
case POSTGRES:
provider = new PostgresPagingQueryProvider();
break;
case SYBASE:
provider = new SybasePagingQueryProvider();
break;
case SQLITE:
provider = new SqlitePagingQueryProvider();
break;
default:
throw new IllegalArgumentException(
"Unable to determine PagingQueryProvider type " + "from database type: " + databaseType);
}
provider.setSelectClause(this.selectClause);
@@ -385,4 +389,5 @@ public class JdbcPagingItemReaderBuilder<T> {
throw new IllegalArgumentException("Unable to determine PagingQueryProvider type", e);
}
}
}

View File

@@ -30,25 +30,29 @@ import org.springframework.util.Assert;
* Builder for {@link JpaCursorItemReader}.
*
* @author Mahmoud Ben Hassine
*
* @since 4.3
*/
public class JpaCursorItemReaderBuilder<T> {
private EntityManagerFactory entityManagerFactory;
private String queryString;
private JpaQueryProvider queryProvider;
private Map<String, Object> parameterValues;
private boolean saveState = true;
private String name;
private int maxItemCount = Integer.MAX_VALUE;
private int currentItemCount;
/**
* Configure if the state of the {@link ItemStreamSupport}
* should be persisted within the {@link ExecutionContext}
* for restart purposes.
*
* Configure if the state of the {@link ItemStreamSupport} should be persisted within
* the {@link ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -59,9 +63,8 @@ public class JpaCursorItemReaderBuilder<T> {
}
/**
* The name used to calculate the key within the {@link ExecutionContext}.
* Required if {@link #saveState(boolean)} is set to true.
*
* The name used to calculate the key within the {@link ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
* @param name name of the reader instance
* @return The current instance of the builder.
* @see ItemStreamSupport#setName(String)
@@ -74,7 +77,6 @@ public class JpaCursorItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -87,7 +89,6 @@ public class JpaCursorItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -99,9 +100,8 @@ public class JpaCursorItemReaderBuilder<T> {
}
/**
* A map of parameter values to be set on the query. The key of the map is
* the name of the parameter to be set with the value being the value to be set.
*
* A map of parameter values to be set on the query. The key of the map is the name of
* the parameter to be set with the value being the value to be set.
* @param parameterValues map of values
* @return this instance for method chaining
* @see JpaCursorItemReader#setParameterValues(Map)
@@ -113,9 +113,8 @@ public class JpaCursorItemReaderBuilder<T> {
}
/**
* A query provider. This should be set only if {@link #queryString(String)}
* have not been set.
*
* A query provider. This should be set only if {@link #queryString(String)} have not
* been set.
* @param queryProvider the query provider
* @return this instance for method chaining
* @see JpaCursorItemReader#setQueryProvider(JpaQueryProvider)
@@ -129,7 +128,6 @@ public class JpaCursorItemReaderBuilder<T> {
/**
* The JPQL query string to execute. This should only be set if
* {@link #queryProvider(JpaQueryProvider)} has not been set.
*
* @param queryString the JPQL query
* @return this instance for method chaining
* @see JpaCursorItemReader#setQueryString(String)
@@ -143,7 +141,6 @@ public class JpaCursorItemReaderBuilder<T> {
/**
* The {@link EntityManagerFactory} to be used for executing the configured
* {@link #queryString}.
*
* @param entityManagerFactory {@link EntityManagerFactory} used to create
* {@link jakarta.persistence.EntityManager}
* @return this instance for method chaining
@@ -156,7 +153,6 @@ public class JpaCursorItemReaderBuilder<T> {
/**
* Returns a fully constructed {@link JpaCursorItemReader}.
*
* @return a new {@link JpaCursorItemReader}
*/
public JpaCursorItemReader<T> build() {
@@ -179,4 +175,5 @@ public class JpaCursorItemReaderBuilder<T> {
reader.setName(this.name);
return reader;
}
}

View File

@@ -30,11 +30,11 @@ import org.springframework.util.Assert;
public class JpaItemWriterBuilder<T> {
private EntityManagerFactory entityManagerFactory;
private boolean usePersist = false;
/**
* The JPA {@link EntityManagerFactory} to obtain an entity manager from. Required.
*
* @param entityManagerFactory the {@link EntityManagerFactory}
* @return this instance for method chaining
* @see JpaItemWriter#setEntityManagerFactory(EntityManagerFactory)
@@ -47,7 +47,6 @@ public class JpaItemWriterBuilder<T> {
/**
* Set whether the entity manager should perform a persist instead of a merge.
*
* @param usePersist defaults to false
* @return this instance for method chaining
* @see JpaItemWriter#setUsePersist(boolean)
@@ -60,12 +59,10 @@ public class JpaItemWriterBuilder<T> {
/**
* Returns a fully built {@link JpaItemWriter}.
*
* @return the writer
*/
public JpaItemWriter<T> build() {
Assert.state(this.entityManagerFactory != null,
"EntityManagerFactory must be provided");
Assert.state(this.entityManagerFactory != null, "EntityManagerFactory must be provided");
JpaItemWriter<T> writer = new JpaItemWriter<>();
writer.setEntityManagerFactory(this.entityManagerFactory);
@@ -73,4 +70,5 @@ public class JpaItemWriterBuilder<T> {
return writer;
}
}

View File

@@ -27,7 +27,6 @@ import org.springframework.util.Assert;
*
* @author Michael Minella
* @author Glenn Renfro
*
* @since 4.0
*/
@@ -54,10 +53,9 @@ public class JpaPagingItemReaderBuilder<T> {
private int currentItemCount;
/**
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
* for restart purposes.
*
* Configure if the state of the
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -71,7 +69,6 @@ public class JpaPagingItemReaderBuilder<T> {
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -84,7 +81,6 @@ public class JpaPagingItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -97,7 +93,6 @@ public class JpaPagingItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -109,9 +104,8 @@ public class JpaPagingItemReaderBuilder<T> {
}
/**
* The number of records to request per page/query. Defaults to 10. Must be greater
* The number of records to request per page/query. Defaults to 10. Must be greater
* than zero.
*
* @param pageSize number of items
* @return this instance for method chaining
* @see JpaPagingItemReader#setPageSize(int)
@@ -123,9 +117,8 @@ public class JpaPagingItemReaderBuilder<T> {
}
/**
* A map of parameter values to be set on the query. The key of the map is the name
* of the parameter to be set with the value being the value to be set.
*
* A map of parameter values to be set on the query. The key of the map is the name of
* the parameter to be set with the value being the value to be set.
* @param parameterValues map of values
* @return this instance for method chaining
* @see JpaPagingItemReader#setParameterValues(Map)
@@ -137,9 +130,8 @@ public class JpaPagingItemReaderBuilder<T> {
}
/**
* A query provider. This should be set only if {@link #queryString(String)} have not
* A query provider. This should be set only if {@link #queryString(String)} have not
* been set.
*
* @param queryProvider the query provider
* @return this instance for method chaining
* @see JpaPagingItemReader#setQueryProvider(JpaQueryProvider)
@@ -151,9 +143,8 @@ public class JpaPagingItemReaderBuilder<T> {
}
/**
* The HQL query string to execute. This should only be set if
* The HQL query string to execute. This should only be set if
* {@link #queryProvider(JpaQueryProvider)} has not been set.
*
* @param queryString the HQL query
* @return this instance for method chaining
* @see JpaPagingItemReader#setQueryString(String)
@@ -165,10 +156,10 @@ public class JpaPagingItemReaderBuilder<T> {
}
/**
* Indicates if a transaction should be created around the read (true by default).
* Can be set to false in cases where JPA implementation doesn't support a particular
* transaction, however this may cause object inconsistency in the EntityManagerFactory.
*
* Indicates if a transaction should be created around the read (true by default). Can
* be set to false in cases where JPA implementation doesn't support a particular
* transaction, however this may cause object inconsistency in the
* EntityManagerFactory.
* @param transacted defaults to true
* @return this instance for method chaining
* @see JpaPagingItemReader#setTransacted(boolean)
@@ -182,7 +173,6 @@ public class JpaPagingItemReaderBuilder<T> {
/**
* The {@link EntityManagerFactory} to be used for executing the configured
* {@link #queryString}.
*
* @param entityManagerFactory {@link EntityManagerFactory} used to create
* {@link jakarta.persistence.EntityManager}
* @return this instance for method chaining
@@ -195,19 +185,17 @@ public class JpaPagingItemReaderBuilder<T> {
/**
* Returns a fully constructed {@link JpaPagingItemReader}.
*
* @return a new {@link JpaPagingItemReader}
*/
public JpaPagingItemReader<T> build() {
Assert.isTrue(this.pageSize > 0, "pageSize must be greater than zero");
Assert.notNull(this.entityManagerFactory, "An EntityManagerFactory is required");
if(this.saveState) {
Assert.hasText(this.name,
"A name is required when saveState is set to true");
if (this.saveState) {
Assert.hasText(this.name, "A name is required when saveState is set to true");
}
if(this.queryProvider == null) {
if (this.queryProvider == null) {
Assert.hasLength(this.queryString, "Query string is required when queryProvider is null");
}
@@ -226,4 +214,5 @@ public class JpaPagingItemReaderBuilder<T> {
return reader;
}
}

View File

@@ -76,10 +76,9 @@ public class StoredProcedureItemReaderBuilder<T> {
private String name;
/**
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
* for restart purposes.
*
* Configure if the state of the
* {@link org.springframework.batch.item.ItemStreamSupport} should be persisted within
* the {@link org.springframework.batch.item.ExecutionContext} for restart purposes.
* @param saveState defaults to true
* @return The current instance of the builder.
*/
@@ -93,7 +92,6 @@ public class StoredProcedureItemReaderBuilder<T> {
* The name used to calculate the key within the
* {@link org.springframework.batch.item.ExecutionContext}. Required if
* {@link #saveState(boolean)} is set to true.
*
* @param name name of the reader instance
* @return The current instance of the builder.
* @see org.springframework.batch.item.ItemStreamSupport#setName(String)
@@ -106,7 +104,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* Configure the max number of items to be read.
*
* @param maxItemCount the max items to be read
* @return The current instance of the builder.
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
@@ -119,7 +116,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* Index for the current item. Used on restarts to indicate where to start from.
*
* @param currentItemCount current index
* @return this instance for method chaining
* @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
@@ -132,7 +128,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* The {@link DataSource} to read from
*
* @param dataSource a relational data base
* @return this instance for method chaining
* @see StoredProcedureItemReader#setDataSource(DataSource)
@@ -145,7 +140,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* A hint to the driver as to how many rows to return with each fetch.
*
* @param fetchSize the hint
* @return this instance for method chaining
* @see StoredProcedureItemReader#setFetchSize(int)
@@ -158,7 +152,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* The max number of rows the {@link java.sql.ResultSet} can contain
*
* @param maxRows the max
* @return this instance for method chaining
* @see StoredProcedureItemReader#setMaxRows(int)
@@ -171,7 +164,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* The time in milliseconds for the query to timeout
*
* @param queryTimeout timeout
* @return this instance for method chaining
* @see StoredProcedureItemReader#setQueryTimeout(int)
@@ -184,7 +176,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* Indicates if SQL warnings should be ignored or if an exception should be thrown.
*
* @param ignoreWarnings indicator. Defaults to true
* @return this instance for method chaining
* @see AbstractCursorItemReader#setIgnoreWarnings(boolean)
@@ -197,9 +188,8 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* Indicates if the reader should verify the current position of the
* {@link java.sql.ResultSet} after being passed to the {@link RowMapper}. Defaults
* to true.
*
* {@link java.sql.ResultSet} after being passed to the {@link RowMapper}. Defaults to
* true.
* @param verifyCursorPosition indicator
* @return this instance for method chaining
* @see StoredProcedureItemReader#setVerifyCursorPosition(boolean)
@@ -213,7 +203,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* Indicates if the JDBC driver supports setting the absolute row on the
* {@link java.sql.ResultSet}.
*
* @param driverSupportsAbsolute indicator
* @return this instance for method chaining
* @see StoredProcedureItemReader#setDriverSupportsAbsolute(boolean)
@@ -227,7 +216,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* Indicates that the connection used for the cursor is being used by all other
* processing, therefor part of the same transaction.
*
* @param useSharedExtendedConnection indicator
* @return this instance for method chaining
* @see StoredProcedureItemReader#setUseSharedExtendedConnection(boolean)
@@ -241,12 +229,12 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* Configures the provided {@link PreparedStatementSetter} to be used to populate any
* arguments in the SQL query to be executed for the reader.
*
* @param preparedStatementSetter setter
* @return this instance for method chaining
* @see StoredProcedureItemReader#setPreparedStatementSetter(PreparedStatementSetter)
*/
public StoredProcedureItemReaderBuilder<T> preparedStatementSetter(PreparedStatementSetter preparedStatementSetter) {
public StoredProcedureItemReaderBuilder<T> preparedStatementSetter(
PreparedStatementSetter preparedStatementSetter) {
this.preparedStatementSetter = preparedStatementSetter;
return this;
@@ -254,7 +242,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* The {@link RowMapper} used to map the results of the cursor to each item.
*
* @param rowMapper {@link RowMapper}
* @return this instance for method chaining
* @see StoredProcedureItemReader#setRowMapper(RowMapper)
@@ -267,7 +254,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* The name of the stored procedure to execute
*
* @param procedureName name of the procedure
* @return this instance for method chaining
* @see StoredProcedureItemReader#setProcedureName(String)
@@ -280,7 +266,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* SQL parameters to be set when executing the stored procedure
*
* @param parameters parameters to be set
* @return this instance for method chaining
* @see StoredProcedureItemReader#setParameters(SqlParameter[])
@@ -293,7 +278,6 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* Indicates the stored procedure is a function
*
* @return this instance for method chaining
* @see StoredProcedureItemReader#setFunction(boolean)
*/
@@ -304,9 +288,8 @@ public class StoredProcedureItemReaderBuilder<T> {
}
/**
* The parameter position of the REF CURSOR. Only used for Oracle and PostgreSQL that
* use REF CURSORs. For any other database, this should remain as the default (0).
*
* The parameter position of the REF CURSOR. Only used for Oracle and PostgreSQL that
* use REF CURSORs. For any other database, this should remain as the default (0).
* @param refCursorPosition the parameter position
* @return this instance for method chaining
* @see StoredProcedureItemReader#setRefCursorPosition(int)
@@ -319,13 +302,11 @@ public class StoredProcedureItemReaderBuilder<T> {
/**
* Validates configuration and builds a new reader instance
*
* @return a fully constructed {@link StoredProcedureItemReader}
*/
public StoredProcedureItemReader<T> build() {
if(this.saveState) {
Assert.hasText(this.name,
"A name is required when saveSate is set to true");
if (this.saveState) {
Assert.hasText(this.name, "A name is required when saveSate is set to true");
}
Assert.notNull(this.procedureName, "The name of the stored procedure must be provided");
@@ -334,7 +315,7 @@ public class StoredProcedureItemReaderBuilder<T> {
StoredProcedureItemReader<T> itemReader = new StoredProcedureItemReader<>();
if(StringUtils.hasText(this.name)) {
if (StringUtils.hasText(this.name)) {
itemReader.setName(this.name);
}

View File

@@ -21,23 +21,27 @@ import org.hibernate.Session;
import org.hibernate.StatelessSession;
/**
* <p>Abstract Hibernate Query Provider to serve as a base class for all
* Hibernate {@link Query} providers.</p>
* <p>
* Abstract Hibernate Query Provider to serve as a base class for all Hibernate
* {@link Query} providers.
* </p>
*
* <p>The implementing provider can be configured to use either
* {@link StatelessSession} sufficient for simple mappings without the need
* to cascade to associated objects or standard Hibernate {@link Session}
* for more advanced mappings or when caching is desired.</p>
* <p>
* The implementing provider can be configured to use either {@link StatelessSession}
* sufficient for simple mappings without the need to cascade to associated objects or
* standard Hibernate {@link Session} for more advanced mappings or when caching is
* desired.
* </p>
*
* @author Anatoly Polinsky
* @author Dave Syer
*
* @since 2.1
*
*/
public abstract class AbstractHibernateQueryProvider<T> implements HibernateQueryProvider<T> {
private StatelessSession statelessSession;
private Session statefulSession;
@Override
@@ -51,7 +55,7 @@ public abstract class AbstractHibernateQueryProvider<T> implements HibernateQuer
}
public boolean isStatelessSession() {
return this.statefulSession==null && this.statelessSession!=null;
return this.statefulSession == null && this.statelessSession != null;
}
protected StatelessSession getStatelessSession() {
@@ -61,4 +65,5 @@ public abstract class AbstractHibernateQueryProvider<T> implements HibernateQuer
protected Session getStatefulSession() {
return statefulSession;
}
}

View File

@@ -23,14 +23,13 @@ import org.springframework.beans.factory.InitializingBean;
/**
* <p>
* Abstract JPA Query Provider to serve as a base class for all JPA
* {@link Query} providers.
* Abstract JPA Query Provider to serve as a base class for all JPA {@link Query}
* providers.
* </p>
*
* @author Anatoly Polinsky
* @author Dave Syer
* @author Mahmoud Ben Hassine
*
* @since 2.1
*/
public abstract class AbstractJpaQueryProvider implements JpaQueryProvider, InitializingBean {
@@ -43,7 +42,6 @@ public abstract class AbstractJpaQueryProvider implements JpaQueryProvider, Init
* {@link HibernateQueryProvider}. This is currently needed to allow
* {@link HibernateQueryProvider} to participate in a user's managed transaction.
* </p>
*
* @param entityManager EntityManager to use
*/
@Override
@@ -55,10 +53,10 @@ public abstract class AbstractJpaQueryProvider implements JpaQueryProvider, Init
* <p>
* Getter for {@link EntityManager}
* </p>
*
* @return entityManager the injected {@link EntityManager}
*/
protected EntityManager getEntityManager() {
return entityManager;
}
}

View File

@@ -24,13 +24,12 @@ import org.springframework.util.StringUtils;
/**
* <p>
* This query provider creates Hibernate {@link Query}s from injected native SQL
* queries. This is useful if there is a need to utilize database-specific
* features such as query hints, the CONNECT keyword in Oracle, etc.
* This query provider creates Hibernate {@link Query}s from injected native SQL queries.
* This is useful if there is a need to utilize database-specific features such as query
* hints, the CONNECT keyword in Oracle, etc.
* </p>
*
*
* @author Anatoly Polinsky
*
* @param <E> entity returned by executing the query
*/
public class HibernateNativeQueryProvider<E> extends AbstractHibernateQueryProvider<E> {
@@ -41,11 +40,11 @@ public class HibernateNativeQueryProvider<E> extends AbstractHibernateQueryProvi
/**
* <p>
* Create an {@link NativeQuery} from the session provided (preferring
* stateless if both are available).
* Create an {@link NativeQuery} from the session provided (preferring stateless if
* both are available).
* </p>
*/
@Override
@Override
@SuppressWarnings("unchecked")
public NativeQuery<E> createQuery() {
@@ -69,4 +68,5 @@ public class HibernateNativeQueryProvider<E> extends AbstractHibernateQueryProvi
Assert.isTrue(StringUtils.hasText(sqlQuery), "Native SQL query cannot be empty");
Assert.notNull(entityClass, "Entity class cannot be NULL");
}
}

View File

@@ -23,15 +23,14 @@ import org.springframework.batch.item.ItemReader;
/**
* <p>
* Interface defining the functionality to be provided for generating queries
* for use with Hibernate {@link ItemReader}s or other custom built artifacts.
* Interface defining the functionality to be provided for generating queries for use with
* Hibernate {@link ItemReader}s or other custom built artifacts.
* </p>
*
*
* @author Anatoly Polinsky
* @author Dave Syer
*
* @since 2.1
*
*
*/
public interface HibernateQueryProvider<T> {
@@ -40,37 +39,33 @@ public interface HibernateQueryProvider<T> {
* Create the query object which type will be determined by the underline
* implementation (e.g. Hibernate, JPA, etc.)
* </p>
*
* @return created query
*/
Query<T> createQuery();
/**
* <p>
* Inject a {@link Session} that can be used as a factory for queries. The
* state of the session is controlled by the caller (i.e. it should be
* closed if necessary).
* Inject a {@link Session} that can be used as a factory for queries. The state of
* the session is controlled by the caller (i.e. it should be closed if necessary).
* </p>
*
*
* <p>
* Use either this method or {@link #setStatelessSession(StatelessSession)}
* </p>
*
* @param session the {@link Session} to set
*/
void setSession(Session session);
/**
* <p>
* Inject a {@link StatelessSession} that can be used as a factory for
* queries. The state of the session is controlled by the caller (i.e. it
* should be closed if necessary).
* Inject a {@link StatelessSession} that can be used as a factory for queries. The
* state of the session is controlled by the caller (i.e. it should be closed if
* necessary).
* </p>
*
*
* <p>
* Use either this method or {@link #setSession(Session)}
* </p>
*
* @param session the {@link StatelessSession} to set
*/
void setStatelessSession(StatelessSession session);

View File

@@ -28,7 +28,6 @@ import org.springframework.util.StringUtils;
* @author Mahmoud Ben Hassine
* @author Parikshit Dutta
* @since 4.3
*
* @param <E> entity returned by executing the query
*/
public class JpaNamedQueryProvider<E> extends AbstractJpaQueryProvider {
@@ -61,4 +60,5 @@ public class JpaNamedQueryProvider<E> extends AbstractJpaQueryProvider {
Assert.isTrue(StringUtils.hasText(this.namedQuery), "Named query cannot be empty");
Assert.notNull(this.entityClass, "Entity class cannot be NULL");
}
}

View File

@@ -23,14 +23,13 @@ import org.springframework.util.StringUtils;
/**
* <p>
* This query provider creates JPA {@link Query}s from injected native SQL
* queries. This is useful if there is a need to utilize database-specific
* features such as query hints, the CONNECT keyword in Oracle, etc.
* This query provider creates JPA {@link Query}s from injected native SQL queries. This
* is useful if there is a need to utilize database-specific features such as query hints,
* the CONNECT keyword in Oracle, etc.
* </p>
*
*
* @author Anatoly Polinsky
* @author Mahmoud Ben Hassine
*
* @param <E> entity returned by executing the query
*/
public class JpaNativeQueryProvider<E> extends AbstractJpaQueryProvider {
@@ -39,7 +38,7 @@ public class JpaNativeQueryProvider<E> extends AbstractJpaQueryProvider {
private String sqlQuery;
@Override
@Override
public Query createQuery() {
return getEntityManager().createNativeQuery(sqlQuery, entityClass);
}
@@ -52,9 +51,10 @@ public class JpaNativeQueryProvider<E> extends AbstractJpaQueryProvider {
this.entityClass = entityClazz;
}
@Override
@Override
public void afterPropertiesSet() throws Exception {
Assert.isTrue(StringUtils.hasText(sqlQuery), "Native SQL query cannot be empty");
Assert.notNull(entityClass, "Entity class cannot be NULL");
}
}

View File

@@ -22,29 +22,31 @@ import jakarta.persistence.Query;
import org.springframework.batch.item.ItemReader;
/**
* <p>Interface defining the functionality to be provided for generating queries
* for use with JPA {@link ItemReader}s or other custom built artifacts.</p>
*
* <p>
* Interface defining the functionality to be provided for generating queries for use with
* JPA {@link ItemReader}s or other custom built artifacts.
* </p>
*
* @author Anatoly Polinsky
* @author Dave Syer
* @author Mahmoud Ben Hassine
* @since 2.1
*
*
*/
public interface JpaQueryProvider {
/**
* <p>Create the query object.</p>
*
* @return created query
*/
/**
* <p>
* Create the query object.
* </p>
* @return created query
*/
public Query createQuery();
/**
* Provide an {@link EntityManager} for the query to be built.
*
* @param entityManager to be used by the {@link JpaQueryProvider}.
*/
void setEntityManager(EntityManager entityManager);
/**
* Provide an {@link EntityManager} for the query to be built.
* @param entityManager to be used by the {@link JpaQueryProvider}.
*/
void setEntityManager(EntityManager entityManager);
}

View File

@@ -30,22 +30,21 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Abstract SQL Paging Query Provider to serve as a base class for all provided
* SQL paging query providers.
*
* Any implementation must provide a way to specify the select clause, from
* clause and optionally a where clause. In addition a way to specify a single
* column sort key must also be provided. This sort key will be used to provide
* the paging functionality. It is recommended that there should be an index for
* the sort key to provide better performance.
*
* Provides properties and preparation for the mandatory "selectClause" and
* "fromClause" as well as for the optional "whereClause". Also provides
* property for the mandatory "sortKeys". <b>Note:</b> The columns that make up
* the sort key must be a true key and not just a column to order by. It is important
* to have a unique key constraint on the sort key to guarantee that no data is lost
* between executions.
*
* Abstract SQL Paging Query Provider to serve as a base class for all provided SQL paging
* query providers.
*
* Any implementation must provide a way to specify the select clause, from clause and
* optionally a where clause. In addition a way to specify a single column sort key must
* also be provided. This sort key will be used to provide the paging functionality. It is
* recommended that there should be an index for the sort key to provide better
* performance.
*
* Provides properties and preparation for the mandatory "selectClause" and "fromClause"
* as well as for the optional "whereClause". Also provides property for the mandatory
* "sortKeys". <b>Note:</b> The columns that make up the sort key must be a true key and
* not just a column to order by. It is important to have a unique key constraint on the
* sort key to guarantee that no data is lost between executions.
*
* @author Thomas Risberg
* @author Dave Syer
* @author Michael Minella
@@ -60,7 +59,7 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
private String fromClause;
private String whereClause;
private Map<String, Order> sortKeys = new LinkedHashMap<>();
private String groupClause;
@@ -68,10 +67,9 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
private int parameterCount;
private boolean usingNamedParameters;
/**
* The setter for the group by clause
*
* @param groupClause SQL GROUP BY clause part of the SQL query string
*/
public void setGroupClause(String groupClause) {
@@ -82,10 +80,9 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
this.groupClause = null;
}
}
/**
* The getter for the group by clause
*
* @return SQL GROUP BY clause part of the SQL query string
*/
public String getGroupClause() {
@@ -100,7 +97,6 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
}
/**
*
* @return SQL SELECT clause part of SQL query string
*/
protected String getSelectClause() {
@@ -115,7 +111,6 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
}
/**
*
* @return SQL FROM clause part of SQL query string
*/
protected String getFromClause() {
@@ -135,7 +130,6 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
}
/**
*
* @return SQL WHERE clause part of SQL query string
*/
protected String getWhereClause() {
@@ -150,32 +144,31 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
}
/**
* A Map&lt;String, Boolean&gt; of sort columns as the key and boolean for ascending/descending (ascending = true).
*
* A Map&lt;String, Boolean&gt; of sort columns as the key and boolean for
* ascending/descending (ascending = true).
* @return sortKey key to use to sort and limit page content
*/
@Override
@Override
public Map<String, Order> getSortKeys() {
return sortKeys;
}
@Override
@Override
public int getParameterCount() {
return parameterCount;
}
@Override
@Override
public boolean isUsingNamedParameters() {
return usingNamedParameters;
}
/**
* The sort key placeholder will vary depending on whether named parameters
* or traditional placeholders are used in query strings.
*
* The sort key placeholder will vary depending on whether named parameters or
* traditional placeholders are used in query strings.
* @return place holder for sortKey.
*/
@Override
@Override
public String getSortKeyPlaceHolder(String keyName) {
return usingNamedParameters ? ":_" + keyName : "?";
}
@@ -184,7 +177,7 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
* Check mandatory properties.
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
@Override
public void init(DataSource dataSource) throws Exception {
Assert.notNull(dataSource, "A DataSource is required");
Assert.hasLength(selectClause, "selectClause must be specified");
@@ -196,7 +189,7 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
if (whereClause != null) {
sql.append(" WHERE ").append(whereClause);
}
if(groupClause != null) {
if (groupClause != null) {
sql.append(" GROUP BY ").append(groupClause);
}
List<String> namedParameters = new ArrayList<>();
@@ -211,40 +204,38 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
}
/**
* Method generating the query string to be used for retrieving the first
* page. This method must be implemented in sub classes.
*
* Method generating the query string to be used for retrieving the first page. This
* method must be implemented in sub classes.
* @param pageSize number of rows to read per page
* @return query string
*/
@Override
@Override
public abstract String generateFirstPageQuery(int pageSize);
/**
* Method generating the query string to be used for retrieving the pages
* following the first page. This method must be implemented in sub classes.
*
* Method generating the query string to be used for retrieving the pages following
* the first page. This method must be implemented in sub classes.
* @param pageSize number of rows to read per page
* @return query string
*/
@Override
@Override
public abstract String generateRemainingPagesQuery(int pageSize);
/**
* Method generating the query string to be used for jumping to a specific
* item position. This method must be implemented in sub classes.
*
* Method generating the query string to be used for jumping to a specific item
* position. This method must be implemented in sub classes.
* @param itemIndex the index of the item to jump to
* @param pageSize number of rows to read per page
* @return query string
*/
@Override
@Override
public abstract String generateJumpToItemQuery(int itemIndex, int pageSize);
private String removeKeyWord(String keyWord, String clause) {
String temp = clause.trim();
int length = keyWord.length();
if (temp.toLowerCase().startsWith(keyWord) && Character.isWhitespace(temp.charAt(length)) && temp.length() > length + 1) {
if (temp.toLowerCase().startsWith(keyWord) && Character.isWhitespace(temp.charAt(length))
&& temp.length() > length + 1) {
return temp.substring(length + 1);
}
else {
@@ -253,7 +244,6 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
}
/**
*
* @return sortKey key to use to sort and limit page content (without alias)
*/
@Override
@@ -268,11 +258,13 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
if (columnIndex < key.length()) {
sortKeysWithoutAliases.put(key.substring(columnIndex), sortKeyEntry.getValue());
}
} else {
}
else {
sortKeysWithoutAliases.put(sortKeyEntry.getKey(), sortKeyEntry.getValue());
}
}
return sortKeysWithoutAliases;
}
}

View File

@@ -27,11 +27,13 @@ import java.sql.SQLException;
import java.util.Map;
/**
* <p>Implementation of the {@link ItemPreparedStatementSetter} interface that assumes all
* keys are contained within a {@link Map} with the column name as the key. It assumes nothing
* about ordering, and assumes that the order the entry set can be iterated over is the same as
* the PreparedStatement should be set.</p>
*
* <p>
* Implementation of the {@link ItemPreparedStatementSetter} interface that assumes all
* keys are contained within a {@link Map} with the column name as the key. It assumes
* nothing about ordering, and assumes that the order the entry set can be iterated over
* is the same as the PreparedStatement should be set.
* </p>
*
* @author Lucas Ward
* @author Dave Syer
* @see ItemPreparedStatementSetter
@@ -39,11 +41,11 @@ import java.util.Map;
*/
public class ColumnMapItemPreparedStatementSetter implements ItemPreparedStatementSetter<Map<String, Object>> {
@Override
@Override
public void setValues(Map<String, Object> item, PreparedStatement ps) throws SQLException {
Assert.isInstanceOf(Map.class, item, "Input to map PreparedStatement parameters must be of type Map.");
int counter = 1;
for(Object value : item.values()){
for (Object value : item.values()) {
StatementCreatorUtils.setParameterValue(ps, counter, SqlTypeValue.TYPE_UNKNOWN, value);
counter++;
}

View File

@@ -18,9 +18,9 @@ package org.springframework.batch.item.database.support;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
/**
* Factory for creating {@link DataFieldMaxValueIncrementer} implementations
* based upon a provided string.
*
* Factory for creating {@link DataFieldMaxValueIncrementer} implementations based upon a
* provided string.
*
* @author Lucas Ward
*
*/
@@ -28,29 +28,28 @@ public interface DataFieldMaxValueIncrementerFactory {
/**
* Return the {@link DataFieldMaxValueIncrementer} for the provided database type.
*
* @param databaseType string represented database type
* @param incrementerName incrementer name to create. In many cases this may be the
* sequence name
* sequence name
* @return incrementer
* @throws IllegalArgumentException if databaseType is invalid type, or incrementerName
* is null.
* @throws IllegalArgumentException if databaseType is invalid type, or
* incrementerName is null.
*/
public DataFieldMaxValueIncrementer getIncrementer(String databaseType, String incrementerName);
/**
* Returns boolean indicated whether or not the provided string is supported by this
* factory.
*
* @param databaseType {@link String} containing the database type.
* @return true if the incrementerType is supported by this database type. Else false is returned.
* @return true if the incrementerType is supported by this database type. Else false
* is returned.
*/
public boolean isSupportedIncrementerType(String databaseType);
/**
* Returns the list of supported database incrementer types
*
* @return an array of {@link String}s containing the supported incrementer types.
* @return an array of {@link String}s containing the supported incrementer types.
*/
public String[] getSupportedIncrementerTypes();
}

View File

@@ -20,8 +20,7 @@ import org.springframework.batch.item.database.PagingQueryProvider;
import org.springframework.util.StringUtils;
/**
* DB2 implementation of a {@link PagingQueryProvider} using
* database specific features.
* DB2 implementation of a {@link PagingQueryProvider} using database specific features.
*
* @author Thomas Risberg
* @author Michael Minella
@@ -37,7 +36,7 @@ public class Db2PagingQueryProvider extends SqlWindowingPagingQueryProvider {
@Override
public String generateRemainingPagesQuery(int pageSize) {
if(StringUtils.hasText(getGroupClause())) {
if (StringUtils.hasText(getGroupClause())) {
return SqlPagingQueryUtils.generateLimitGroupedSqlQuery(this, buildLimitClause(pageSize));
}
else {

View File

@@ -48,12 +48,12 @@ import static org.springframework.batch.support.DatabaseType.SQLSERVER;
import static org.springframework.batch.support.DatabaseType.SYBASE;
/**
* Default implementation of the {@link DataFieldMaxValueIncrementerFactory}
* interface. Valid database types are given by the {@link DatabaseType} enum.
* Default implementation of the {@link DataFieldMaxValueIncrementerFactory} interface.
* Valid database types are given by the {@link DatabaseType} enum.
*
* Note: For MySql databases, the
* {@link MySQLMaxValueIncrementer#setUseNewConnection(boolean)} will be set to true.
*
*
* @author Lucas Ward
* @author Michael Minella
* @author Drummond Dawson
@@ -67,11 +67,10 @@ public class DefaultDataFieldMaxValueIncrementerFactory implements DataFieldMaxV
private String incrementerColumnName = "ID";
/**
* Public setter for the column name (defaults to "ID") in the incrementer.
* Only used by some platforms (Derby, HSQL, MySQL, SQL Server and Sybase),
* and should be fine for use with Spring Batch meta data as long as the
* default batch schema hasn't been changed.
*
* Public setter for the column name (defaults to "ID") in the incrementer. Only used
* by some platforms (Derby, HSQL, MySQL, SQL Server and Sybase), and should be fine
* for use with Spring Batch meta data as long as the default batch schema hasn't been
* changed.
* @param incrementerColumnName the primary key column name to set
*/
public void setIncrementerColumnName(String incrementerColumnName) {
@@ -105,7 +104,8 @@ public class DefaultDataFieldMaxValueIncrementerFactory implements DataFieldMaxV
return new HanaSequenceMaxValueIncrementer(dataSource, incrementerName);
}
else if (databaseType == MYSQL) {
MySQLMaxValueIncrementer mySQLMaxValueIncrementer = new MySQLMaxValueIncrementer(dataSource, incrementerName, incrementerColumnName);
MySQLMaxValueIncrementer mySQLMaxValueIncrementer = new MySQLMaxValueIncrementer(dataSource,
incrementerName, incrementerColumnName);
mySQLMaxValueIncrementer.setUseNewConnection(true);
return mySQLMaxValueIncrementer;
}
@@ -126,8 +126,8 @@ public class DefaultDataFieldMaxValueIncrementerFactory implements DataFieldMaxV
}
throw new IllegalArgumentException("databaseType argument was not on the approved list");
}
@Override
@Override
public boolean isSupportedIncrementerType(String incrementerType) {
for (DatabaseType type : DatabaseType.values()) {
if (type.name().equalsIgnoreCase(incrementerType)) {
@@ -138,7 +138,7 @@ public class DefaultDataFieldMaxValueIncrementerFactory implements DataFieldMaxV
return false;
}
@Override
@Override
public String[] getSupportedIncrementerTypes() {
List<String> types = new ArrayList<>();
@@ -149,4 +149,5 @@ public class DefaultDataFieldMaxValueIncrementerFactory implements DataFieldMaxV
return types.toArray(new String[types.size()]);
}
}

View File

@@ -24,11 +24,11 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.jdbc.support.JdbcUtils;
/**
* Derby implementation of a {@link PagingQueryProvider} using standard SQL:2003 windowing functions.
* These features are supported starting with Apache Derby version 10.4.1.3.
* Derby implementation of a {@link PagingQueryProvider} using standard SQL:2003 windowing
* functions. These features are supported starting with Apache Derby version 10.4.1.3.
*
* As the OVER() function does not support the ORDER BY clause a sub query is instead used to order the results
* before the ROW_NUM restriction is applied
* As the OVER() function does not support the ORDER BY clause a sub query is instead used
* to order the results before the ROW_NUM restriction is applied
*
* @author Thomas Risberg
* @author David Thexton
@@ -36,7 +36,7 @@ import org.springframework.jdbc.support.JdbcUtils;
* @since 2.0
*/
public class DerbyPagingQueryProvider extends SqlWindowingPagingQueryProvider {
private static final String MINIMAL_DERBY_VERSION = "10.4.1.3";
@Override
@@ -44,11 +44,14 @@ public class DerbyPagingQueryProvider extends SqlWindowingPagingQueryProvider {
super.init(dataSource);
String version = JdbcUtils.extractDatabaseMetaData(dataSource, DatabaseMetaData::getDatabaseProductVersion);
if (!isDerbyVersionSupported(version)) {
throw new InvalidDataAccessResourceUsageException("Apache Derby version " + version + " is not supported by this class, Only version " + MINIMAL_DERBY_VERSION + " or later is supported");
throw new InvalidDataAccessResourceUsageException(
"Apache Derby version " + version + " is not supported by this class, Only version "
+ MINIMAL_DERBY_VERSION + " or later is supported");
}
}
// derby version numbering is M.m.f.p [ {alpha|beta} ] see https://db.apache.org/derby/papers/versionupgrade.html#Basic+Numbering+Scheme
// derby version numbering is M.m.f.p [ {alpha|beta} ] see
// https://db.apache.org/derby/papers/versionupgrade.html#Basic+Numbering+Scheme
private boolean isDerbyVersionSupported(String version) {
String[] minimalVersionParts = MINIMAL_DERBY_VERSION.split("\\.");
String[] versionParts = version.split("[\\. ]");
@@ -57,13 +60,14 @@ public class DerbyPagingQueryProvider extends SqlWindowingPagingQueryProvider {
int versionPart = Integer.parseInt(versionParts[i]);
if (versionPart < minimalVersionPart) {
return false;
} else if (versionPart > minimalVersionPart) {
}
else if (versionPart > minimalVersionPart) {
return true;
}
}
return true;
return true;
}
@Override
protected String getOrderedQueryAlias() {
return "TMP_ORDERED";
@@ -74,12 +78,12 @@ public class DerbyPagingQueryProvider extends SqlWindowingPagingQueryProvider {
return "";
}
@Override
@Override
protected String getOverSubstituteClauseStart() {
return " FROM (SELECT " + getSelectClause();
}
@Override
@Override
protected String getOverSubstituteClauseEnd() {
return " ) AS " + getOrderedQueryAlias();
}

View File

@@ -17,7 +17,9 @@
package org.springframework.batch.item.database.support;
/**
* H2 implementation of a {@link org.springframework.batch.item.database.PagingQueryProvider} using database specific features.
* H2 implementation of a
* {@link org.springframework.batch.item.database.PagingQueryProvider} using database
* specific features.
*
* @author Dave Syer
* @author Henning Pöttker
@@ -43,10 +45,9 @@ public class H2PagingQueryProvider extends AbstractSqlPagingQueryProvider {
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
int page = itemIndex / pageSize;
int offset = (page * pageSize) - 1;
offset = offset<0 ? 0 : offset;
offset = offset < 0 ? 0 : offset;
String limitClause = new StringBuilder().append("OFFSET ")
.append(offset).append(" ROWS FETCH NEXT 1 ROWS ONLY")
String limitClause = new StringBuilder().append("OFFSET ").append(offset).append(" ROWS FETCH NEXT 1 ROWS ONLY")
.toString();
return SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause);
}

View File

@@ -20,7 +20,8 @@ import org.springframework.batch.item.database.PagingQueryProvider;
import org.springframework.util.StringUtils;
/**
* SAP HANA implementation of a {@link PagingQueryProvider} using database specific features.
* SAP HANA implementation of a {@link PagingQueryProvider} using database specific
* features.
*
* @author Jonathan Bregler
* @since 5.0
@@ -34,7 +35,7 @@ public class HanaPagingQueryProvider extends AbstractSqlPagingQueryProvider {
@Override
public String generateRemainingPagesQuery(int pageSize) {
if(StringUtils.hasText(getGroupClause())) {
if (StringUtils.hasText(getGroupClause())) {
return SqlPagingQueryUtils.generateLimitGroupedSqlQuery(this, buildLimitClause(pageSize));
}
else {
@@ -50,7 +51,7 @@ public class HanaPagingQueryProvider extends AbstractSqlPagingQueryProvider {
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
int page = itemIndex / pageSize;
int offset = (page * pageSize) - 1;
offset = offset<0 ? 0 : offset;
offset = offset < 0 ? 0 : offset;
String limitClause = new StringBuilder().append("LIMIT 1 OFFSET ").append(offset).toString();
return SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause);
}

View File

@@ -19,7 +19,9 @@ package org.springframework.batch.item.database.support;
import org.springframework.util.StringUtils;
/**
* HSQLDB implementation of a {@link org.springframework.batch.item.database.PagingQueryProvider} using database specific features.
* HSQLDB implementation of a
* {@link org.springframework.batch.item.database.PagingQueryProvider} using database
* specific features.
*
* @author Thomas Risberg
* @author Michael Minella
@@ -34,7 +36,7 @@ public class HsqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {
@Override
public String generateRemainingPagesQuery(int pageSize) {
if(StringUtils.hasText(getGroupClause())) {
if (StringUtils.hasText(getGroupClause())) {
return SqlPagingQueryUtils.generateGroupedTopSqlQuery(this, true, buildTopClause(pageSize));
}
else {
@@ -50,7 +52,7 @@ public class HsqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
int page = itemIndex / pageSize;
int offset = (page * pageSize) - 1;
offset = offset<0 ? 0 : offset;
offset = offset < 0 ? 0 : offset;
String topClause = new StringBuilder().append("LIMIT ").append(offset).append(" 1").toString();
return SqlPagingQueryUtils.generateTopJumpToQuery(this, topClause);

View File

@@ -36,7 +36,7 @@ public class MySqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {
@Override
public String generateRemainingPagesQuery(int pageSize) {
if(StringUtils.hasText(getGroupClause())) {
if (StringUtils.hasText(getGroupClause())) {
return SqlPagingQueryUtils.generateLimitGroupedSqlQuery(this, buildLimitClause(pageSize));
}
else {
@@ -52,7 +52,7 @@ public class MySqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
int page = itemIndex / pageSize;
int offset = (page * pageSize) - 1;
offset = offset<0 ? 0 : offset;
offset = offset < 0 ? 0 : offset;
String limitClause = new StringBuilder().append("LIMIT ").append(offset).append(", 1").toString();
return SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause);

Some files were not shown because too many files have changed in this diff Show More