diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/MapJobRegistry.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/MapJobRegistry.java
index 791d16ceb..32baf51ec 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/MapJobRegistry.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/MapJobRegistry.java
@@ -78,7 +78,7 @@ public class MapJobRegistry implements ListableJobRegistry {
if (!map.containsKey(name)) {
throw new NoSuchJobException("No job configuration with the name [" + name + "] was registered");
}
- return (Job) ((JobFactory) map.get(name)).createJob();
+ return map.get(name).createJob();
}
}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractListenerParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractListenerParser.java
index 7957c113d..f68b38076 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractListenerParser.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractListenerParser.java
@@ -5,14 +5,15 @@ import java.util.List;
import org.springframework.batch.core.listener.AbstractListenerFactoryBean;
import org.springframework.batch.core.listener.ListenerMetaData;
+import org.springframework.beans.BeanMetadataElement;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
-import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
+import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
/**
* @author Dan Garrette
@@ -23,10 +24,12 @@ import org.w3c.dom.NamedNodeMap;
public abstract class AbstractListenerParser {
private static final String ID_ATTR = "id";
-
+
private static final String REF_ATTR = "ref";
-
- private static final String CLASS_ATTR = "class";
+
+ private static final String BEAN_ELE = "bean";
+
+ private static final String REF_ELE = "ref";
public AbstractBeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(getBeanClass());
@@ -36,23 +39,7 @@ public abstract class AbstractListenerParser {
@SuppressWarnings("unchecked")
public void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
- String id = element.getAttribute(ID_ATTR);
- String listenerRef = element.getAttribute(REF_ATTR);
- String className = element.getAttribute(CLASS_ATTR);
- checkListenerElementAttributes(parserContext, element, id, listenerRef, className);
-
- if (StringUtils.hasText(listenerRef)) {
- builder.addPropertyReference("delegate", listenerRef);
- }
- else if (StringUtils.hasText(className)) {
- RootBeanDefinition beanDef = new RootBeanDefinition(className, null, null);
- builder.addPropertyValue("delegate", beanDef);
- }
- else {
- parserContext.getReaderContext().error(
- "Neither '" + REF_ATTR + "' or '" + CLASS_ATTR + "' specified for <" + element.getTagName()
- + "> element", element);
- }
+ builder.addPropertyValue("delegate", parseListenerElement(element, parserContext));
ManagedMap metaDataMap = new ManagedMap();
for (String metaDataPropertyName : getMethodNameAttributes()) {
@@ -64,20 +51,57 @@ public abstract class AbstractListenerParser {
builder.addPropertyValue("metaDataMap", metaDataMap);
}
- private void checkListenerElementAttributes(ParserContext parserContext, Element element, String id,
- String listenerRef, String className) {
- if (StringUtils.hasText(className) && StringUtils.hasText(listenerRef)) {
- NamedNodeMap attributeNodes = element.getAttributes();
- StringBuilder attributes = new StringBuilder();
- for (int i = 0; i < attributeNodes.getLength(); i++) {
- if (i > 0) {
- attributes.append(" ");
- }
- attributes.append(attributeNodes.item(i));
+ @SuppressWarnings("unchecked")
+ public static BeanMetadataElement parseListenerElement(Element element, ParserContext parserContext) {
+ String listenerRef = element.getAttribute(REF_ATTR);
+ List beanElements = DomUtils.getChildElementsByTagName(element, BEAN_ELE);
+ List refElements = DomUtils.getChildElementsByTagName(element, REF_ELE);
+
+ verifyListenerAttributesAndSubelements(listenerRef, beanElements, refElements, element, parserContext);
+
+ if (StringUtils.hasText(listenerRef)) {
+ return new RuntimeBeanReference(listenerRef);
+ }
+ else if (beanElements.size() == 1) {
+ return parserContext.getDelegate().parseBeanDefinitionElement(beanElements.get(0));
+ }
+ else {
+ return (BeanMetadataElement) parserContext.getDelegate().parsePropertySubElement(refElements.get(0), null);
+ }
+ }
+
+ private static void verifyListenerAttributesAndSubelements(String listenerRef, List beanElements,
+ List refElements, Element element, ParserContext parserContext) {
+ int total = (StringUtils.hasText(listenerRef) ? 1 : 0) + beanElements.size() + refElements.size();
+ if (total != 1) {
+ StringBuilder found = new StringBuilder();
+ if (total == 0) {
+ found.append("None");
}
+ else {
+ if (StringUtils.hasText(listenerRef)) {
+ found.append("'" + REF_ATTR + "' attribute, ");
+ }
+ if (beanElements.size() == 1) {
+ found.append("<" + BEAN_ELE + "/> element, ");
+ }
+ else if (beanElements.size() > 1) {
+ found.append(beanElements.size() + " <" + BEAN_ELE + "/> elements, ");
+ }
+ if (refElements.size() == 1) {
+ found.append("<" + REF_ELE + "/> element, ");
+ }
+ else if (refElements.size() > 1) {
+ found.append(refElements.size() + " <" + REF_ELE + "/> elements, ");
+ }
+ found.delete(found.length() - 2, found.length());
+ }
+
+ String id = element.getAttribute(ID_ATTR);
parserContext.getReaderContext().error(
- "Either '" + REF_ATTR + "' or '" + CLASS_ATTR + "' may be specified, but not both; <"
- + element.getTagName() + "> element specified with attributes: " + attributes, element);
+ "The <" + element.getTagName() + (StringUtils.hasText(id) ? " id=\"" + id + "\"" : "")
+ + "/> element must have exactly one of: '" + REF_ATTR + "' attribute, <" + BEAN_ELE
+ + "/> attribute, or <" + REF_ELE + "/> element. Found: " + found + ".", element);
}
}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java
index d4b59dfc8..8d32d1f0b 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java
@@ -15,7 +15,6 @@
*/
package org.springframework.batch.core.configuration.xml;
-import java.util.Arrays;
import java.util.List;
import org.springframework.beans.MutablePropertyValues;
@@ -78,7 +77,7 @@ public abstract class AbstractStepParser {
AbstractBeanDefinition bd = new GenericBeanDefinition();
@SuppressWarnings("unchecked")
- List taskletElements = (List) DomUtils.getChildElementsByTagName(stepElement, TASKLET_ELE);
+ List taskletElements = DomUtils.getChildElementsByTagName(stepElement, TASKLET_ELE);
if (taskletElements.size() == 1) {
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
parseTasklet(stepElement, taskletElements.get(0), bd, parserContext, stepUnderspecified);
@@ -115,7 +114,7 @@ public abstract class AbstractStepParser {
String taskletRef = taskletElement.getAttribute(TASKLET_REF_ATTR);
@SuppressWarnings("unchecked")
- List chunkElements = (List) DomUtils.getChildElementsByTagName(taskletElement, CHUNK_ELE);
+ List chunkElements = DomUtils.getChildElementsByTagName(taskletElement, CHUNK_ELE);
if (StringUtils.hasText(taskletRef)) {
if (chunkElements.size() > 0) {
parserContext.getReaderContext().error(
@@ -135,7 +134,7 @@ public abstract class AbstractStepParser {
taskletElement);
}
- setUpBeanDefinitionForTaskletStep(taskletElement, bd, parserContext);
+ handleTaskletElement(taskletElement, bd, parserContext);
}
private void parseTaskletRef(String taskletRef, MutablePropertyValues propertyValues) {
@@ -145,40 +144,18 @@ public abstract class AbstractStepParser {
}
}
- private void setUpBeanDefinitionForTaskletStep(Element taskletElement, AbstractBeanDefinition bd,
- ParserContext parserContext) {
-
+ private void handleTaskletElement(Element taskletElement, AbstractBeanDefinition bd, ParserContext parserContext) {
MutablePropertyValues propertyValues = bd.getPropertyValues();
-
- checkStepAttributes(taskletElement, propertyValues);
-
- String jobRepositoryRef = taskletElement.getAttribute(JOB_REPO_ATTR);
- if (StringUtils.hasText(jobRepositoryRef)) {
- RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference(jobRepositoryRef);
- propertyValues.addPropertyValue("jobRepository", jobRepositoryBeanRef);
- }
-
- String transactionManagerRef = taskletElement.getAttribute("transaction-manager");
- if (StringUtils.hasText(transactionManagerRef)) {
- RuntimeBeanReference transactionManagerBeanRef = new RuntimeBeanReference(transactionManagerRef);
- propertyValues.addPropertyValue("transactionManager", transactionManagerBeanRef);
- }
-
- handleTransactionAttributesElement(taskletElement, propertyValues, parserContext);
-
+ handleTaskletAttributes(taskletElement, propertyValues);
+ handleTransactionAttributesElement(taskletElement, propertyValues);
handleListenersElement(taskletElement, propertyValues, parserContext);
-
handleExceptionElement(taskletElement, parserContext, propertyValues, "no-rollback-exception-classes",
"noRollbackExceptionClasses");
-
bd.setRole(BeanDefinition.ROLE_SUPPORT);
-
bd.setSource(parserContext.extractSource(taskletElement));
-
}
- private void handleTransactionAttributesElement(Element stepElement, MutablePropertyValues propertyValues,
- ParserContext parserContext) {
+ private void handleTransactionAttributesElement(Element stepElement, MutablePropertyValues propertyValues) {
@SuppressWarnings("unchecked")
List txAttrElements = DomUtils.getChildElementsByTagName(stepElement, TX_ATTRIBUTES_ELE);
if (txAttrElements.size() == 1) {
@@ -199,36 +176,73 @@ public abstract class AbstractStepParser {
}
@SuppressWarnings("unchecked")
- public static void handleExceptionElement(Element element, ParserContext parserContext,
- MutablePropertyValues propertyValues, String subElementName, String propertyName) {
- List children = DomUtils.getChildElementsByTagName(element, subElementName);
+ private void handleExceptionElement(Element element, ParserContext parserContext,
+ MutablePropertyValues propertyValues, String exceptionListName, String propertyName) {
+ List children = DomUtils.getChildElementsByTagName(element, exceptionListName);
if (children.size() == 1) {
- Element child = children.get(0);
- String exceptions = DomUtils.getTextValue(child);
- String[] exceptionArray = StringUtils.tokenizeToStringArray(exceptions, ",\n");
- ManagedList managedList = new ManagedList();
- managedList.setMergeEnabled(child.hasAttribute(MERGE_ATTR)
- && Boolean.valueOf(child.getAttribute(MERGE_ATTR)));
- managedList.addAll(Arrays.asList(exceptionArray));
- propertyValues.addPropertyValue(propertyName, managedList);
+ Element exceptionClassesElement = children.get(0);
+ ManagedList list = new ManagedList();
+ list.setMergeEnabled(exceptionClassesElement.hasAttribute(MERGE_ATTR)
+ && Boolean.valueOf(exceptionClassesElement.getAttribute(MERGE_ATTR)));
+ addExceptionClasses("include", exceptionClassesElement, list, parserContext);
+ propertyValues.addPropertyValue(propertyName, list);
}
else if (children.size() > 1) {
parserContext.getReaderContext().error(
- "The <" + subElementName + "/> element may not appear more than once in a single <"
+ "The <" + exceptionListName + "/> element may not appear more than once in a single <"
+ element.getNodeName() + "/>.", element);
}
-
}
- private void checkStepAttributes(Element stepElement, MutablePropertyValues propertyValues) {
- String startLimit = stepElement.getAttribute("start-limit");
+ @SuppressWarnings("unchecked")
+ private void addExceptionClasses(String elementName, Element exceptionClassesElement, ManagedList list,
+ ParserContext parserContext) {
+ for (Element child : (List) DomUtils.getChildElementsByTagName(exceptionClassesElement, elementName)) {
+ String className = child.getAttribute("class");
+ try {
+ Class
*
* @author Ben Hale
* @author Lucas Ward
* @author Robert Kasanicky
* @author Dave Syer
+ * @author Dan Garrette
*/
public class LimitCheckingItemSkipPolicy implements SkipPolicy {
private final int skipLimit;
- private final Classifier fatalExceptionClassifier;
-
private final Classifier skippableExceptionClassifier;
/**
- * Convenience constructor that assumes all exception types are skippable
- * and none are fatal.
- * @param skipLimit the number of exceptions allowed to skip
+ * Convenience constructor that assumes all exception types are fatal.
*/
- public LimitCheckingItemSkipPolicy(int skipLimit) {
- this(skipLimit, Collections.> singleton(Exception.class), Collections
- .> emptyList());
+ public LimitCheckingItemSkipPolicy() {
+ this(0, Collections., Boolean> emptyMap());
}
/**
- *
* @param skipLimit the number of skippable exceptions that are allowed to
* be skipped
* @param skippableExceptions exception classes that can be skipped
* (non-critical)
- * @param fatalExceptions exception classes that should never be skipped
*/
- public LimitCheckingItemSkipPolicy(int skipLimit, Collection> skippableExceptions,
- Collection> fatalExceptions) {
- this(skipLimit, new BinaryExceptionClassifier(skippableExceptions), new BinaryExceptionClassifier(
- fatalExceptions));
+ public LimitCheckingItemSkipPolicy(int skipLimit, Map, Boolean> skippableExceptions) {
+ this(skipLimit, new BinaryExceptionClassifier(skippableExceptions));
}
/**
- *
* @param skipLimit the number of skippable exceptions that are allowed to
* be skipped
* @param skippableExceptionClassifier exception classifier for those that
* can be skipped (non-critical)
- * @param fatalExceptionClassifier exception classifier for classes that
- * should never be skipped
*/
- public LimitCheckingItemSkipPolicy(int skipLimit, Classifier skippableExceptionClassifier,
- Classifier fatalExceptionClassifier) {
+ public LimitCheckingItemSkipPolicy(int skipLimit, Classifier skippableExceptionClassifier) {
this.skipLimit = skipLimit;
this.skippableExceptionClassifier = skippableExceptionClassifier;
- this.fatalExceptionClassifier = fatalExceptionClassifier;
}
/**
* Given the provided exception and skip count, determine whether or not
* processing should continue for the given exception. If the exception is
- * not within the list of 'skippable exceptions' or belongs to the list of
- * 'fatal exceptions', false will be returned. If the exception is within
- * the skippable list (and not in the fatal list), and {@link StepExecution}
+ * not classified as skippable in the classifier, false will be returned. If
+ * the exception is classified as skippable and {@link StepExecution}
* skipCount is greater than the skipLimit, then a
* {@link SkipLimitExceededException} will be thrown.
*/
public boolean shouldSkip(Throwable t, int skipCount) {
- if (fatalExceptionClassifier.classify(t)) {
- return false;
- }
if (skippableExceptionClassifier.classify(t)) {
if (skipCount < skipLimit) {
return true;
diff --git a/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.0.xsd b/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.0.xsd
index 9f8241f3d..563290991 100644
--- a/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.0.xsd
+++ b/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.0.xsd
@@ -34,7 +34,7 @@
-
+
@@ -292,11 +292,8 @@
-
-
-
-
-
+
+
@@ -343,6 +340,18 @@
+
+
+
+
+
+
+
+
+
+
@@ -390,8 +399,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -415,7 +467,7 @@
-
+
@@ -438,18 +490,15 @@
-
-
-
-
-
+
+
@@ -461,27 +510,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -555,18 +585,6 @@
]]>
-
-
-
-
-
-
-
-
-
-
-
-
+
+
- A reference to a listener, a POJO with a
- listener-annotated method, or a POJO with
- a method
- referenced by a *-method attribute.
-
-
-
-
-
-
-
-
-
- A class name used to create a listener from the default constructor.
+ A class name.
@@ -630,6 +635,53 @@
+
+
+
+
+
+
+
+ Classify an exception as "included" in the set.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Classify an exception as "excluded" from the set.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A reference to a listener, a POJO with a
+ listener-annotated method, or a POJO with
+ a method referenced by a *-method attribute.
+
+
+
+
+
+
@@ -672,7 +724,7 @@
-
+
@@ -830,4 +882,15 @@
+
+
+
+
+ This attribute indicates the method from the class that should
+ be used to dynamically create a proxy.
+
+
+
+
+
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/ChunkElementParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/ChunkElementParserTests.java
index 7478720fa..894711432 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/ChunkElementParserTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/ChunkElementParserTests.java
@@ -16,12 +16,12 @@
package org.springframework.batch.core.configuration.xml;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
-import java.util.Set;
import org.junit.Test;
import org.springframework.batch.core.Step;
@@ -48,38 +48,30 @@ public class ChunkElementParserTests {
@Test
public void testInheritSkippable() throws Exception {
- Collection> skippable = getExceptionClasses("s1", "skippable",
+ Map, Boolean> skippable = getExceptionClasses("s1",
chunkElementParentAttributeParserTestsContext);
- assertEquals(3, skippable.size());
- boolean e = false;
- boolean f = false;
- for (Class> cls : skippable) {
- if (cls.equals(NullPointerException.class)) {
- e = true;
- }
- else if (cls.equals(ArithmeticException.class)) {
- f = true;
- }
- }
- assertTrue(e);
- assertTrue(f);
+ assertEquals(11, skippable.size());
+ containsClassified(skippable, NullPointerException.class, true);
+ containsClassified(skippable, ArithmeticException.class, true);
+ containsClassified(skippable, CannotAcquireLockException.class, false);
+ containsClassified(skippable, DeadlockLoserDataAccessException.class, false);
}
@Test
- public void testInheritFatal() throws Exception {
- Collection> fatal = getExceptionClasses("s1", "fatal", chunkElementParentAttributeParserTestsContext);
- boolean a = false;
- boolean b = false;
- for (Class> cls : fatal) {
- if (cls.equals(CannotAcquireLockException.class)) {
- a = true;
- }
- else if (cls.equals(DeadlockLoserDataAccessException.class)) {
- b = true;
- }
- }
- assertTrue(a);
- assertTrue(b);
+ public void testInheritSkippableWithNoMerge() throws Exception {
+ Map, Boolean> skippable = getExceptionClasses("s2",
+ chunkElementParentAttributeParserTestsContext);
+ assertEquals(9, skippable.size());
+ containsClassified(skippable, NullPointerException.class, true);
+ assertFalse(skippable.containsKey(ArithmeticException.class));
+ containsClassified(skippable, CannotAcquireLockException.class, false);
+ assertFalse(skippable.containsKey(DeadlockLoserDataAccessException.class));
+ }
+
+ private void containsClassified(Map, Boolean> classified,
+ Class extends Throwable> cls, boolean include) {
+ assertTrue(classified.containsKey(cls));
+ assertEquals(include, classified.get(cls));
}
@Test
@@ -114,37 +106,6 @@ public class ChunkElementParserTests {
assertTrue(h);
}
- @Test
- public void testInheritSkippableWithNoMerge() throws Exception {
- Collection> skippable = getExceptionClasses("s2", "skippable",
- chunkElementParentAttributeParserTestsContext);
- assertEquals(2, skippable.size());
- boolean e = false;
- for (Class> cls : skippable) {
- if (cls.equals(NullPointerException.class)) {
- e = true;
- }
- }
- assertTrue(e);
- }
-
- @Test
- public void testInheritFatalWithNoMerge() throws Exception {
- Collection> fatal = getExceptionClasses("s2", "fatal", chunkElementParentAttributeParserTestsContext);
- boolean a = false;
- boolean b = false;
- for (Class> cls : fatal) {
- if (cls.equals(CannotAcquireLockException.class)) {
- a = true;
- }
- else if (cls.equals(DeadlockLoserDataAccessException.class)) {
- b = true;
- }
- }
- assertTrue(a);
- assertTrue(!b);
- }
-
@Test
public void testInheritStreamsWithNoMerge() throws Exception {
Collection streams = getStreams("s2", chunkElementParentAttributeParserTestsContext);
@@ -173,7 +134,8 @@ public class ChunkElementParserTests {
}
@SuppressWarnings("unchecked")
- private Set> getExceptionClasses(String stepName, String type, ApplicationContext ctx) throws Exception {
+ private Map, Boolean> getExceptionClasses(String stepName, ApplicationContext ctx)
+ throws Exception {
Map beans = ctx.getBeansOfType(Step.class);
assertTrue(beans.containsKey(stepName));
Object step = ctx.getBean(stepName);
@@ -182,10 +144,8 @@ public class ChunkElementParserTests {
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
Object chunkProvider = ReflectionTestUtils.getField(tasklet, "chunkProvider");
Object skipPolicy = ReflectionTestUtils.getField(chunkProvider, "skipPolicy");
- Object classifier = ReflectionTestUtils.getField(skipPolicy, type + "ExceptionClassifier");
- Map, ?> classified = (Map, ?>) ReflectionTestUtils.getField(classifier, "classified");
-
- return classified.keySet();
+ Object classifier = ReflectionTestUtils.getField(skipPolicy, "skippableExceptionClassifier");
+ return (Map, Boolean>) ReflectionTestUtils.getField(classifier, "classified");
}
@SuppressWarnings("unchecked")
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/DummyItemHandlerAdapter.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/DummyItemHandlerAdapter.java
new file mode 100644
index 000000000..5c9ee2edf
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/DummyItemHandlerAdapter.java
@@ -0,0 +1,20 @@
+package org.springframework.batch.core.configuration.xml;
+
+/**
+ * @author Dan Garrette
+ * @since 2.1
+ */
+public class DummyItemHandlerAdapter {
+
+ public Object dummyRead() {
+ return null;
+ }
+
+ public Object dummyProcess(Object o) {
+ return null;
+ }
+
+ public void dummyWrite(Object o) {
+ }
+
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/InlineItemHandlerParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/InlineItemHandlerParserTests.java
new file mode 100644
index 000000000..7a6efae60
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/InlineItemHandlerParserTests.java
@@ -0,0 +1,67 @@
+package org.springframework.batch.core.configuration.xml;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.springframework.batch.item.adapter.ItemProcessorAdapter;
+import org.springframework.batch.item.adapter.ItemReaderAdapter;
+import org.springframework.batch.item.adapter.ItemWriterAdapter;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.test.util.ReflectionTestUtils;
+
+/**
+ * @author Dan Garrette
+ * @since 2.1
+ */
+public class InlineItemHandlerParserTests {
+
+ private ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
+ "org/springframework/batch/core/configuration/xml/InlineItemHandlerParserTests-context.xml");
+
+ @Test
+ public void testInlineHandlers() throws Exception {
+ Object step = ctx.getBean("inlineHandlers");
+ Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
+ Object chunkProvider = ReflectionTestUtils.getField(tasklet, "chunkProvider");
+ Object reader = ReflectionTestUtils.getField(chunkProvider, "itemReader");
+ Object chunkProcessor = ReflectionTestUtils.getField(tasklet, "chunkProcessor");
+ Object processor = ReflectionTestUtils.getField(chunkProcessor, "itemProcessor");
+ Object writer = ReflectionTestUtils.getField(chunkProcessor, "itemWriter");
+
+ assertTrue(reader instanceof TestReader);
+ assertTrue(processor instanceof TestProcessor);
+ assertTrue(writer instanceof TestWriter);
+ }
+
+ @Test
+ public void testInlineAdapters() throws Exception {
+ Object step = ctx.getBean("inlineAdapters");
+ Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
+ Object chunkProvider = ReflectionTestUtils.getField(tasklet, "chunkProvider");
+ Object reader = ReflectionTestUtils.getField(chunkProvider, "itemReader");
+ Object chunkProcessor = ReflectionTestUtils.getField(tasklet, "chunkProcessor");
+ Object processor = ReflectionTestUtils.getField(chunkProcessor, "itemProcessor");
+ Object writer = ReflectionTestUtils.getField(chunkProcessor, "itemWriter");
+
+ assertTrue(reader instanceof ItemReaderAdapter>);
+ Object readerObject = ReflectionTestUtils.getField(reader, "targetObject");
+ assertTrue(readerObject instanceof DummyItemHandlerAdapter);
+ Object readerMethod = ReflectionTestUtils.getField(reader, "targetMethod");
+ assertEquals("dummyRead", readerMethod);
+
+ assertTrue(processor instanceof ItemProcessorAdapter, ?>);
+ Object processorObject = ReflectionTestUtils.getField(processor, "targetObject");
+ assertTrue(processorObject instanceof DummyItemHandlerAdapter);
+ Object processorMethod = ReflectionTestUtils.getField(processor, "targetMethod");
+ assertEquals("dummyProcess", processorMethod);
+
+ assertTrue(writer instanceof ItemWriterAdapter>);
+ Object writerObject = ReflectionTestUtils.getField(writer, "targetObject");
+ assertTrue(writerObject instanceof DummyItemHandlerAdapter);
+ Object writerMethod = ReflectionTestUtils.getField(writer, "targetMethod");
+ assertEquals("dummyWrite", writerMethod);
+ }
+
+}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserTests.java
index e9e420db2..81d3b6d67 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserTests.java
@@ -184,8 +184,7 @@ public class JobParserTests {
@Test
public void testListenerClearingJob() throws Exception {
- // TODO BATCH-1357:
- // assertEquals(0, getListeners("listenerClearingJob", jobParserParentAttributeTestsCtx).size());
+ assertEquals(0, getListeners("listenerClearingJob", jobParserParentAttributeTestsCtx).size());
}
}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserStepFactoryBeanTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserStepFactoryBeanTests.java
index 341d0d99d..cd9b30159 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserStepFactoryBeanTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserStepFactoryBeanTests.java
@@ -19,10 +19,10 @@ package org.springframework.batch.core.configuration.xml;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
+import java.util.HashMap;
import org.junit.Test;
import org.springframework.batch.core.StepListener;
-import org.springframework.batch.core.configuration.xml.StepParserStepFactoryBean;
import org.springframework.batch.core.listener.StepExecutionListenerSupport;
import org.springframework.batch.core.step.JobRepositorySupport;
import org.springframework.batch.core.step.item.ChunkOrientedTasklet;
@@ -147,9 +147,8 @@ public class StepParserStepFactoryBeanTests {
fb.setRetryLimit(5);
fb.setSkipLimit(100);
fb.setRetryListeners(new RetryListenerSupport());
- fb.setSkippableExceptionClasses(new ArrayList>());
- fb.setRetryableExceptionClasses(new ArrayList>());
- fb.setFatalExceptionClasses(new ArrayList>());
+ fb.setSkippableExceptionClasses(new HashMap, Boolean>());
+ fb.setRetryableExceptionClasses(new HashMap, Boolean>());
Object step = fb.getObject();
assertTrue(step instanceof TaskletStep);
@@ -204,9 +203,8 @@ public class StepParserStepFactoryBeanTests {
fb.setRetryLimit(5);
fb.setSkipLimit(100);
fb.setRetryListeners(new RetryListenerSupport());
- fb.setSkippableExceptionClasses(new ArrayList>());
- fb.setRetryableExceptionClasses(new ArrayList>());
- fb.setFatalExceptionClasses(new ArrayList>());
+ fb.setSkippableExceptionClasses(new HashMap, Boolean>());
+ fb.setRetryableExceptionClasses(new HashMap, Boolean>());
Object step = fb.getObject();
assertTrue(step instanceof TaskletStep);
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java
index af84a9a33..925258561 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java
@@ -21,8 +21,10 @@ import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -83,8 +85,7 @@ public class StepParserTests {
Map beans = ctx.getBeansOfType(StepParserStepFactoryBean.class);
String factoryName = (String) beans.keySet().toArray()[0];
@SuppressWarnings("unchecked")
- StepParserStepFactoryBean factory = (StepParserStepFactoryBean) beans
- .get(factoryName);
+ StepParserStepFactoryBean factory = beans.get(factoryName);
TaskletStep bean = (TaskletStep) factory.getObject();
assertEquals("wrong start-limit:", 25, bean.getStartLimit());
}
@@ -420,11 +421,14 @@ public class StepParserTests {
public void testStepWithListsMerge() throws Exception {
ApplicationContext ctx = stepParserParentAttributeTestsCtx;
- List> skippable = Arrays.asList(SkippableRuntimeException.class,
- SkippableException.class);
- Collection> fatal = Arrays.asList(FatalRuntimeException.class, FatalException.class);
- Collection> retryable = Arrays.asList(DeadlockLoserDataAccessException.class,
- FatalException.class);
+ Map, Boolean> skippable = new HashMap, Boolean>();
+ skippable.put(SkippableRuntimeException.class, true);
+ skippable.put(SkippableException.class, true);
+ skippable.put(FatalRuntimeException.class, false);
+ skippable.put(FatalException.class, false);
+ Map, Boolean> retryable = new HashMap, Boolean>();
+ retryable.put(DeadlockLoserDataAccessException.class, true);
+ retryable.put(FatalException.class, true);
List> streams = Arrays.asList(CompositeItemStream.class, TestReader.class);
List> retryListeners = Arrays.asList(RetryListenerSupport.class,
DummyRetryListener.class);
@@ -435,17 +439,15 @@ public class StepParserTests {
StepParserStepFactoryBean, ?> fb = (StepParserStepFactoryBean, ?>) ctx.getBean("&stepWithListsMerge");
- Collection> skippableFound = getExceptionList(fb, "skippableExceptionClasses");
- Collection> fatalFound = getExceptionList(fb, "fatalExceptionClasses");
- Collection> retryableFound = getExceptionList(fb, "retryableExceptionClasses");
+ Map, Boolean> skippableFound = getExceptionMap(fb, "skippableExceptionClasses");
+ Map, Boolean> retryableFound = getExceptionMap(fb, "retryableExceptionClasses");
ItemStream[] streamsFound = (ItemStream[]) ReflectionTestUtils.getField(fb, "streams");
RetryListener[] retryListenersFound = (RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners");
StepListener[] stepListenersFound = (StepListener[]) ReflectionTestUtils.getField(fb, "listeners");
Collection> noRollbackFound = getExceptionList(fb, "noRollbackExceptionClasses");
- assertSameCollections(skippable, skippableFound);
- assertSameCollections(fatal, fatalFound);
- assertSameCollections(retryable, retryableFound);
+ assertSameMaps(skippable, skippableFound);
+ assertSameMaps(retryable, retryableFound);
assertSameCollections(streams, toClassCollection(streamsFound));
assertSameCollections(retryListeners, toClassCollection(retryListenersFound));
assertSameCollections(stepListeners, toClassCollection(stepListenersFound));
@@ -457,9 +459,11 @@ public class StepParserTests {
public void testStepWithListsNoMerge() throws Exception {
ApplicationContext ctx = stepParserParentAttributeTestsCtx;
- List> skippable = Arrays.asList(SkippableException.class);
- List> fatal = Arrays.asList(FatalException.class);
- List> retryable = Arrays.asList(FatalException.class);
+ Map, Boolean> skippable = new HashMap, Boolean>();
+ skippable.put(SkippableException.class, true);
+ skippable.put(FatalException.class, false);
+ Map, Boolean> retryable = new HashMap, Boolean>();
+ retryable.put(FatalException.class, true);
List> streams = Arrays.asList(CompositeItemStream.class);
List> retryListeners = Arrays.asList(DummyRetryListener.class);
List> stepListeners = Arrays.asList(CompositeStepExecutionListener.class);
@@ -467,17 +471,15 @@ public class StepParserTests {
StepParserStepFactoryBean, ?> fb = (StepParserStepFactoryBean, ?>) ctx.getBean("&stepWithListsNoMerge");
- Collection> skippableFound = getExceptionList(fb, "skippableExceptionClasses");
- Collection> fatalFound = getExceptionList(fb, "fatalExceptionClasses");
- Collection> retryableFound = getExceptionList(fb, "retryableExceptionClasses");
+ Map, Boolean> skippableFound = getExceptionMap(fb, "skippableExceptionClasses");
+ Map, Boolean> retryableFound = getExceptionMap(fb, "retryableExceptionClasses");
ItemStream[] streamsFound = (ItemStream[]) ReflectionTestUtils.getField(fb, "streams");
RetryListener[] retryListenersFound = (RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners");
StepListener[] stepListenersFound = (StepListener[]) ReflectionTestUtils.getField(fb, "listeners");
Collection> noRollbackFound = getExceptionList(fb, "noRollbackExceptionClasses");
- assertSameCollections(skippable, skippableFound);
- assertSameCollections(fatal, fatalFound);
- assertSameCollections(retryable, retryableFound);
+ assertSameMaps(skippable, skippableFound);
+ assertSameMaps(retryable, retryableFound);
assertSameCollections(streams, toClassCollection(streamsFound));
assertSameCollections(retryListeners, toClassCollection(retryListenersFound));
assertSameCollections(stepListeners, toClassCollection(stepListenersFound));
@@ -491,15 +493,11 @@ public class StepParserTests {
StepParserStepFactoryBean, ?> fb = (StepParserStepFactoryBean, ?>) ctx
.getBean("&stepWithListsOverrideWithEmpty");
- assertEquals(0, getExceptionList(fb, "skippableExceptionClasses").size());
- assertEquals(0, getExceptionList(fb, "fatalExceptionClasses").size());
- assertEquals(0, getExceptionList(fb, "retryableExceptionClasses").size());
- // TODO BATCH-1357:
- // assertEquals(0, ((ItemStream[]) ReflectionTestUtils.getField(fb, "streams")).length);
- // TODO BATCH-1357:
- // assertEquals(0, ((RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners")).length);
- // TODO BATCH-1357:
- // assertEquals(0, ((StepListener[]) ReflectionTestUtils.getField(fb, "listeners")).length);
+ assertEquals(0, getExceptionMap(fb, "skippableExceptionClasses").size());
+ assertEquals(0, getExceptionMap(fb, "retryableExceptionClasses").size());
+ assertEquals(0, ((ItemStream[]) ReflectionTestUtils.getField(fb, "streams")).length);
+ assertEquals(0, ((RetryListener[]) ReflectionTestUtils.getField(fb, "retryListeners")).length);
+ assertEquals(0, ((StepListener[]) ReflectionTestUtils.getField(fb, "listeners")).length);
assertEquals(0, getExceptionList(fb, "noRollbackExceptionClasses").size());
}
@@ -509,11 +507,25 @@ public class StepParserTests {
return (Collection>) ReflectionTestUtils.getField(fb, propertyName);
}
+ @SuppressWarnings("unchecked")
+ private Map, Boolean> getExceptionMap(StepParserStepFactoryBean, ?> fb,
+ String propertyName) {
+ return (Map, Boolean>) ReflectionTestUtils.getField(fb, propertyName);
+ }
+
private void assertSameCollections(Collection expected, Collection actual) {
assertEquals(expected.size(), actual.size());
assertTrue(expected.containsAll(actual));
}
+ private void assertSameMaps(Map expected, Map actual) {
+ assertEquals(expected.size(), actual.size());
+ for (Entry e : expected.entrySet()) {
+ assertTrue(actual.containsKey(e.getKey()));
+ assertEquals(e.getValue(), actual.get(e.getKey()));
+ }
+ }
+
private Collection> toClassCollection(T[] in) throws Exception {
return toClassCollection(Arrays.asList(in));
}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java
index ed3b044be..0a2880fab 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/converter/DefaultJobParametersConverterTests.java
@@ -143,7 +143,7 @@ public class DefaultJobParametersConverterTests extends TestCase {
JobParameters props = factory.getJobParameters(StringUtils.splitArrayElementsIntoProperties(args, "="));
assertNotNull(props);
- assertEquals((double) 1.0, props.getDouble("value"), Double.MIN_VALUE);
+ assertEquals(1.0, props.getDouble("value"), Double.MIN_VALUE);
}
public void testGetProperties() throws Exception {
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java
index eaea2ec25..2e209442e 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java
@@ -467,7 +467,7 @@ public class SimpleJobTests {
private void checkRepository(BatchStatus status, ExitStatus exitStatus) {
assertEquals(jobInstance, jobInstanceDao.getJobInstance(job.getName(), jobParameters));
// because map dao stores in memory, it can be checked directly
- JobExecution jobExecution = (JobExecution) jobExecutionDao.findJobExecutions(jobInstance).get(0);
+ JobExecution jobExecution = jobExecutionDao.findJobExecutions(jobInstance).get(0);
assertEquals(jobInstance.getId(), jobExecution.getJobId());
assertEquals(status, jobExecution.getStatus());
if (exitStatus != null) {
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/flow/FlowJobTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/flow/FlowJobTests.java
index e815b136d..17e7a2f89 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/flow/FlowJobTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/flow/FlowJobTests.java
@@ -548,7 +548,7 @@ public class FlowJobTests {
private void checkRepository(BatchStatus status, ExitStatus exitStatus) {
// because map dao stores in memory, it can be checked directly
JobInstance jobInstance = jobExecution.getJobInstance();
- JobExecution other = (JobExecution) jobExecutionDao.findJobExecutions(jobInstance).get(0);
+ JobExecution other = jobExecutionDao.findJobExecutions(jobInstance).get(0);
assertEquals(jobInstance.getId(), other.getJobId());
assertEquals(status, other.getStatus());
if (exitStatus != null) {
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/listener/StepListenerFactoryBeanTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/listener/StepListenerFactoryBeanTests.java
index bdd62bfcf..ec3d09d84 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/listener/StepListenerFactoryBeanTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/listener/StepListenerFactoryBeanTests.java
@@ -272,8 +272,7 @@ public class StepListenerFactoryBeanTests {
public void testNonListener() throws Exception {
Object delegate = new Object();
factoryBean.setDelegate(delegate);
- StepListener listener = (StepListener) factoryBean.getObject();
- assertTrue(listener instanceof StepListener);
+ assertTrue(factoryBean.getObject() instanceof StepListener);
}
@Test
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/BatchRetryTemplateTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/BatchRetryTemplateTests.java
index 6ecf1b704..8812b6bf9 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/BatchRetryTemplateTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/BatchRetryTemplateTests.java
@@ -6,6 +6,7 @@ import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import org.junit.Test;
@@ -38,7 +39,8 @@ public class BatchRetryTemplateTests {
String result = template.execute(new RetryCallback() {
public String doWithRetry(RetryContext context) throws Exception {
- assertTrue("Wrong context type: " + context.getClass().getSimpleName(), context.getClass().getSimpleName().contains("Batch"));
+ assertTrue("Wrong context type: " + context.getClass().getSimpleName(), context.getClass()
+ .getSimpleName().contains("Batch"));
return "2";
}
}, Arrays. asList(new DefaultRetryState("1")));
@@ -80,7 +82,8 @@ public class BatchRetryTemplateTests {
public void testExhaustedRetry() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
- template.setRetryPolicy(new SimpleRetryPolicy(1));
+ template.setRetryPolicy(new SimpleRetryPolicy(1, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
RetryCallback retryCallback = new RetryCallback() {
public String[] doWithRetry(RetryContext context) throws Exception {
@@ -108,7 +111,8 @@ public class BatchRetryTemplateTests {
public void testExhaustedRetryAfterShuffle() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
- template.setRetryPolicy(new SimpleRetryPolicy(1));
+ template.setRetryPolicy(new SimpleRetryPolicy(1, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
RetryCallback retryCallback = new RetryCallback() {
public String[] doWithRetry(RetryContext context) throws Exception {
@@ -161,7 +165,8 @@ public class BatchRetryTemplateTests {
public void testExhaustedRetryWithRecovery() throws Exception {
BatchRetryTemplate template = new BatchRetryTemplate();
- template.setRetryPolicy(new SimpleRetryPolicy(1));
+ template.setRetryPolicy(new SimpleRetryPolicy(1, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
RetryCallback retryCallback = new RetryCallback() {
public String[] doWithRetry(RetryContext context) throws Exception {
@@ -171,12 +176,12 @@ public class BatchRetryTemplateTests {
return outputs.toArray(new String[0]);
}
};
-
+
RecoveryCallback recoveryCallback = new RecoveryCallback() {
public String[] recover(RetryContext context) throws Exception {
List recovered = new ArrayList();
for (String item : outputs) {
- recovered.add("r:"+item);
+ recovered.add("r:" + item);
}
return recovered.toArray(new String[0]);
}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantExceptionClassesTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantExceptionClassesTests.java
index 71c2ca496..674aba8d0 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantExceptionClassesTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantExceptionClassesTests.java
@@ -36,9 +36,6 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
public class FaultTolerantExceptionClassesTests implements ApplicationContextAware {
- //
- // TODO BATCH-1318: Commented out tests are related to this issue
- //
@Autowired
private JobRepository jobRepository;
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanNonBufferingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanNonBufferingTests.java
index 83b0f80d0..dc75b1570 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanNonBufferingTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanNonBufferingTests.java
@@ -9,8 +9,9 @@ import static org.junit.Assert.assertFalse;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -36,10 +37,6 @@ public class FaultTolerantStepFactoryBeanNonBufferingTests {
private FaultTolerantStepFactoryBean factory = new FaultTolerantStepFactoryBean();
- @SuppressWarnings("unchecked")
- private Collection> skippableExceptions = new HashSet>(Arrays
- .> asList(SkippableException.class, SkippableRuntimeException.class));
-
private List items = Arrays.asList(new String[] { "1", "2", "3", "4", "5" });
private ListItemReader reader = new ListItemReader(TransactionAwareProxyFactory
@@ -61,6 +58,9 @@ public class FaultTolerantStepFactoryBeanNonBufferingTests {
factory.setCommitInterval(2);
factory.setItemReader(reader);
factory.setItemWriter(writer);
+ Map, Boolean> skippableExceptions = new HashMap, Boolean>();
+ skippableExceptions.put(SkippableException.class, true);
+ skippableExceptions.put(SkippableRuntimeException.class, true);
factory.setSkippableExceptionClasses(skippableExceptions);
factory.setSkipLimit(2);
factory.setIsReaderTransactionalQueue(true);
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java
index 5cd964f63..e74165d24 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRetryTests.java
@@ -20,10 +20,11 @@ import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -89,6 +90,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
}
};
+ @SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
@@ -103,17 +105,10 @@ public class FaultTolerantStepFactoryBeanRetryTests {
factory.setItemWriter(writer);
factory.setJobRepository(repository);
factory.setTransactionManager(new ResourcelessTransactionManager());
- factory.setRetryableExceptionClasses(new HashSet>() {
- {
- add(Exception.class);
- }
- });
+ factory.setRetryableExceptionClasses(getExceptionMap(Exception.class));
factory.setCommitInterval(1); // trivial by default
- @SuppressWarnings("unchecked")
- Collection> skippableExceptions = Arrays
- .> asList(Exception.class);
- factory.setSkippableExceptionClasses(skippableExceptions);
+ factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
JobParameters jobParameters = new JobParametersBuilder().addString("statefulTest", "make_this_unique")
.toJobParameters();
@@ -140,6 +135,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
*
* @throws Exception
*/
+ @SuppressWarnings("unchecked")
@Test
public void testSuccessfulRetryWithReadFailure() throws Exception {
ItemReader provider = new ListItemReader(Arrays.asList("a", "b", "c")) {
@@ -155,7 +151,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
};
factory.setItemReader(provider);
factory.setRetryLimit(10);
- factory.setSkippableExceptionClasses(new HashSet>());
+ factory.setSkippableExceptionClasses(getExceptionMap());
Step step = (Step) factory.getObject();
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
@@ -263,6 +259,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
assertEquals(4, stepExecution.getReadCount());
}
+ @SuppressWarnings("unchecked")
@Test
public void testSkipAndRetryWithWriteFailure() throws Exception {
@@ -296,11 +293,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
factory.setItemReader(provider);
factory.setItemWriter(itemWriter);
factory.setRetryLimit(5);
- factory.setRetryableExceptionClasses(new HashSet>() {
- {
- add(RuntimeException.class);
- }
- });
+ factory.setRetryableExceptionClasses(getExceptionMap(RuntimeException.class));
AbstractStep step = (AbstractStep) factory.getObject();
step.setName("mytest");
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
@@ -319,6 +312,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
assertEquals("[b, d]", recovered.toString());
}
+ @SuppressWarnings("unchecked")
@Test
public void testSkipAndRetryWithWriteFailureAndNonTrivialCommitInterval() throws Exception {
@@ -353,11 +347,7 @@ public class FaultTolerantStepFactoryBeanRetryTests {
factory.setItemReader(provider);
factory.setItemWriter(itemWriter);
factory.setRetryLimit(5);
- factory.setRetryableExceptionClasses(new HashSet>() {
- {
- add(RuntimeException.class);
- }
- });
+ factory.setRetryableExceptionClasses(getExceptionMap(RuntimeException.class));
AbstractStep step = (AbstractStep) factory.getObject();
step.setName("mytest");
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
@@ -425,17 +415,14 @@ public class FaultTolerantStepFactoryBeanRetryTests {
assertEquals(1, stepExecution.getReadCount());
}
+ @SuppressWarnings("unchecked")
@Test
public void testNonSkippableException() throws Exception {
// Very specific skippable exception
- factory.setSkippableExceptionClasses(new HashSet>() {
- {
- add(UnsupportedOperationException.class);
- }
- });
+ factory.setSkippableExceptionClasses(getExceptionMap(UnsupportedOperationException.class));
// ...which is not retryable...
- factory.setRetryableExceptionClasses(new HashSet>());
+ factory.setRetryableExceptionClasses(getExceptionMap());
factory.setSkipLimit(1);
ItemReader provider = new ListItemReader(Arrays.asList("b")) {
@@ -479,7 +466,8 @@ public class FaultTolerantStepFactoryBeanRetryTests {
@Test
public void testRetryPolicy() throws Exception {
- factory.setRetryPolicy(new SimpleRetryPolicy(4));
+ factory.setRetryPolicy(new SimpleRetryPolicy(4, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
factory.setSkipLimit(0);
ItemReader provider = new ListItemReader(Arrays.asList("b")) {
public String read() {
@@ -564,4 +552,12 @@ public class FaultTolerantStepFactoryBeanRetryTests {
// []
assertEquals(0, recovered.size());
}
+
+ private Map, Boolean> getExceptionMap(Class extends Throwable>... args) {
+ Map, Boolean> map = new HashMap, Boolean>();
+ for (Class extends Throwable> arg : args) {
+ map.put(arg, true);
+ }
+ return map;
+ }
}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRollbackTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRollbackTests.java
index 259061f0c..e0fd37e90 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRollbackTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanRollbackTests.java
@@ -6,8 +6,9 @@ import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -55,6 +56,7 @@ public class FaultTolerantStepFactoryBeanRollbackTests {
writer = new SkipWriterStub();
}
+ @SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
factory = new FaultTolerantStepFactoryBean();
@@ -73,7 +75,7 @@ public class FaultTolerantStepFactoryBeanRollbackTests {
factory.setSkipLimit(2);
- factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
+ factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
MapJobRepositoryFactoryBean.clear();
MapJobRepositoryFactoryBean repositoryFactory = new MapJobRepositoryFactoryBean();
@@ -137,6 +139,7 @@ public class FaultTolerantStepFactoryBeanRollbackTests {
/**
* Scenario: Exception in reader that should not cause rollback
*/
+ @SuppressWarnings("unchecked")
@Test
public void testReaderAttributesOverrideSkippableNoRollback() throws Exception {
reader.setFailures("2", "3");
@@ -144,7 +147,7 @@ public class FaultTolerantStepFactoryBeanRollbackTests {
reader.setExceptionType(SkippableException.class);
// No skips by default
- factory.setSkippableExceptionClasses(new HashSet>());
+ factory.setSkippableExceptionClasses(getExceptionMap());
// But this one is explicit in the tx-attrs so it should be skipped
factory.setNoRollbackExceptionClasses(getExceptionList(SkippableException.class));
@@ -416,4 +419,12 @@ public class FaultTolerantStepFactoryBeanRollbackTests {
return Arrays.> asList(arg);
}
+ private Map, Boolean> getExceptionMap(Class extends Throwable>... args) {
+ Map, Boolean> map = new HashMap, Boolean>();
+ for (Class extends Throwable> arg : args) {
+ map.put(arg, true);
+ }
+ return map;
+ }
+
}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanTests.java
index 861aa4f7b..565db22fc 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/FaultTolerantStepFactoryBeanTests.java
@@ -6,9 +6,9 @@ import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@@ -81,6 +81,7 @@ public class FaultTolerantStepFactoryBeanTests {
writer = new SkipWriterStub();
}
+ @SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
factory = new FaultTolerantStepFactoryBean();
@@ -99,10 +100,8 @@ public class FaultTolerantStepFactoryBeanTests {
factory.setSkipLimit(2);
- @SuppressWarnings("unchecked")
- Collection> skippableExceptions = Arrays.> asList(
- SkippableException.class, SkippableRuntimeException.class);
- factory.setSkippableExceptionClasses(skippableExceptions);
+ factory
+ .setSkippableExceptionClasses(getExceptionMap(SkippableException.class, SkippableRuntimeException.class));
MapJobRepositoryFactoryBean.clear();
MapJobRepositoryFactoryBean repositoryFactory = new MapJobRepositoryFactoryBean();
@@ -118,15 +117,16 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* Non-skippable (and non-fatal) exception causes failure immediately.
+ *
* @throws Exception
*/
+ @SuppressWarnings("unchecked")
@Test
public void testNonSkippableExceptionOnRead() throws Exception {
reader.setFailures("2");
// nothing is skippable
- Collection> empty = Collections.emptySet();
- factory.setSkippableExceptionClasses(empty);
+ factory.setSkippableExceptionClasses(getExceptionMap());
Step step = (Step) factory.getObject();
@@ -139,11 +139,11 @@ public class FaultTolerantStepFactoryBeanTests {
.getName()));
}
+ @SuppressWarnings("unchecked")
@Test
public void testNonSkippableException() throws Exception {
// nothing is skippable
- Collection> empty = Collections.emptySet();
- factory.setSkippableExceptionClasses(empty);
+ factory.setSkippableExceptionClasses(getExceptionMap());
factory.setCommitInterval(1);
// no failures on read
@@ -287,7 +287,11 @@ public class FaultTolerantStepFactoryBeanTests {
public void testFatalException() throws Exception {
reader.setFailures("2");
- factory.setFatalExceptionClasses(getExceptionList(FatalRuntimeException.class));
+ Map, Boolean> map = new HashMap, Boolean>();
+ map.put(SkippableException.class, true);
+ map.put(SkippableRuntimeException.class, true);
+ map.put(FatalRuntimeException.class, false);
+ factory.setSkippableExceptionClasses(map);
factory.setItemWriter(new ItemWriter() {
public void write(List extends String> items) {
throw new FatalRuntimeException("Ouch!");
@@ -298,7 +302,7 @@ public class FaultTolerantStepFactoryBeanTests {
step.execute(stepExecution);
String message = stepExecution.getFailureExceptions().get(0).getCause().getMessage();
- assertTrue("Wrong message: " + message, message.equals("Ouch!"));
+ assertEquals("Wrong message: ", "Ouch!", message);
assertStepExecutionsAreEqual(stepExecution, repository.getLastStepExecution(jobExecution.getJobInstance(), step
.getName()));
}
@@ -333,6 +337,7 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* Check items causing errors are skipped as expected.
*/
+ @SuppressWarnings("unchecked")
@Test
public void testSkipOverLimitOnRead() throws Exception {
reader.setItems(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"));
@@ -341,7 +346,7 @@ public class FaultTolerantStepFactoryBeanTests {
writer.setFailures("4");
factory.setSkipLimit(3);
- factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
+ factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
Step step = (Step) factory.getObject();
@@ -366,6 +371,7 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* Check items causing errors are skipped as expected.
*/
+ @SuppressWarnings("unchecked")
@Test
public void testSkipListenerFailsOnRead() throws Exception {
reader.setItems(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"));
@@ -380,7 +386,7 @@ public class FaultTolerantStepFactoryBeanTests {
throw new RuntimeException("oops");
}
} });
- factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
+ factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
Step step = (Step) factory.getObject();
@@ -401,6 +407,7 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* Check items causing errors are skipped as expected.
*/
+ @SuppressWarnings("unchecked")
@Test
public void testSkipListenerFailsOnWrite() throws Exception {
reader.setItems(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6"));
@@ -414,7 +421,7 @@ public class FaultTolerantStepFactoryBeanTests {
throw new RuntimeException("oops");
}
} });
- factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
+ factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
Step step = (Step) factory.getObject();
@@ -485,12 +492,13 @@ public class FaultTolerantStepFactoryBeanTests {
.getName()));
}
+ @SuppressWarnings("unchecked")
@Test
public void testDefaultSkipPolicy() throws Exception {
reader.setItems("a", "b", "c");
reader.setFailures("b");
- factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
+ factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
factory.setSkipLimit(1);
Step step = (Step) factory.getObject();
@@ -506,6 +514,7 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* Check items causing errors are skipped as expected.
*/
+ @SuppressWarnings("unchecked")
@Test
public void testSkipOverLimitOnReadWithAllSkipsAtEnd() throws Exception {
reader.setItems(StringUtils.commaDelimitedListToStringArray("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15"));
@@ -515,7 +524,7 @@ public class FaultTolerantStepFactoryBeanTests {
factory.setCommitInterval(5);
factory.setSkipLimit(3);
- factory.setSkippableExceptionClasses(getExceptionList(Exception.class));
+ factory.setSkippableExceptionClasses(getExceptionMap(Exception.class));
Step step = (Step) factory.getObject();
@@ -826,11 +835,11 @@ public class FaultTolerantStepFactoryBeanTests {
/**
* condition: skippable < fatal; exception is skippable
*
- * expected: false; fatal overrides skippable
+ * expected: true
*/
@Test
public void testSkippableSubset_skippable() throws Exception {
- assertFalse(getSkippableSubsetSkipPolicy().shouldSkip(new WriteFailedException(""), 0));
+ assertTrue(getSkippableSubsetSkipPolicy().shouldSkip(new WriteFailedException(""), 0));
}
/**
@@ -874,34 +883,34 @@ public class FaultTolerantStepFactoryBeanTests {
}
private SkipPolicy getSkippableSubsetSkipPolicy() throws Exception {
- List> skippableExceptions = new ArrayList>();
- skippableExceptions.add(WriteFailedException.class);
- List> fatalExceptions = new ArrayList>();
- fatalExceptions.add(ItemWriterException.class);
+ Map, Boolean> skippableExceptions = new HashMap, Boolean>();
+ skippableExceptions.put(WriteFailedException.class, true);
+ skippableExceptions.put(ItemWriterException.class, false);
factory.setSkippableExceptionClasses(skippableExceptions);
- factory.setFatalExceptionClasses(fatalExceptions);
return getSkipPolicy(factory);
}
private SkipPolicy getFatalSubsetSkipPolicy() throws Exception {
- List> skippableExceptions = new ArrayList>();
- skippableExceptions.add(ItemWriterException.class);
- List> fatalExceptions = new ArrayList>();
- fatalExceptions.add(WriteFailedException.class);
+ Map, Boolean> skippableExceptions = new HashMap, Boolean>();
+ skippableExceptions.put(ItemWriterException.class, true);
+ skippableExceptions.put(WriteFailedException.class, false);
factory.setSkippableExceptionClasses(skippableExceptions);
- factory.setFatalExceptionClasses(fatalExceptions);
return getSkipPolicy(factory);
}
- private SkipPolicy getSkipPolicy(FactoryBean stepFactoryBean) throws Exception {
+ private SkipPolicy getSkipPolicy(FactoryBean factory) throws Exception {
Object step = factory.getObject();
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
Object chunkProvider = ReflectionTestUtils.getField(tasklet, "chunkProvider");
return (SkipPolicy) ReflectionTestUtils.getField(chunkProvider, "skipPolicy");
}
- @SuppressWarnings("unchecked")
- private Collection> getExceptionList(Class extends Throwable> args) {
- return Arrays.> asList(args);
+ private Map, Boolean> getExceptionMap(Class extends Throwable>... args) {
+ Map, Boolean> map = new HashMap, Boolean>();
+ for (Class extends Throwable> arg : args) {
+ map.put(arg, true);
+ }
+ return map;
}
+
}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/skip/LimitCheckingItemSkipPolicyTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/skip/LimitCheckingItemSkipPolicyTests.java
index d86cfc6d4..18fb21450 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/skip/LimitCheckingItemSkipPolicyTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/skip/LimitCheckingItemSkipPolicyTests.java
@@ -20,8 +20,8 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
import org.junit.Before;
import org.junit.Test;
@@ -41,10 +41,9 @@ public class LimitCheckingItemSkipPolicyTests {
@Before
public void setUp() throws Exception {
- List> skippableExceptions = new ArrayList>();
- skippableExceptions.add(FlatFileParseException.class);
- List> fatalExceptions = new ArrayList>();
- failurePolicy = new LimitCheckingItemSkipPolicy(1, skippableExceptions, fatalExceptions);
+ Map, Boolean> skippableExceptions = new HashMap, Boolean>();
+ skippableExceptions.put(FlatFileParseException.class, true);
+ failurePolicy = new LimitCheckingItemSkipPolicy(1, skippableExceptions);
}
@Test
@@ -68,11 +67,10 @@ public class LimitCheckingItemSkipPolicyTests {
}
private LimitCheckingItemSkipPolicy getSkippableSubsetSkipPolicy() {
- List> skippableExceptions = new ArrayList>();
- skippableExceptions.add(WriteFailedException.class);
- List> fatalExceptions = new ArrayList>();
- fatalExceptions.add(ItemWriterException.class);
- return new LimitCheckingItemSkipPolicy(1, skippableExceptions, fatalExceptions);
+ Map, Boolean> skippableExceptions = new HashMap, Boolean>();
+ skippableExceptions.put(WriteFailedException.class, true);
+ skippableExceptions.put(ItemWriterException.class, false);
+ return new LimitCheckingItemSkipPolicy(1, skippableExceptions);
}
/**
@@ -88,11 +86,11 @@ public class LimitCheckingItemSkipPolicyTests {
/**
* condition: skippable < fatal; exception is skippable
*
- * expected: false; fatal overrides skippable
+ * expected: true
*/
@Test
public void testSkippableSubset_skippable() {
- assertFalse(getSkippableSubsetSkipPolicy().shouldSkip(new WriteFailedException(""), 0));
+ assertTrue(getSkippableSubsetSkipPolicy().shouldSkip(new WriteFailedException(""), 0));
}
/**
@@ -106,11 +104,10 @@ public class LimitCheckingItemSkipPolicyTests {
}
private LimitCheckingItemSkipPolicy getFatalSubsetSkipPolicy() {
- List> skippableExceptions = new ArrayList>();
- skippableExceptions.add(ItemWriterException.class);
- List> fatalExceptions = new ArrayList>();
- fatalExceptions.add(WriteFailedException.class);
- return new LimitCheckingItemSkipPolicy(1, skippableExceptions, fatalExceptions);
+ Map, Boolean> skippableExceptions = new HashMap, Boolean>();
+ skippableExceptions.put(WriteFailedException.class, false);
+ skippableExceptions.put(ItemWriterException.class, true);
+ return new LimitCheckingItemSkipPolicy(1, skippableExceptions);
}
/**
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/ChunkElementParentAttributeParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/ChunkElementParentAttributeParserTests-context.xml
index 1d6e2a67d..17979abce 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/ChunkElementParentAttributeParserTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/ChunkElementParentAttributeParserTests-context.xml
@@ -11,19 +11,19 @@
- java.lang.NullPointerException
+
+
-
- org.springframework.dao.CannotAcquireLockException
-
- org.springframework.dao.DeadlockLoserDataAccessException
+
-
+
+
+
@@ -33,19 +33,19 @@
- java.lang.NullPointerException
+
+
-
- org.springframework.dao.CannotAcquireLockException
-
- org.springframework.dao.DeadlockLoserDataAccessException
+
-
+
+
+
@@ -56,16 +56,16 @@
- java.lang.ArithmeticException
+
+
-
- org.springframework.dao.DeadlockLoserDataAccessException
-
-
+
+
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/InlineItemHandlerParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/InlineItemHandlerParserTests-context.xml
new file mode 100644
index 000000000..051395a9d
--- /dev/null
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/InlineItemHandlerParserTests-context.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobExecutionListenerParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobExecutionListenerParserTests-context.xml
index af0da63a7..26f28f78b 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobExecutionListenerParserTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobExecutionListenerParserTests-context.xml
@@ -10,8 +10,12 @@
-
-
+
+
+
+
+
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml
index 6717a607a..79a3dc041 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml
@@ -10,7 +10,9 @@
-
+
+
+
@@ -18,7 +20,9 @@
-
+
+
+
@@ -50,16 +54,22 @@
-
+
+
+
-
+
+
+
-
+
+
+
@@ -68,7 +78,7 @@
-
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepListenerParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepListenerParserTests-context.xml
index 610a073b2..47b6e0c4d 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepListenerParserTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepListenerParserTests-context.xml
@@ -10,7 +10,9 @@
-
+
+
+
@@ -19,20 +21,28 @@
-
+
+
+
-
-
+
+
+
+
+
+
-
+
+
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserBadRetryListenerTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserBadRetryListenerTests-context.xml
index d59f4e76f..400697af3 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserBadRetryListenerTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserBadRetryListenerTests-context.xml
@@ -8,24 +8,25 @@
-
+
+ retry-limit="3" cache-capacity="100" is-reader-transactional-queue="true">
-
+
+
+
- org.springframework.dao.DataIntegrityViolationException,
+
- org.springframework.dao.DataIntegrityViolationException
-
+
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserBadStepListenerTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserBadStepListenerTests-context.xml
index 163ce5466..db5077834 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserBadStepListenerTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserBadStepListenerTests-context.xml
@@ -10,7 +10,9 @@
-
+
+
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml
index 84fdbd538..5df92ccc5 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml
@@ -85,7 +85,9 @@
-
+
+
+
@@ -149,26 +151,28 @@
- org.springframework.batch.core.step.item.SkippableRuntimeException
+
+
-
- org.springframework.batch.core.step.item.FatalRuntimeException
-
- org.springframework.dao.DeadlockLoserDataAccessException
+
-
+
+
+
-
+
+
+
- org.springframework.batch.core.step.item.FatalRuntimeException
+
@@ -177,26 +181,28 @@
- org.springframework.batch.core.step.item.SkippableException
+
+
-
- org.springframework.batch.core.step.item.FatalException
-
- org.springframework.batch.core.step.item.FatalException
+
-
+
+
+
-
+
+
+
- org.springframework.batch.core.step.item.SkippableRuntimeException
+
@@ -205,26 +211,28 @@
- org.springframework.batch.core.step.item.SkippableException
+
+
-
- org.springframework.batch.core.step.item.FatalException
-
- org.springframework.batch.core.step.item.FatalException
+
-
+
+
+
-
+
+
+
- org.springframework.batch.core.step.item.SkippableRuntimeException
+
@@ -233,12 +241,11 @@
-
-
-
+
+
-
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserTaskletAttributesTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserTaskletAttributesTests-context.xml
index 46e3eaea6..c3f90b227 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserTaskletAttributesTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserTaskletAttributesTests-context.xml
@@ -6,29 +6,28 @@
-
+
+ retry-limit="3" cache-capacity="100" is-reader-transactional-queue="true">
-
+
+
+
-
- org.springframework.jdbc.BadSqlGrammarException
-
- org.springframework.dao.DataIntegrityViolationException
+
+
- org.springframework.dao.DeadlockLoserDataAccessException
+
- org.springframework.dao.DataIntegrityViolationException
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepWithBasicProcessTaskJobParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepWithBasicProcessTaskJobParserTests-context.xml
index bc94c3e80..5c10af463 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepWithBasicProcessTaskJobParserTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepWithBasicProcessTaskJobParserTests-context.xml
@@ -16,8 +16,9 @@
-
+
+
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepWithFaultTolerantProcessTaskJobParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepWithFaultTolerantProcessTaskJobParserTests-context.xml
index a6fcf1b43..0d8e382f8 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepWithFaultTolerantProcessTaskJobParserTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepWithFaultTolerantProcessTaskJobParserTests-context.xml
@@ -8,29 +8,35 @@
-
-
+
+
+
-
+
+
+
- org.springframework.dao.DataIntegrityViolationException
+
- org.springframework.dao.DeadlockLoserDataAccessException
+
- org.springframework.dao.DataIntegrityViolationException
+
-
+
+
+
@@ -38,9 +44,9 @@
-
+
-
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests-context.xml
index 9396861bd..ca2e6f35c 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StopCustomStatusJobParserTests-context.xml
@@ -10,8 +10,9 @@
-
+
+
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/step/item/FaultTolerantExceptionClassesTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/step/item/FaultTolerantExceptionClassesTests-context.xml
index 718ac5c2b..f8150c5e4 100644
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/step/item/FaultTolerantExceptionClassesTests-context.xml
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/step/item/FaultTolerantExceptionClassesTests-context.xml
@@ -15,8 +15,8 @@
- org.springframework.batch.core.step.item.SkippableRuntimeException
- org.springframework.batch.core.step.item.SkippableException
+
+
@@ -26,13 +26,11 @@
- org.springframework.batch.core.step.item.SkippableRuntimeException
- org.springframework.batch.core.step.item.SkippableException
+
+
+
+
-
- org.springframework.batch.core.step.item.FatalRuntimeException
- org.springframework.batch.core.step.item.FatalException
-
@@ -41,15 +39,13 @@
- org.springframework.batch.core.step.item.SkippableRuntimeException
- org.springframework.batch.core.step.item.SkippableException
+
+
+
+
-
- org.springframework.batch.core.step.item.FatalRuntimeException
- org.springframework.batch.core.step.item.FatalException
-
- java.lang.Exception
+
@@ -60,11 +56,11 @@
- java.util.FormatterClosedException
+
- java.lang.IllegalStateException
+
@@ -73,11 +69,11 @@
- java.lang.IllegalStateException
+
- java.lang.RuntimeException
+
@@ -86,14 +82,14 @@
- org.springframework.batch.core.step.item.SkippableRuntimeException
- org.springframework.batch.core.step.item.SkippableException
- org.springframework.batch.core.step.item.FatalRuntimeException
- org.springframework.batch.core.step.item.FatalException
+
+
+
+
- org.springframework.batch.core.step.item.FatalRuntimeException
+
@@ -102,17 +98,15 @@
- java.lang.Exception
+
+
+
+
+
-
- org.springframework.batch.core.step.item.SkippableRuntimeException
- org.springframework.batch.core.step.item.SkippableException
- org.springframework.batch.core.step.item.FatalRuntimeException
- org.springframework.batch.core.step.item.FatalException
-
- org.springframework.batch.core.step.item.FatalRuntimeException
+
@@ -120,7 +114,7 @@
- org.springframework.batch.core.step.item.SkippableRuntimeException
+
@@ -156,4 +150,4 @@
-
\ No newline at end of file
+
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/classify/BinaryExceptionClassifier.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/classify/BinaryExceptionClassifier.java
index e43c9b7c9..d206b80ff 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/classify/BinaryExceptionClassifier.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/classify/BinaryExceptionClassifier.java
@@ -34,9 +34,7 @@ import java.util.Map;
public class BinaryExceptionClassifier extends SubclassClassifier {
/**
- * Create a binary exception classifier with the provided default value. All
- * exceptions will classify as this value unless
- * {@link #setTypes(Collection)} is used to narrow the field.
+ * Create a binary exception classifier with the provided default value.
*
* @param defaultValue defaults to false
*/
@@ -44,23 +42,22 @@ public class BinaryExceptionClassifier extends SubclassClassifier> exceptionClasses, boolean value) {
this(!value);
- if (exceptionClasses!=null) setTypes(exceptionClasses);
+ if (exceptionClasses != null) {
+ Map, Boolean> map = new HashMap, Boolean>();
+ for (Class extends Throwable> type : exceptionClasses) {
+ map.put(type, !getDefault());
+ }
+ setTypeMap(map);
+ }
}
/**
@@ -72,17 +69,23 @@ public class BinaryExceptionClassifier extends SubclassClassifier> types) {
- Map, Boolean> map = new HashMap, Boolean>();
- for (Class extends Throwable> type : types) {
- map.put(type, !getDefault());
- }
- setTypeMap(map);
+ public BinaryExceptionClassifier(Map, Boolean> typeMap) {
+ this(typeMap, false);
+ }
+
+ /**
+ * Create a binary exception classifier using the given classification map
+ * and a default classification of false.
+ *
+ * @param typeMap
+ */
+ public BinaryExceptionClassifier(Map, Boolean> typeMap, boolean defaultValue) {
+ super(typeMap, defaultValue);
}
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemProcessor.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemProcessor.java
index 1e6b88c9e..921bad3fc 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemProcessor.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemProcessor.java
@@ -25,40 +25,38 @@ import org.springframework.util.Assert;
/**
* Composite {@link ItemProcessor} that passes the item through a sequence of
* injected ItemTransformers (return value of previous
- * transformation is the entry value of the next).
+ * transformation is the entry value of the next).
+ *
*
- * Note the user is responsible for injecting a chain of {@link ItemProcessor}
- * s that conforms to declared input and output types.
+ * Note the user is responsible for injecting a chain of {@link ItemProcessor} s
+ * that conforms to declared input and output types.
*
* @author Robert Kasanicky
*/
-@SuppressWarnings("unchecked")
public class CompositeItemProcessor implements ItemProcessor, InitializingBean {
- private List itemProcessors;
+ private List> delegates;
+ @SuppressWarnings("unchecked")
public O process(I item) throws Exception {
Object result = item;
-
- for(ItemProcessor transformer: itemProcessors){
- if(result == null){
+
+ for (ItemProcessor delegate : delegates) {
+ if (result == null) {
return null;
}
- result = transformer.process(result);
+ result = delegate.process(result);
}
return (O) result;
}
public void afterPropertiesSet() throws Exception {
- Assert.notEmpty(itemProcessors);
+ Assert.notNull(delegates, "The 'delgates' may not be null");
+ Assert.notEmpty(delegates, "The 'delgates' may not be empty");
}
- /**
- * @param itemProcessors will be chained to produce a composite
- * transformation.
- */
- public void setItemProcessors(List itemProcessors) {
- this.itemProcessors = itemProcessors;
+ public void setDelegates(List> delegates) {
+ this.delegates = delegates;
}
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemWriter.java
index b7078b73a..a8bc61fdf 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemWriter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/CompositeItemWriter.java
@@ -16,34 +16,38 @@
package org.springframework.batch.item.support;
-import java.util.Arrays;
import java.util.List;
import org.springframework.batch.item.ItemWriter;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.Assert;
/**
- * Calls a collection of {@link ItemWriter}s in fixed-order sequence.
+ * Calls a collection of {@link ItemWriter}s in fixed-order sequence.
+ *
*
* The implementation is thread-safe if all delegates are thread-safe.
*
* @author Robert Kasanicky
* @author Dave Syer
*/
-public class CompositeItemWriter implements ItemWriter {
+public class CompositeItemWriter implements ItemWriter, InitializingBean {
private List> delegates;
- public void setDelegates(ItemWriter super T>[] delegates) {
- this.delegates = Arrays.asList(delegates);
- }
-
- /**
- * Calls injected ItemProcessors in order.
- */
- public void write(List extends T> item) throws Exception {
+ public void write(List extends T> item) throws Exception {
for (ItemWriter super T> writer : delegates) {
writer.write(item);
}
}
+ public void afterPropertiesSet() throws Exception {
+ Assert.notNull(delegates, "The 'delgates' may not be null");
+ Assert.notEmpty(delegates, "The 'delgates' may not be empty");
+ }
+
+ public void setDelegates(List> delegates) {
+ this.delegates = delegates;
+ }
+
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/policy/SimpleRetryPolicy.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/policy/SimpleRetryPolicy.java
index 7f4c4328a..1a2fe5192 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/policy/SimpleRetryPolicy.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/policy/SimpleRetryPolicy.java
@@ -16,8 +16,7 @@
package org.springframework.batch.retry.policy;
-import java.util.Collection;
-import java.util.HashSet;
+import java.util.Map;
import org.springframework.batch.classify.BinaryExceptionClassifier;
import org.springframework.batch.retry.RetryContext;
@@ -43,44 +42,26 @@ import org.springframework.batch.retry.context.RetryContextSupport;
*/
public class SimpleRetryPolicy implements RetryPolicy {
- /**
- * The default limit to the number of attempts for a new policy.
- */
- public final static int DEFAULT_MAX_ATTEMPTS = 3;
-
private volatile int maxAttempts;
- private BinaryExceptionClassifier retryableClassifier = new BinaryExceptionClassifier();
-
- private BinaryExceptionClassifier fatalClassifier = new BinaryExceptionClassifier();
-
- /**
- * Create a {@link SimpleRetryPolicy} with the default number of retry
- * attempts.
- */
- public SimpleRetryPolicy() {
- this(DEFAULT_MAX_ATTEMPTS);
- }
+ private BinaryExceptionClassifier retryableClassifier = new BinaryExceptionClassifier(false);
/**
* Create a {@link SimpleRetryPolicy} with the specified number of retry
- * attempts, and default exceptions to retry.
+ * attempts.
*
- * @param maxAttempts number of allowed attempts (typically >= 1)
+ * @param maxAttempts
+ * @param retryableExceptions
*/
- public SimpleRetryPolicy(int maxAttempts) {
+ public SimpleRetryPolicy(int maxAttempts, Map, Boolean> retryableExceptions) {
super();
- Collection> classes;
- classes = new HashSet>();
- classes.add(Exception.class);
- setRetryableExceptionClasses(classes);
- classes = new HashSet>();
- setFatalExceptionClasses(classes);
this.maxAttempts = maxAttempts;
+ this.retryableClassifier = new BinaryExceptionClassifier(retryableExceptions);
}
/**
* Setter for retry attempts.
+ *
* @param retryAttempts the number of attempts before a retry becomes
* impossible.
*/
@@ -90,6 +71,7 @@ public class SimpleRetryPolicy implements RetryPolicy {
/**
* Test for retryable operation based on the status.
+ *
* @see org.springframework.batch.retry.RetryPolicy#canRetry(org.springframework.batch.retry.RetryContext)
*
* @return true if the last exception was retryable and the number of
@@ -100,27 +82,6 @@ public class SimpleRetryPolicy implements RetryPolicy {
return (t == null || retryForException(t)) && context.getRetryCount() < maxAttempts;
}
- /**
- * Set the retryable exceptions. Any exception on the list, or subclasses
- * thereof, will be retryable. Others will be re-thrown without retry.
- *
- * @param retryableExceptionClasses defaults to {@link Exception}.
- */
- public final void setRetryableExceptionClasses(Collection> retryableExceptionClasses) {
- retryableClassifier.setTypes(retryableExceptionClasses);
- }
-
- /**
- * Set the fatal exceptions. Any exception on the list, or subclasses
- * thereof, will be re-thrown without retry. This list takes precedence over
- * the retryable list.
- *
- * @param fatalExceptionClasses defaults to {@link Exception}.
- */
- public final void setFatalExceptionClasses(Collection> fatalExceptionClasses) {
- fatalClassifier.setTypes(fatalExceptionClasses);
- }
-
/**
* @see org.springframework.batch.retry.RetryPolicy#close(RetryContext)
*/
@@ -142,6 +103,7 @@ public class SimpleRetryPolicy implements RetryPolicy {
* Get a status object that can be used to track the current operation
* according to this policy. Has to be aware of the latest exception and the
* number of attempts.
+ *
* @see org.springframework.batch.retry.RetryPolicy#open(RetryContext)
*/
public RetryContext open(RetryContext parent) {
@@ -162,6 +124,6 @@ public class SimpleRetryPolicy implements RetryPolicy {
* retryable.
*/
private boolean retryForException(Throwable ex) {
- return !fatalClassifier.classify(ex) && retryableClassifier.classify(ex);
+ return retryableClassifier.classify(ex);
}
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/RetryTemplate.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/RetryTemplate.java
index a92087651..3b0a12287 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/RetryTemplate.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/RetryTemplate.java
@@ -18,6 +18,7 @@ package org.springframework.batch.retry.support;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
@@ -73,7 +74,8 @@ public class RetryTemplate implements RetryOperations {
private volatile BackOffPolicy backOffPolicy = new NoBackOffPolicy();
- private volatile RetryPolicy retryPolicy = new SimpleRetryPolicy();
+ private volatile RetryPolicy retryPolicy = new SimpleRetryPolicy(3, Collections
+ ., Boolean> singletonMap(Exception.class, true));
private volatile RetryListener[] listeners = new RetryListener[0];
@@ -81,6 +83,7 @@ public class RetryTemplate implements RetryOperations {
/**
* Public setter for the {@link RetryContextCache}.
+ *
* @param retryContextCache the {@link RetryContextCache} to set.
*/
public void setRetryContextCache(RetryContextCache retryContextCache) {
@@ -91,6 +94,7 @@ public class RetryTemplate implements RetryOperations {
* Setter for listeners. The listeners are executed before and after a retry
* block (i.e. before and after all the attempts), and on an error (every
* attempt).
+ *
* @param listeners
* @see RetryListener
*/
@@ -100,6 +104,7 @@ public class RetryTemplate implements RetryOperations {
/**
* Register an additional listener.
+ *
* @param listener
* @see #setListeners(RetryListener[])
*/
@@ -111,6 +116,7 @@ public class RetryTemplate implements RetryOperations {
/**
* Setter for {@link BackOffPolicy}.
+ *
* @param backOffPolicy
*/
public void setBackOffPolicy(BackOffPolicy backOffPolicy) {
@@ -195,7 +201,7 @@ public class RetryTemplate implements RetryOperations {
// Allow the retry policy to initialise itself...
RetryContext context = open(retryPolicy, state);
- logger.debug("RetryContext retrieved: "+context);
+ logger.debug("RetryContext retrieved: " + context);
// Make sure the context is available globally for clients who need
// it...
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/classify/BinaryExceptionClassifierTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/classify/BinaryExceptionClassifierTests.java
index d532b0b4e..570501626 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/classify/BinaryExceptionClassifierTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/classify/BinaryExceptionClassifierTests.java
@@ -16,15 +16,14 @@
package org.springframework.batch.classify;
+import java.util.Collection;
import java.util.Collections;
-import org.springframework.batch.classify.BinaryExceptionClassifier;
-
import junit.framework.TestCase;
public class BinaryExceptionClassifierTests extends TestCase {
- BinaryExceptionClassifier classifier = new BinaryExceptionClassifier();
+ BinaryExceptionClassifier classifier = new BinaryExceptionClassifier(false);
public void testClassifyNullIsDefault() {
assertFalse(classifier.classify(null));
@@ -44,8 +43,9 @@ public class BinaryExceptionClassifierTests extends TestCase {
}
public void testClassifyExactMatch() {
- classifier.setTypes(Collections.> singleton(IllegalStateException.class));
- assertTrue(classifier.classify(new IllegalStateException("Foo")));
+ Collection> set = Collections
+ .> singleton(IllegalStateException.class);
+ assertTrue(new BinaryExceptionClassifier(set).classify(new IllegalStateException("Foo")));
}
public void testTypesProvidedInConstructor() {
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/CompositeItemProcessorTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/CompositeItemProcessorTests.java
index a8f1ac0d7..4ce3556af 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/CompositeItemProcessorTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/CompositeItemProcessorTests.java
@@ -33,7 +33,7 @@ public class CompositeItemProcessorTests {
processor1 = createMock(ItemProcessor.class);
processor2 = createMock(ItemProcessor.class);
- composite.setItemProcessors(new ArrayList() {{
+ composite.setDelegates(new ArrayList>() {{
add(processor1); add(processor2);
}});
@@ -67,12 +67,11 @@ public class CompositeItemProcessorTests {
* The list of transformers must not be null or empty and
* can contain only instances of {@link ItemProcessor}.
*/
- @SuppressWarnings("unchecked")
@Test
public void testAfterPropertiesSet() throws Exception {
// value not set
- composite.setItemProcessors(null);
+ composite.setDelegates(null);
try {
composite.afterPropertiesSet();
fail();
@@ -82,7 +81,7 @@ public class CompositeItemProcessorTests {
}
// empty list
- composite.setItemProcessors(new ArrayList());
+ composite.setDelegates(new ArrayList>());
try {
composite.afterPropertiesSet();
fail();
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/CompositeItemWriterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/CompositeItemWriterTests.java
index db6d874e1..ae3e9d145 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/CompositeItemWriterTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/support/CompositeItemWriterTests.java
@@ -5,6 +5,7 @@ import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -21,37 +22,35 @@ public class CompositeItemWriterTests extends TestCase {
// object under test
private CompositeItemWriter itemProcessor = new CompositeItemWriter();
-
+
/**
- * Regular usage scenario.
- * All injected processors should be called.
+ * Regular usage scenario. All injected processors should be called.
*/
-
+
public void testProcess() throws Exception {
-
+
final int NUMBER_OF_WRITERS = 10;
List data = Collections.singletonList(new Object());
-
- @SuppressWarnings("unchecked")
- ItemWriter[] writers = new ItemWriter[NUMBER_OF_WRITERS];
-
+
+ List> writers = new ArrayList>();
+
for (int i = 0; i < NUMBER_OF_WRITERS; i++) {
@SuppressWarnings("unchecked")
ItemWriter writer = createStrictMock(ItemWriter.class);
-
+
writer.write(data);
expectLastCall().once();
replay(writer);
-
- writers[i] = writer;
+
+ writers.add(writer);
}
-
+
itemProcessor.setDelegates(writers);
itemProcessor.write(data);
-
+
for (ItemWriter writer : writers) {
verify(writer);
}
}
-
+
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/interceptor/RetryOperationsInterceptorTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/interceptor/RetryOperationsInterceptorTests.java
index 737d9418c..8bb3bd300 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/interceptor/RetryOperationsInterceptorTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/interceptor/RetryOperationsInterceptorTests.java
@@ -19,6 +19,7 @@ package org.springframework.batch.retry.interceptor;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
@@ -28,7 +29,6 @@ import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.target.SingletonTargetSource;
-import org.springframework.batch.retry.interceptor.RetryOperationsInterceptor;
import org.springframework.batch.retry.policy.NeverRetryPolicy;
import org.springframework.batch.retry.policy.SimpleRetryPolicy;
import org.springframework.batch.retry.support.RetryTemplate;
@@ -44,7 +44,7 @@ public class RetryOperationsInterceptorTests extends TestCase {
private Service service;
private ServiceImpl target;
-
+
private static int count;
private static int transactionCount;
@@ -53,8 +53,7 @@ public class RetryOperationsInterceptorTests extends TestCase {
super.setUp();
interceptor = new RetryOperationsInterceptor();
target = new ServiceImpl();
- service = (Service) ProxyFactory.getProxy(Service.class,
- new SingletonTargetSource(target));
+ service = (Service) ProxyFactory.getProxy(Service.class, new SingletonTargetSource(target));
count = 0;
transactionCount = 0;
}
@@ -75,7 +74,8 @@ public class RetryOperationsInterceptorTests extends TestCase {
}
});
RetryTemplate template = new RetryTemplate();
- template.setRetryPolicy(new SimpleRetryPolicy(2));
+ template.setRetryPolicy(new SimpleRetryPolicy(2, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
interceptor.setRetryOperations(template);
service.service();
assertEquals(2, count);
@@ -90,20 +90,20 @@ public class RetryOperationsInterceptorTests extends TestCase {
try {
service.service();
fail("Expected Exception.");
- } catch (Exception e) {
+ }
+ catch (Exception e) {
assertTrue(e.getMessage().startsWith("Not enough calls"));
}
assertEquals(1, count);
}
public void testOutsideTransaction() throws Exception {
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
- ClassUtils.addResourcePathToPackagePath(getClass(),
- "retry-transaction-test.xml"));
+ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(ClassUtils
+ .addResourcePathToPackagePath(getClass(), "retry-transaction-test.xml"));
Object object = context.getBean("bean");
assertNotNull(object);
assertTrue(object instanceof Service);
- Service bean = (Service) object ;
+ Service bean = (Service) object;
bean.doTansactional();
assertEquals(2, count);
// Expect 2 separate transactions...
@@ -134,20 +134,21 @@ public class RetryOperationsInterceptorTests extends TestCase {
}
});
fail("IllegalStateException expected");
- } catch (IllegalStateException e) {
- assertTrue("Exception message should contain MethodInvocation: "
- + e.getMessage(), e.getMessage()
- .indexOf("MethodInvocation") >= 0);
+ }
+ catch (IllegalStateException e) {
+ assertTrue("Exception message should contain MethodInvocation: " + e.getMessage(), e.getMessage().indexOf(
+ "MethodInvocation") >= 0);
}
}
public static interface Service {
void service() throws Exception;
+
void doTansactional() throws Exception;
}
public static class ServiceImpl implements Service {
-
+
private boolean enteredTransaction = false;
public void service() throws Exception {
@@ -156,6 +157,7 @@ public class RetryOperationsInterceptorTests extends TestCase {
throw new Exception("Not enough calls: " + count);
}
}
+
public void doTansactional() throws Exception {
if (TransactionSynchronizationManager.isActualTransactionActive() && !enteredTransaction) {
transactionCount++;
@@ -164,10 +166,10 @@ public class RetryOperationsInterceptorTests extends TestCase {
enteredTransaction = false;
}
});
- enteredTransaction = true;
+ enteredTransaction = true;
}
count++;
- if (count==1) {
+ if (count == 1) {
throw new RuntimeException("Rollback please");
}
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/interceptor/StatefulRetryOperationsInterceptorTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/interceptor/StatefulRetryOperationsInterceptorTests.java
index ee4a9dd6f..714aaead0 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/interceptor/StatefulRetryOperationsInterceptorTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/interceptor/StatefulRetryOperationsInterceptorTests.java
@@ -108,7 +108,8 @@ public class StatefulRetryOperationsInterceptorTests extends TestCase {
}
});
interceptor.setRetryOperations(retryTemplate);
- retryTemplate.setRetryPolicy(new SimpleRetryPolicy(2));
+ retryTemplate.setRetryPolicy(new SimpleRetryPolicy(2, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
try {
service.service("foo");
fail("Expected Exception.");
@@ -126,7 +127,8 @@ public class StatefulRetryOperationsInterceptorTests extends TestCase {
public void testTransformerWithSuccessfulRetry() throws Exception {
((Advised) transformer).addAdvice(interceptor);
interceptor.setRetryOperations(retryTemplate);
- retryTemplate.setRetryPolicy(new SimpleRetryPolicy(2));
+ retryTemplate.setRetryPolicy(new SimpleRetryPolicy(2, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
try {
transformer.transform("foo");
fail("Expected Exception.");
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/FatalExceptionRetryPolicyTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/FatalExceptionRetryPolicyTests.java
index 56caae4d6..6650f7d1a 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/FatalExceptionRetryPolicyTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/FatalExceptionRetryPolicyTests.java
@@ -16,8 +16,8 @@
package org.springframework.batch.retry.policy;
-import java.util.Arrays;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
import junit.framework.TestCase;
@@ -34,15 +34,15 @@ public class FatalExceptionRetryPolicyTests extends TestCase {
callback.setExceptionToThrow(new IllegalArgumentException());
RetryTemplate retryTemplate = new RetryTemplate();
- // Allow multiple attempts in general...
- SimpleRetryPolicy policy = new SimpleRetryPolicy(3);
- retryTemplate.setRetryPolicy(policy);
- // ...but make sure certain exceptions are fatal
- @SuppressWarnings("unchecked")
- List> list = Arrays.> asList(IllegalArgumentException.class,
- IllegalStateException.class);
- policy.setFatalExceptionClasses(list);
+ // Make sure certain exceptions are fatal...
+ Map, Boolean> map = new HashMap, Boolean>();
+ map.put(IllegalArgumentException.class, false);
+ map.put(IllegalStateException.class, false);
+
+ // ... and allow multiple attempts
+ SimpleRetryPolicy policy = new SimpleRetryPolicy(3, map);
+ retryTemplate.setRetryPolicy(policy);
RecoveryCallback recoveryCallback = new RecoveryCallback() {
public String recover(RetryContext context) throws Exception {
return "bar";
@@ -67,13 +67,14 @@ public class FatalExceptionRetryPolicyTests extends TestCase {
callback.setExceptionToThrow(new IllegalArgumentException());
RetryTemplate retryTemplate = new RetryTemplate();
- SimpleRetryPolicy policy = new SimpleRetryPolicy(3);
+
+ Map, Boolean> map = new HashMap, Boolean>();
+ map.put(IllegalArgumentException.class, false);
+ map.put(IllegalStateException.class, false);
+
+ SimpleRetryPolicy policy = new SimpleRetryPolicy(3, map);
retryTemplate.setRetryPolicy(policy);
- @SuppressWarnings("unchecked")
- List> list = Arrays.> asList(
- IllegalArgumentException.class, IllegalStateException.class);
- policy.setFatalExceptionClasses(list);
RecoveryCallback recoveryCallback = new RecoveryCallback() {
public String recover(RetryContext context) throws Exception {
return "bar";
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/SimpleRetryPolicyTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/SimpleRetryPolicyTests.java
index df5ccf0d2..4ecdf82e4 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/SimpleRetryPolicyTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/SimpleRetryPolicyTests.java
@@ -16,11 +16,16 @@
package org.springframework.batch.retry.policy;
-import static org.junit.Assert.*;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import org.junit.Test;
import org.springframework.batch.retry.RetryContext;
@@ -29,7 +34,8 @@ public class SimpleRetryPolicyTests {
@Test
public void testCanRetryIfNoException() throws Exception {
- SimpleRetryPolicy policy = new SimpleRetryPolicy();
+ SimpleRetryPolicy policy = new SimpleRetryPolicy(3, Collections
+ ., Boolean> singletonMap(Exception.class, true));
RetryContext context = policy.open(null);
assertTrue(policy.canRetry(context));
}
@@ -37,12 +43,10 @@ public class SimpleRetryPolicyTests {
@Test
public void testEmptyExceptionsNeverRetry() throws Exception {
- SimpleRetryPolicy policy = new SimpleRetryPolicy();
- RetryContext context = policy.open(null);
-
// We can't retry any exceptions...
- Collection> empty = Collections.emptySet();
- policy.setRetryableExceptionClasses(empty);
+ SimpleRetryPolicy policy = new SimpleRetryPolicy(3, Collections
+ ., Boolean> emptyMap());
+ RetryContext context = policy.open(null);
// ...so we can't retry this one...
policy.registerThrowable(context, new IllegalStateException());
@@ -51,7 +55,8 @@ public class SimpleRetryPolicyTests {
@Test
public void testRetryLimitInitialState() throws Exception {
- SimpleRetryPolicy policy = new SimpleRetryPolicy();
+ SimpleRetryPolicy policy = new SimpleRetryPolicy(3, Collections
+ ., Boolean> singletonMap(Exception.class, true));
RetryContext context = policy.open(null);
assertTrue(policy.canRetry(context));
policy.setMaxAttempts(0);
@@ -61,7 +66,8 @@ public class SimpleRetryPolicyTests {
@Test
public void testRetryLimitSubsequentState() throws Exception {
- SimpleRetryPolicy policy = new SimpleRetryPolicy();
+ SimpleRetryPolicy policy = new SimpleRetryPolicy(3, Collections
+ ., Boolean> singletonMap(Exception.class, true));
RetryContext context = policy.open(null);
policy.setMaxAttempts(2);
assertTrue(policy.canRetry(context));
@@ -73,7 +79,8 @@ public class SimpleRetryPolicyTests {
@Test
public void testRetryCount() throws Exception {
- SimpleRetryPolicy policy = new SimpleRetryPolicy();
+ SimpleRetryPolicy policy = new SimpleRetryPolicy(3, Collections
+ ., Boolean> singletonMap(Exception.class, true));
RetryContext context = policy.open(null);
assertNotNull(context);
policy.registerThrowable(context, null);
@@ -85,28 +92,20 @@ public class SimpleRetryPolicyTests {
@Test
public void testFatalOverridesRetryable() throws Exception {
- SimpleRetryPolicy policy = new SimpleRetryPolicy();
- policy.setFatalExceptionClasses(getClasses(Exception.class));
- policy.setRetryableExceptionClasses(getClasses(RuntimeException.class));
+ Map, Boolean> map = new HashMap, Boolean>();
+ map.put(Exception.class, false);
+ map.put(RuntimeException.class, true);
+ SimpleRetryPolicy policy = new SimpleRetryPolicy(3, map);
RetryContext context = policy.open(null);
assertNotNull(context);
policy.registerThrowable(context, new RuntimeException("foo"));
- assertFalse(policy.canRetry(context));
- }
-
- /**
- * @param cls
- * @return
- */
- private Collection> getClasses(Class extends Throwable> cls) {
- Collection> classes = new HashSet>();
- classes.add(cls);
- return classes;
+ assertTrue(policy.canRetry(context));
}
@Test
public void testParent() throws Exception {
- SimpleRetryPolicy policy = new SimpleRetryPolicy();
+ SimpleRetryPolicy policy = new SimpleRetryPolicy(3, Collections
+ ., Boolean> singletonMap(Exception.class, true));
RetryContext context = policy.open(null);
RetryContext child = policy.open(context);
assertNotSame(child, context);
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/StatefulRetryIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/StatefulRetryIntegrationTests.java
index 435811d8c..995437d48 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/StatefulRetryIntegrationTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/StatefulRetryIntegrationTests.java
@@ -22,6 +22,8 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.util.Collections;
+
import org.junit.Test;
import org.springframework.batch.retry.ExhaustedRetryException;
import org.springframework.batch.retry.RetryState;
@@ -45,7 +47,8 @@ public class StatefulRetryIntegrationTests {
RetryTemplate retryTemplate = new RetryTemplate();
MapRetryContextCache cache = new MapRetryContextCache();
retryTemplate.setRetryContextCache(cache);
- retryTemplate.setRetryPolicy(new SimpleRetryPolicy(1));
+ retryTemplate.setRetryPolicy(new SimpleRetryPolicy(1, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
assertFalse(cache.containsKey("foo"));
@@ -86,7 +89,8 @@ public class StatefulRetryIntegrationTests {
RetryTemplate retryTemplate = new RetryTemplate();
MapRetryContextCache cache = new MapRetryContextCache();
retryTemplate.setRetryContextCache(cache);
- retryTemplate.setRetryPolicy(new SimpleRetryPolicy(2));
+ retryTemplate.setRetryPolicy(new SimpleRetryPolicy(2, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
assertFalse(cache.containsKey("foo"));
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/RetryTemplateTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/RetryTemplateTests.java
index 2a44861f4..30db12318 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/RetryTemplateTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/RetryTemplateTests.java
@@ -55,7 +55,8 @@ public class RetryTemplateTests {
MockRetryCallback callback = new MockRetryCallback();
callback.setAttemptsBeforeSuccess(x);
RetryTemplate retryTemplate = new RetryTemplate();
- retryTemplate.setRetryPolicy(new SimpleRetryPolicy(x));
+ retryTemplate.setRetryPolicy(new SimpleRetryPolicy(x, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
retryTemplate.execute(callback);
assertEquals(x, callback.attempts);
}
@@ -66,7 +67,8 @@ public class RetryTemplateTests {
MockRetryCallback callback = new MockRetryCallback();
callback.setAttemptsBeforeSuccess(3);
RetryTemplate retryTemplate = new RetryTemplate();
- retryTemplate.setRetryPolicy(new SimpleRetryPolicy(2));
+ retryTemplate.setRetryPolicy(new SimpleRetryPolicy(2, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
final Object value = new Object();
Object result = retryTemplate.execute(callback, new RecoveryCallback() {
public Object recover(RetryContext context) throws Exception {
@@ -94,7 +96,8 @@ public class RetryTemplateTests {
callback.setAttemptsBeforeSuccess(Integer.MAX_VALUE);
RetryTemplate retryTemplate = new RetryTemplate();
int retryAttempts = 2;
- retryTemplate.setRetryPolicy(new SimpleRetryPolicy(retryAttempts));
+ retryTemplate.setRetryPolicy(new SimpleRetryPolicy(retryAttempts, Collections
+ ., Boolean> singletonMap(Exception.class, true)));
try {
retryTemplate.execute(callback);
fail("Expected IllegalArgumentException");
@@ -115,7 +118,8 @@ public class RetryTemplateTests {
callback.setExceptionToThrow(new IllegalArgumentException());
RetryTemplate retryTemplate = new RetryTemplate();
- retryTemplate.setRetryPolicy(new SimpleRetryPolicy(attempts));
+ retryTemplate.setRetryPolicy(new SimpleRetryPolicy(attempts, Collections
+ .