diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/listener/JobListenerFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/listener/JobListenerFactoryBean.java
index e2bdbfd4b..acd827933 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/listener/JobListenerFactoryBean.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/listener/JobListenerFactoryBean.java
@@ -15,8 +15,8 @@
*/
package org.springframework.batch.core.listener;
-import static org.springframework.batch.core.configuration.util.MethodInvokerUtils.getMethodInvokerByAnnotation;
-import static org.springframework.batch.core.configuration.util.MethodInvokerUtils.getMethodInvokerForInterface;
+import static org.springframework.batch.support.MethodInvokerUtils.getMethodInvokerByAnnotation;
+import static org.springframework.batch.support.MethodInvokerUtils.getMethodInvokerForInterface;
import java.util.HashMap;
import java.util.HashSet;
@@ -28,8 +28,8 @@ import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
-import org.springframework.batch.core.configuration.util.MethodInvoker;
-import org.springframework.batch.core.configuration.util.MethodInvokerUtils;
+import org.springframework.batch.support.MethodInvoker;
+import org.springframework.batch.support.MethodInvokerUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/listener/MethodInvokerMethodInterceptor.java b/spring-batch-core/src/main/java/org/springframework/batch/core/listener/MethodInvokerMethodInterceptor.java
index 08c20ce20..8ed87fd6f 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/listener/MethodInvokerMethodInterceptor.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/listener/MethodInvokerMethodInterceptor.java
@@ -22,7 +22,7 @@ import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecutionListener;
-import org.springframework.batch.core.configuration.util.MethodInvoker;
+import org.springframework.batch.support.MethodInvoker;
/**
* {@link MethodInterceptor} that, given a map of method names and
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/listener/StepListenerFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/listener/StepListenerFactoryBean.java
index 9d4faa78e..243030c45 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/listener/StepListenerFactoryBean.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/listener/StepListenerFactoryBean.java
@@ -15,8 +15,8 @@
*/
package org.springframework.batch.core.listener;
-import static org.springframework.batch.core.configuration.util.MethodInvokerUtils.getMethodInvokerByAnnotation;
-import static org.springframework.batch.core.configuration.util.MethodInvokerUtils.getMethodInvokerForInterface;
+import static org.springframework.batch.support.MethodInvokerUtils.getMethodInvokerByAnnotation;
+import static org.springframework.batch.support.MethodInvokerUtils.getMethodInvokerForInterface;
import java.util.HashMap;
import java.util.HashSet;
@@ -27,8 +27,8 @@ import java.util.Map.Entry;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.batch.core.StepListener;
-import org.springframework.batch.core.configuration.util.MethodInvoker;
-import org.springframework.batch.core.configuration.util.MethodInvokerUtils;
+import org.springframework.batch.support.MethodInvoker;
+import org.springframework.batch.support.MethodInvokerUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java
index a4c4526af..ced7517bf 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcStepExecutionDao.java
@@ -136,7 +136,7 @@ public class JdbcStepExecutionDao extends AbstractJdbcBatchMetadataDao implement
* Validate StepExecution. At a minimum, JobId, StartTime, and Status cannot
* be null. EndTime can be null for an unfinished job.
*
- * @param jobExecution
+ * @param value
* @throws IllegalArgumentException
*/
private void validateStepExecution(StepExecution stepExecution) {
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/AnnotationMethodResolverTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/AnnotationMethodResolverTests.java
index 0b50d9415..b3f036741 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/AnnotationMethodResolverTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/AnnotationMethodResolverTests.java
@@ -26,7 +26,7 @@ import java.lang.annotation.Target;
import java.lang.reflect.Method;
import org.junit.Test;
-import org.springframework.batch.core.configuration.util.AnnotationMethodResolver;
+import org.springframework.batch.support.AnnotationMethodResolver;
/**
* @author Mark Fisher
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/listener/StepListenerMethodInterceptorTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/listener/StepListenerMethodInterceptorTests.java
index 2832de19d..2fa697806 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/listener/StepListenerMethodInterceptorTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/listener/StepListenerMethodInterceptorTests.java
@@ -13,9 +13,9 @@ import org.aopalliance.intercept.MethodInvocation;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.ExitStatus;
-import org.springframework.batch.core.configuration.util.MethodInvoker;
-import org.springframework.batch.core.configuration.util.MethodInvokerUtils;
-import org.springframework.batch.core.configuration.util.SimpleMethodInvoker;
+import org.springframework.batch.support.MethodInvoker;
+import org.springframework.batch.support.MethodInvokerUtils;
+import org.springframework.batch.support.SimpleMethodInvoker;
public class StepListenerMethodInterceptorTests {
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/PrefixMatchingCompositeLineMapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/PrefixMatchingCompositeLineMapper.java
index f7dac303d..7ea94b059 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/PrefixMatchingCompositeLineMapper.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/mapping/PrefixMatchingCompositeLineMapper.java
@@ -28,9 +28,9 @@ import org.springframework.util.Assert;
/**
*
* A {@link LineMapper} implementation that stores a mapping of String prefixes
- * to delegate {@link LineTokenizer}s as well as a mapping of String prefixes
- * to delegate {@link FieldSetMapper}s. Each line received will be tokenized
- * and then mapped to a field set.
+ * to delegate {@link LineTokenizer}s as well as a mapping of String prefixes to
+ * delegate {@link FieldSetMapper}s. Each line received will be tokenized and
+ * then mapped to a field set.
*
*
* Both the tokenizing and the mapping work in a similar way. The line will be
@@ -39,7 +39,6 @@ import org.springframework.util.Assert;
* with the most specific, and the first match always succeeds.
*
* @see PrefixMatchingCompositeLineTokenizer
- * @see PatternMatcher#match(String, Map)
*
* @author Dan Garrette
* @since 2.0
@@ -47,27 +46,29 @@ import org.springframework.util.Assert;
public class PrefixMatchingCompositeLineMapper implements LineMapper, InitializingBean {
private PrefixMatchingCompositeLineTokenizer tokenizer = new PrefixMatchingCompositeLineTokenizer();
- private Map> fieldSetMappers = null;
+
+ private PatternMatcher> patternMatcher;
/*
* (non-Javadoc)
*
- * @see org.springframework.batch.item.file.mapping.LineMapper#mapLine(java.lang.String,
- * int)
+ * @see
+ * org.springframework.batch.item.file.mapping.LineMapper#mapLine(java.lang
+ * .String, int)
*/
public T mapLine(String line, int lineNumber) throws Exception {
- return PatternMatcher.match(line, this.fieldSetMappers).mapFieldSet(this.tokenizer.tokenize(line));
+ return patternMatcher.match(line).mapFieldSet(this.tokenizer.tokenize(line));
}
/*
* (non-Javadoc)
*
- * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+ * @see
+ * org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
this.tokenizer.afterPropertiesSet();
- Assert.isTrue(this.fieldSetMappers != null && this.fieldSetMappers.size() > 0,
- "The 'fieldSetMappers' property must be non-empty");
+ Assert.isTrue(this.patternMatcher != null, "The 'fieldSetMappers' property must be non-empty");
}
public void setTokenizers(Map tokenizers) {
@@ -75,13 +76,15 @@ public class PrefixMatchingCompositeLineMapper implements LineMapper, Init
}
public void setFieldSetMappers(Map> fieldSetMappers) {
- this.fieldSetMappers = new LinkedHashMap>();
+ Assert.isTrue(!fieldSetMappers.isEmpty(), "The 'fieldSetMappers' property must be non-empty");
+ LinkedHashMap> map = new LinkedHashMap>();
for (String key : fieldSetMappers.keySet()) {
FieldSetMapper value = fieldSetMappers.get(key);
if (!key.endsWith("*")) {
key = key + "*";
}
- this.fieldSetMappers.put(key, value);
+ map.put(key, value);
}
+ this.patternMatcher = new PatternMatcher>(map);
}
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/PrefixMatchingCompositeLineTokenizer.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/PrefixMatchingCompositeLineTokenizer.java
index 6c2f7d2a8..aa3863b82 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/PrefixMatchingCompositeLineTokenizer.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/transform/PrefixMatchingCompositeLineTokenizer.java
@@ -31,43 +31,45 @@ import org.springframework.util.Assert;
* are sorted starting with the most specific, and the first match always
* succeeds.
*
- * @see PatternMatcher#match(String, Map)
- *
* @author Ben Hale
* @author Dan Garrette
* @author Dave Syer
*/
public class PrefixMatchingCompositeLineTokenizer implements LineTokenizer, InitializingBean {
- private Map tokenizers = null;
+ private PatternMatcher tokenizers = null;
/*
* (non-Javadoc)
*
- * @see org.springframework.batch.item.file.transform.LineTokenizer#tokenize(java.lang.String)
+ * @see
+ * org.springframework.batch.item.file.transform.LineTokenizer#tokenize(
+ * java.lang.String)
*/
public FieldSet tokenize(String line) {
- return PatternMatcher.match(line, this.tokenizers).tokenize(line);
+ return tokenizers.match(line).tokenize(line);
}
/*
* (non-Javadoc)
*
- * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+ * @see
+ * org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
- Assert.isTrue(this.tokenizers != null && this.tokenizers.size() > 0,
- "The 'tokenizers' property must be non-empty");
+ Assert.isTrue(this.tokenizers != null, "The 'tokenizers' property must be non-empty");
}
public void setTokenizers(Map tokenizers) {
- this.tokenizers = new LinkedHashMap();
+ Assert.isTrue(!tokenizers.isEmpty(), "The 'tokenizers' property must be non-empty");
+ LinkedHashMap map = new LinkedHashMap();
for (String key : tokenizers.keySet()) {
LineTokenizer value = tokenizers.get(key);
if (!key.endsWith("*")) {
key = key + "*";
}
- this.tokenizers.put(key, value);
+ map.put(key, value);
}
+ this.tokenizers = new PatternMatcher(map);
}
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/ClassifierCompositeItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/ClassifierCompositeItemWriter.java
new file mode 100644
index 000000000..968b9d1b5
--- /dev/null
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/ClassifierCompositeItemWriter.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.batch.item.support;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.batch.item.ItemWriter;
+import org.springframework.batch.support.Classifier;
+import org.springframework.batch.support.ClassifierSupport;
+
+/**
+ * Calls one of a collection of ItemWriters for each item, based on a router
+ * pattern implemented through the provided {@link Classifier}.
+ *
+ * The implementation is thread-safe if all delegates are thread-safe.
+ *
+ * @author Dave Syer
+ */
+public class ClassifierCompositeItemWriter implements ItemWriter {
+
+ private Classifier> classifier = new ClassifierSupport>(null);
+
+ /**
+ * @param classifier the classifier to set
+ */
+ public void setClassifier(Classifier> classifier) {
+ this.classifier = classifier;
+ }
+
+ /**
+ * Delegates to injected {@link ItemWriter} instances according to their
+ * classification by the {@link Classifier}.
+ */
+ public void write(List extends T> items) throws Exception {
+
+ Map, List> map = new HashMap, List>();
+
+ for (T item : items) {
+ ItemWriter super T> key = classifier.classify(item);
+ if (!map.containsKey(key)) {
+ map.put(key, new ArrayList());
+ }
+ map.get(key).add(item);
+ }
+
+ for (ItemWriter super T> writer : map.keySet()) {
+ writer.write(map.get(writer));
+ }
+
+ }
+
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/AnnotationMethodResolver.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/AnnotationMethodResolver.java
similarity index 98%
rename from spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/AnnotationMethodResolver.java
rename to spring-batch-infrastructure/src/main/java/org/springframework/batch/support/AnnotationMethodResolver.java
index 37dd88a00..ea5ace787 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/AnnotationMethodResolver.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/AnnotationMethodResolver.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.batch.core.configuration.util;
+package org.springframework.batch.support;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/BackToBackPatternClassifier.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/BackToBackPatternClassifier.java
new file mode 100644
index 000000000..5d9793b8d
--- /dev/null
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/BackToBackPatternClassifier.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.support;
+
+import java.util.Map;
+
+/**
+ * A special purpose {@link Classifier} with easy configuration options for
+ * mapping from one arbitrary type of object to another via a pattern matcher.
+ *
+ * @author Dave Syer
+ *
+ */
+public class BackToBackPatternClassifier implements Classifier {
+
+ private Classifier router;
+
+ private Classifier matcher;
+
+ /**
+ * Default constructor, provided as a convenience for people using setter
+ * injection.
+ */
+ public BackToBackPatternClassifier() {
+ }
+
+ /**
+ * Set up a classifier with input to the router and output from the matcher.
+ *
+ * @param router see {@link #setRouterDelegate(Object)}
+ * @param matcher see {@link #setMatcherMap(Map)}
+ */
+ public BackToBackPatternClassifier(Classifier router, Classifier matcher) {
+ super();
+ this.router = router;
+ this.matcher = matcher;
+ }
+
+ /**
+ * A convenience method for creating a pattern matching classifier for the
+ * matcher component.
+ *
+ * @param map maps pattern keys with wildcards to output values
+ */
+ public void setMatcherMap(Map map) {
+ this.matcher = new PatternMatchingClassifier(map);
+ }
+
+ /**
+ * A convenience method of creating a router classifier based on a plain old
+ * Java Object. The object provided must have precisely one public method
+ * that either has the @Classifier annotation or accepts a single argument
+ * and outputs a String. This will be used to create an input classifier for
+ * the router component.
+ *
+ * @param delegate the delegate object used to create a router classifier
+ */
+ public void setRouterDelegate(Object delegate) {
+ this.router = new ClassifierAdapter(delegate);
+ }
+
+ /**
+ * Classify the input and map to a String, then take that and put it into a
+ * pattern matcher to match to an output value.
+ */
+ public T classify(C classifiable) {
+ return matcher.classify(router.classify(classifiable));
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/Classifier.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/Classifier.java
index 4b3ddd1c6..8e9719bea 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/Classifier.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/Classifier.java
@@ -26,8 +26,8 @@ package org.springframework.batch.support;
public interface Classifier {
/**
- * Classify the given object and return an object. The return type depends
- * on the implementation.
+ * Classify the given object and return an object of a different type,
+ * possibly an enumerated type.
*
* @param classifiable the input object. Can be null.
* @return an object. Can be null, but implementations should declare if
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/ClassifierAdapter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/ClassifierAdapter.java
new file mode 100644
index 000000000..796a8452f
--- /dev/null
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/ClassifierAdapter.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.support;
+
+import org.springframework.util.Assert;
+
+/**
+ * Wrapper for an object to adapt it to the {@link Classifier} interface.
+ *
+ * @author Dave Syer
+ *
+ */
+public class ClassifierAdapter implements Classifier {
+
+ private MethodInvoker invoker;
+
+ private Classifier classifier;
+
+ /**
+ * Default constructor for use with setter injection.
+ */
+ public ClassifierAdapter() {
+ super();
+ }
+
+ /**
+ * Create a new {@link Classifier} from the delegate provided. Use the
+ * constructor as an alternative to the {@link #setDelegate(Object)} method.
+ *
+ * @param delegate
+ */
+ public ClassifierAdapter(Object delegate) {
+ setDelegate(delegate);
+ }
+
+ /**
+ * Create a new {@link Classifier} from the delegate provided. Use the
+ * constructor as an alternative to the {@link #setDelegate(Classifier)}
+ * method.
+ *
+ * @param delegate
+ */
+ public ClassifierAdapter(Classifier delegate) {
+ classifier = delegate;
+ }
+
+ public void setDelegate(Classifier delegate) {
+ classifier = delegate;
+ invoker = null;
+ }
+
+ /**
+ * Search for the
+ * {@link org.springframework.batch.support.annotation.Classifier
+ * Classifier} annotation on a method in the supplied delegate and use that
+ * to create a {@link Classifier} from the parameter type to the return
+ * type. If the annotation is not found a unique non-void method with a
+ * single parameter will be used, if it exists. The signature of the method
+ * cannot be checked here, so might be a runtime exception when the method
+ * is invoked if the signature doesn't match the classifier types.
+ *
+ * @param delegate an object with an annotated method
+ */
+ public void setDelegate(Object delegate) {
+ classifier = null;
+ invoker = MethodInvokerUtils.getMethodInvokerByAnnotation(
+ org.springframework.batch.support.annotation.Classifier.class, delegate);
+ if (invoker == null) {
+ invoker = MethodInvokerUtils. getMethodInvokerForSingleArgument(delegate);
+ }
+ Assert.state(invoker != null, "No single argument public method with or without "
+ + "@Classifier was found in delegate of type " + delegate.getClass());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public T classify(C classifiable) {
+ if (classifier != null) {
+ return classifier.classify(classifiable);
+ }
+ return (T) invoker.invokeMethod(classifiable);
+ }
+
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/MethodInvoker.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/MethodInvoker.java
similarity index 93%
rename from spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/MethodInvoker.java
rename to spring-batch-infrastructure/src/main/java/org/springframework/batch/support/MethodInvoker.java
index 0b797095a..46f3992af 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/MethodInvoker.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/MethodInvoker.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.batch.core.configuration.util;
+package org.springframework.batch.support;
/**
* A strategy interface for invoking a method.
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/MethodInvokerUtils.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/MethodInvokerUtils.java
similarity index 58%
rename from spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/MethodInvokerUtils.java
rename to spring-batch-infrastructure/src/main/java/org/springframework/batch/support/MethodInvokerUtils.java
index 33735a812..4b6a5b25b 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/MethodInvokerUtils.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/MethodInvokerUtils.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.batch.core.configuration.util;
+package org.springframework.batch.support;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
@@ -36,82 +36,113 @@ import org.springframework.util.ReflectionUtils;
public class MethodInvokerUtils {
/**
- * Create a {@link MethodInvoker} using the provided method name to search.
+ * Create a {@link MethodInvoker} using the provided method name to search.
*
* @param object to be invoked
* @param methodName of the method to be invoked
- * @param paramsRequired boolean indicating whether the parameters are required, if false, a no args version of the
- * method will be searched for.
+ * @param paramsRequired boolean indicating whether the parameters are
+ * required, if false, a no args version of the method will be searched for.
* @param paramTypes - parameter types of the method to search for.
* @return MethodInvoker if the method is found, null if it is not.
*/
- public static MethodInvoker createMethodInvokerByName(Object object, String methodName, boolean paramsRequired, Class>... paramTypes){
+ public static MethodInvoker createMethodInvokerByName(Object object, String methodName, boolean paramsRequired,
+ Class>... paramTypes) {
Assert.notNull(object, "Object to invoke must not be null");
Method method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName, paramTypes);
- //if no method was found for the given parameters, and the parameters aren't required
- if(method == null && !paramsRequired){
- //try with no params
- method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName, new Class[]{});
+ // if no method was found for the given parameters, and the parameters
+ // aren't required
+ if (method == null && !paramsRequired) {
+ // try with no params
+ method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName, new Class[] {});
}
- if(method == null){
+ if (method == null) {
return null;
}
- else{
+ else {
return new SimpleMethodInvoker(object, method);
}
}
-
+
/**
- * Create a {@link MethodInvoker} using the provided interface, and string methodname from that interface.
+ * Create a {@link MethodInvoker} using the provided interface, and method
+ * name from that interface.
*
- * @param object to be invoked
+ * @param cls the interface to search for the method named
* @param methodName of the method to be invoked
+ * @param object to be invoked
* @param paramTypes - parameter types of the method to search for.
* @return MethodInvoker if the method is found, null if it is not.
*/
- public static MethodInvoker getMethodInvokerForInterface(Class> iFace, String methodName,
- Object object, Class>... paramTypes){
-
- if(iFace.isAssignableFrom(object.getClass())){
+ public static MethodInvoker getMethodInvokerForInterface(Class> cls, String methodName, Object object,
+ Class>... paramTypes) {
+
+ if (cls.isAssignableFrom(object.getClass())) {
return MethodInvokerUtils.createMethodInvokerByName(object, methodName, true, paramTypes);
}
- else{
+ else {
return null;
}
}
-
+
/**
- * Create {@link MethodInvoker} for the method with the provided annotation on the provided object. It
- * should be noted that annotations that cannot be applied to methods (i.e. that aren't annotated with an
- * element type of METHOD) will cause an exception to be thrown.
+ * Create {@link MethodInvoker} for the method with the provided annotation
+ * on the provided object. It should be noted that annotations that cannot
+ * be applied to methods (i.e. that aren't annotated with an element type of
+ * METHOD) will cause an exception to be thrown.
*
* @param annotationType to be searched for
* @param candidate to be invoked
* @return MethodInvoker for the provided annotation, null if none is found.
*/
- public static MethodInvoker getMethodInvokerByAnnotation(final Class extends Annotation> annotationType, final Object candidate){
+ public static MethodInvoker getMethodInvokerByAnnotation(final Class extends Annotation> annotationType,
+ final Object candidate) {
Assert.notNull(candidate, "class must not be null");
Assert.notNull(annotationType, "annotationType must not be null");
- Assert.isTrue(ObjectUtils.containsElement(
- annotationType.getAnnotation(Target.class).value(), ElementType.METHOD),
- "Annotation [" + annotationType + "] is not a Method-level annotation.");
+ Assert.isTrue(ObjectUtils.containsElement(annotationType.getAnnotation(Target.class).value(),
+ ElementType.METHOD), "Annotation [" + annotationType + "] is not a Method-level annotation.");
final AtomicReference annotatedMethod = new AtomicReference();
ReflectionUtils.doWithMethods(candidate.getClass(), new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType);
if (annotation != null) {
- Assert.isNull(annotatedMethod.get(), "found more than one method on target class ["
- + candidate + "] with the annotation type [" + candidate + "]");
+ Assert.isNull(annotatedMethod.get(), "found more than one method on target class [" + candidate
+ + "] with the annotation type [" + candidate + "]");
annotatedMethod.set(method);
}
}
});
Method method = annotatedMethod.get();
- if(method == null){
+ if (method == null) {
return null;
}
- else{
+ else {
return new SimpleMethodInvoker(candidate, annotatedMethod.get());
}
}
+
+ /**
+ * Create a {@link MethodInvoker} for the delegate from a single public
+ * method with the signature provided.
+ *
+ * @param candidate an object to search for an appropriate method
+ * @return a MethodInvoker that calls a method on the delegate
+ */
+ public static MethodInvoker getMethodInvokerForSingleArgument(Object candidate) {
+ final AtomicReference methodHolder = new AtomicReference();
+ ReflectionUtils.doWithMethods(candidate.getClass(), new ReflectionUtils.MethodCallback() {
+ public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
+ if (method.getParameterTypes() == null || method.getParameterTypes().length != 1) {
+ return;
+ }
+ if (method.getReturnType().equals(Void.TYPE) || ReflectionUtils.isEqualsMethod(method)) {
+ return;
+ }
+ Assert.state(methodHolder.get() == null,
+ "More than one non-void public method detected with single argument.");
+ methodHolder.set(method);
+ }
+ });
+ Method method = methodHolder.get();
+ return new SimpleMethodInvoker(candidate, method);
+ }
}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/MethodResolver.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/MethodResolver.java
similarity index 96%
rename from spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/MethodResolver.java
rename to spring-batch-infrastructure/src/main/java/org/springframework/batch/support/MethodResolver.java
index cf63278ff..3cab3454f 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/MethodResolver.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/MethodResolver.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.batch.core.configuration.util;
+package org.springframework.batch.support;
import java.lang.reflect.Method;
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatcher.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatcher.java
index 12cc51056..074983435 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatcher.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatcher.java
@@ -18,6 +18,7 @@ package org.springframework.batch.support;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -27,7 +28,28 @@ import org.springframework.util.Assert;
* @author Dave Syer
* @author Dan Garrette
*/
-public class PatternMatcher {
+public class PatternMatcher {
+
+ private Map map = new HashMap();
+ private List sorted = new ArrayList();
+
+ /**
+ * Initialize a new {@link PatternMatcher} with a map of patterns to values
+ * @param map a map from String patterns to values
+ */
+ public PatternMatcher(Map map) {
+ super();
+ this.map = map;
+ // Sort keys to start with the most specific
+ sorted = new ArrayList(map.keySet());
+ Collections.sort(sorted, new Comparator() {
+ public int compare(String o1, String o2) {
+ String s1 = o1; // .replace('?', '{');
+ String s2 = o2; // .replace('*', '}');
+ return s2.compareTo(s1);
+ }
+ });
+ }
/**
* Lifted from AntPathMatcher in Spring Core. Tests whether or not a string
@@ -174,8 +196,8 @@ public class PatternMatcher {
* type. During processing, the method will identify the most specific key
* in the map that matches the line. Once the correct is identified, its
* value is returned. Note that if the map contains the wildcard string "*"
- * as a key, then it will serve as the "default" case, matching every
- * line that does not match anything else.
+ * as a key, then it will serve as the "default" case, matching every line
+ * that does not match anything else.
*
*
* If no matching prefix is found, a {@link IllegalStateException} will be
@@ -185,22 +207,13 @@ public class PatternMatcher {
* Null keys are not allowed in the map.
*
* @param line An input string
- * @param map A map with String prefixes as keys.
* @return the value whose prefix matches the given line
*/
- public static S match(String line, Map map) {
- S value = null;
- Assert.notNull(line, "A non-null key must be provided.");
+ public S match(String line) {
+
+ S value = null;
+ Assert.notNull(line, "A non-null key must be provided to match against.");
- // Sort keys to start with the most specific
- List sorted = new ArrayList(map.keySet());
- Collections.sort(sorted, new Comparator() {
- public int compare(String o1, String o2) {
- String s1 = o1; // .replace('?', '{');
- String s2 = o2; // .replace('*', '}');
- return s2.compareTo(s1);
- }
- });
for (String key : sorted) {
if (PatternMatcher.match(key, line)) {
value = map.get(key);
@@ -212,6 +225,7 @@ public class PatternMatcher {
throw new IllegalStateException("Could not find a matching pattern for key=[" + line + "]");
}
return value;
+
}
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatchingClassifier.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatchingClassifier.java
new file mode 100644
index 000000000..c019236bd
--- /dev/null
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/PatternMatchingClassifier.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.support;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link Classifier} that maps from String patterns with wildcards to a set
+ * of values of a given type. An input String is matched with the most specific
+ * pattern possible to the corresponding value in an input map. A default value
+ * should be specified with a pattern key of "*".
+ *
+ * @author Dave Syer
+ *
+ */
+public class PatternMatchingClassifier implements Classifier {
+
+ private PatternMatcher values;
+
+ /**
+ * Default constructor. Use the setter or the other constructor to create a
+ * sensible classifier, otherwise all inputs will cause an exception.
+ */
+ public PatternMatchingClassifier() {
+ this(new HashMap());
+ }
+
+ /**
+ * Create a classifier from the provided map. The keys are patterns, using
+ * '?' as a single character and '*' as multi-character wildcard.
+ *
+ * @param values
+ */
+ public PatternMatchingClassifier(Map values) {
+ super();
+ this.values = new PatternMatcher(values);
+ }
+
+ /**
+ * A map from pattern to value
+ * @param values the pattern map to set
+ */
+ public void setPatternMap(Map values) {
+ this.values = new PatternMatcher(values);
+ }
+
+ /**
+ * Classify the input by matching it against the patterns provided in
+ * {@link #setPatternMap(Map)}. The most specific pattern that matches will
+ * be used to locate a value.
+ *
+ * @return the value matching the most specific pattern possible
+ *
+ * @throws IllegalStateException if no matching value is found.
+ */
+ public T classify(String classifiable) {
+ T value = values.match(classifiable);
+ return value;
+ }
+
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/SimpleMethodInvoker.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/SimpleMethodInvoker.java
similarity index 97%
rename from spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/SimpleMethodInvoker.java
rename to spring-batch-infrastructure/src/main/java/org/springframework/batch/support/SimpleMethodInvoker.java
index f4325799b..8d4ec66e6 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/util/SimpleMethodInvoker.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/SimpleMethodInvoker.java
@@ -29,7 +29,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.batch.core.configuration.util;
+package org.springframework.batch.support;
import java.lang.reflect.Method;
import java.util.Arrays;
@@ -82,7 +82,7 @@ public class SimpleMethodInvoker implements MethodInvoker {
if(parameterTypes.length == 0){
invokeArgs = new Object[]{};
}
- else if(parameterTypes.length > args.length){
+ else if(parameterTypes.length != args.length){
throw new IllegalArgumentException("Wrong number of arguments, expected no more than: [" + parameterTypes.length + "]");
}
else{
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/annotation/Classifier.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/annotation/Classifier.java
new file mode 100644
index 000000000..d28ca042b
--- /dev/null
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/support/annotation/Classifier.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.support.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark a method as capable of classifying its input to an instance of its
+ * output. Should only be used on non-void methods with one parameter.
+ *
+ * @author Dave Syer
+ *
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface Classifier {
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/BackToBackPatternClassifierTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/BackToBackPatternClassifierTests.java
new file mode 100644
index 000000000..03c84f3ff
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/BackToBackPatternClassifierTests.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.support;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.batch.support.annotation.Classifier;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public class BackToBackPatternClassifierTests {
+
+ private BackToBackPatternClassifier classifier = new BackToBackPatternClassifier();
+
+ private Map map;
+
+ @Before
+ public void createMap() {
+ map = new HashMap();
+ map.put("foo", "bar");
+ map.put("*", "spam");
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void testNoClassifiers() {
+ classifier.classify("foo");
+ }
+
+ @Test
+ public void testCreateFromConstructor() {
+ classifier = new BackToBackPatternClassifier(new PatternMatchingClassifier(Collections
+ .singletonMap("oof", "bucket")), new PatternMatchingClassifier(map));
+ assertEquals("spam", classifier.classify("oof"));
+ }
+
+ @Test
+ public void testSetRouterDelegate() {
+ classifier.setRouterDelegate(new Object() {
+ @SuppressWarnings("unused")
+ @Classifier
+ public String convert(String value) {
+ return "bucket";
+ }
+ });
+ classifier.setMatcherMap(map);
+ assertEquals("spam", classifier.classify("oof"));
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/ClassifierAdapterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/ClassifierAdapterTests.java
new file mode 100644
index 000000000..7579da47b
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/ClassifierAdapterTests.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.support;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.springframework.batch.support.annotation.Classifier;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public class ClassifierAdapterTests {
+
+ private ClassifierAdapter adapter = new ClassifierAdapter();
+
+ @Test
+ public void testClassifierAdapterObject() {
+ adapter = new ClassifierAdapter(new Object() {
+ @SuppressWarnings("unused")
+ @Classifier
+ public Integer getValue(String key) {
+ return Integer.parseInt(key);
+ }
+
+ @SuppressWarnings("unused")
+ public Integer getAnother(String key) {
+ throw new UnsupportedOperationException("Not allowed");
+ }
+ });
+ assertEquals(23, adapter.classify("23").intValue());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testClassifierAdapterObjectWithNoAnnotation() {
+ adapter = new ClassifierAdapter(new Object() {
+ @SuppressWarnings("unused")
+ public Integer getValue(String key) {
+ return Integer.parseInt(key);
+ }
+
+ @SuppressWarnings("unused")
+ public Integer getAnother(String key) {
+ throw new UnsupportedOperationException("Not allowed");
+ }
+ });
+ assertEquals(23, adapter.classify("23").intValue());
+ }
+
+ @Test
+ public void testClassifierAdapterObjectSingleMethodWithNoAnnotation() {
+ adapter = new ClassifierAdapter(new Object() {
+ @SuppressWarnings("unused")
+ public Integer getValue(String key) {
+ return Integer.parseInt(key);
+ }
+ @SuppressWarnings("unused")
+ public void doNothing(String key) {
+ }
+ @SuppressWarnings("unused")
+ public String doNothing(String key, int value) {
+ return "foo";
+ }
+ });
+ assertEquals(23, adapter.classify("23").intValue());
+ }
+
+ @Test
+ public void testClassifierAdapterClassifier() {
+ adapter = new ClassifierAdapter(
+ new org.springframework.batch.support.Classifier() {
+ public Integer classify(String classifiable) {
+ return Integer.valueOf(classifiable);
+ }
+ });
+ assertEquals(23, adapter.classify("23").intValue());
+ }
+
+ @Test
+ public void testClassifyWithSetter() {
+ adapter.setDelegate(new Object() {
+ @SuppressWarnings("unused")
+ @Classifier
+ public Integer getValue(String key) {
+ return Integer.parseInt(key);
+ }
+ });
+ assertEquals(23, adapter.classify("23").intValue());
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testClassifyWithWrongType() {
+ adapter.setDelegate(new Object() {
+ @SuppressWarnings("unused")
+ @Classifier
+ public String getValue(Integer key) {
+ return key.toString();
+ }
+ });
+ assertEquals(23, adapter.classify("23").intValue());
+ }
+
+ @Test
+ public void testClassifyWithClassifier() {
+ adapter.setDelegate(new org.springframework.batch.support.Classifier() {
+ public Integer classify(String classifiable) {
+ return Integer.valueOf(classifiable);
+ }
+ });
+ assertEquals(23, adapter.classify("23").intValue());
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/PatternMatcherTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/PatternMatcherTests.java
index 48df26683..7debe99e6 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/PatternMatcherTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/PatternMatcherTests.java
@@ -76,6 +76,26 @@ public class PatternMatcherTests {
assertTrue(PatternMatcher.match("a*c", "abdegc"));
}
+ @Test
+ public void testMatchTwoStars() {
+ assertTrue(PatternMatcher.match("a*d*", "abcdeg"));
+ }
+
+ @Test
+ public void testMatchPastEnd() {
+ assertFalse(PatternMatcher.match("a*de", "abcdeg"));
+ }
+
+ @Test
+ public void testMatchPastEndTwoStars() {
+ assertTrue(PatternMatcher.match("a*d*g*", "abcdeg"));
+ }
+
+ @Test
+ public void testMatchStarAtEnd() {
+ assertTrue(PatternMatcher.match("ab*", "ab"));
+ }
+
@Test
public void testMatchStarNo() {
assertFalse(PatternMatcher.match("a*c", "abdeg"));
@@ -83,36 +103,36 @@ public class PatternMatcherTests {
@Test
public void testMatchPrefixSubsumed() {
- assertEquals(2, PatternMatcher.match("apple", map).intValue());
+ assertEquals(2, new PatternMatcher(map).match("apple").intValue());
}
@Test
public void testMatchPrefixSubsuming() {
- assertEquals(3, PatternMatcher.match("animal", map).intValue());
+ assertEquals(3, new PatternMatcher(map).match("animal").intValue());
}
@Test
public void testMatchPrefixUnrelated() {
- assertEquals(4, PatternMatcher.match("biggest", map).intValue());
+ assertEquals(4, new PatternMatcher(map).match("biggest").intValue());
}
@Test(expected = IllegalStateException.class)
- public void testMatchPrefix_noMatch() {
- PatternMatcher.match("bat", map);
+ public void testMatchPrefixNoMatch() {
+ new PatternMatcher(map).match("bat");
}
@Test
public void testMatchPrefixDefaultValueUnrelated() {
- assertEquals(5, PatternMatcher.match("biggest", defaultMap).intValue());
+ assertEquals(5, new PatternMatcher(defaultMap).match("biggest").intValue());
}
@Test
public void testMatchPrefixDefaultValueEmptyString() {
- assertEquals(1, PatternMatcher.match("", defaultMap).intValue());
+ assertEquals(1, new PatternMatcher(defaultMap).match("").intValue());
}
@Test
public void testMatchPrefixDefaultValueNoMatch() {
- assertEquals(1, PatternMatcher.match("bat", defaultMap).intValue());
+ assertEquals(1, new PatternMatcher(defaultMap).match("bat").intValue());
}
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/PatternMatchingClassifierTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/PatternMatchingClassifierTests.java
new file mode 100644
index 000000000..98b1d616d
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/PatternMatchingClassifierTests.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.batch.support;
+
+import static org.junit.Assert.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public class PatternMatchingClassifierTests {
+
+ private PatternMatchingClassifier classifier = new PatternMatchingClassifier();
+
+ private Map map;
+
+ @Before
+ public void createMap() {
+ map = new HashMap();
+ map.put("foo", "bar");
+ map.put("*", "spam");
+ }
+
+ @Test
+ public void testSetPatternMap() {
+ classifier.setPatternMap(map);
+ assertEquals("bar", classifier.classify("foo"));
+ assertEquals("spam", classifier.classify("bucket"));
+ }
+
+ @Test
+ public void testCreateFromMap() {
+ classifier = new PatternMatchingClassifier(map);
+ assertEquals("bar", classifier.classify("foo"));
+ assertEquals("spam", classifier.classify("bucket"));
+ }
+
+}
\ No newline at end of file
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/util/SimpleMethodInvokerTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/SimpleMethodInvokerTests.java
similarity index 65%
rename from spring-batch-core/src/test/java/org/springframework/batch/core/configuration/util/SimpleMethodInvokerTests.java
rename to spring-batch-infrastructure/src/test/java/org/springframework/batch/support/SimpleMethodInvokerTests.java
index cbefc80a8..bd059b637 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/util/SimpleMethodInvokerTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/SimpleMethodInvokerTests.java
@@ -29,16 +29,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.batch.core.configuration.util;
+package org.springframework.batch.support;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.batch.core.JobExecution;
-import org.springframework.batch.core.JobExecutionListener;
import org.springframework.util.Assert;
/**
@@ -48,8 +48,7 @@ import org.springframework.util.Assert;
public class SimpleMethodInvokerTests {
TestClass testClass;
- JobExecution jobExecution = new JobExecution(11L);
-
+ String value = "foo";
@Before
public void setUp(){
testClass = new TestClass();
@@ -58,48 +57,48 @@ public class SimpleMethodInvokerTests {
@Test
public void testMethod() throws Exception{
- Method method = TestClass.class.getMethod("beforeJob");
+ Method method = TestClass.class.getMethod("before");
MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, method);
- methodInvoker.invokeMethod(jobExecution);
- assertTrue(testClass.beforeJobCalled);
+ methodInvoker.invokeMethod(value);
+ assertTrue(testClass.beforeCalled);
}
@Test
public void testMethodByName() throws Exception{
- MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, "beforeJob", JobExecutionListener.class);
- methodInvoker.invokeMethod(jobExecution);
- assertTrue(testClass.beforeJobCalled);
+ MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, "before", String.class);
+ methodInvoker.invokeMethod(value);
+ assertTrue(testClass.beforeCalled);
}
@Test
public void testMethodWithExecution() throws Exception{
- Method method = TestClass.class.getMethod("beforeJobWithExecution", JobExecution.class);
+ Method method = TestClass.class.getMethod("beforeWithArgument", String.class);
MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, method);
- methodInvoker.invokeMethod(jobExecution);
- assertTrue(testClass.beforeJobCalled);
+ methodInvoker.invokeMethod(value);
+ assertTrue(testClass.beforeCalled);
}
@Test
public void testMethodByNameWithExecution() throws Exception{
- MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, "beforeJobWithExecution", JobExecution.class);
- methodInvoker.invokeMethod(jobExecution);
- assertTrue(testClass.beforeJobCalled);
+ MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, "beforeWithArgument", String.class);
+ methodInvoker.invokeMethod(value);
+ assertTrue(testClass.beforeCalled);
}
@Test(expected=IllegalArgumentException.class)
public void testMethodWithTooManyArguments() throws Exception{
- Method method = TestClass.class.getMethod("beforeJobWithTooManyArguments", JobExecution.class, int.class);
+ Method method = TestClass.class.getMethod("beforeWithTooManyArguments", String.class, int.class);
MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, method);
- methodInvoker.invokeMethod(jobExecution);
- assertFalse(testClass.beforeJobCalled);
+ methodInvoker.invokeMethod(value);
+ assertFalse(testClass.beforeCalled);
}
@Test(expected=IllegalArgumentException.class)
public void testMethodByNameWithTooManyArguments() throws Exception{
- MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, "beforeJobWithTooManyArguments", JobExecution.class);
- methodInvoker.invokeMethod(jobExecution);
- assertFalse(testClass.beforeJobCalled);
+ MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, "beforeWithTooManyArguments", String.class);
+ methodInvoker.invokeMethod(value);
+ assertFalse(testClass.beforeCalled);
}
@Test
@@ -111,29 +110,29 @@ public class SimpleMethodInvokerTests {
@Test
public void testEquals() throws Exception{
- Method method = TestClass.class.getMethod("beforeJobWithExecution", JobExecution.class);
+ Method method = TestClass.class.getMethod("beforeWithArgument", String.class);
MethodInvoker methodInvoker = new SimpleMethodInvoker(testClass, method);
- method = TestClass.class.getMethod("beforeJobWithExecution", JobExecution.class);
+ method = TestClass.class.getMethod("beforeWithArgument", String.class);
MethodInvoker methodInvoker2 = new SimpleMethodInvoker(testClass, method);
assertEquals(methodInvoker, methodInvoker2);
}
private class TestClass{
- boolean beforeJobCalled = false;
+ boolean beforeCalled = false;
boolean argumentTestCalled = false;
- public void beforeJob(){
- beforeJobCalled = true;
+ public void before(){
+ beforeCalled = true;
}
- public void beforeJobWithExecution(JobExecution jobExecution){
- beforeJobCalled = true;
+ public void beforeWithArgument(String value){
+ beforeCalled = true;
}
- public void beforeJobWithTooManyArguments(JobExecution jobExecution, int someInt){
- beforeJobCalled = true;
+ public void beforeWithTooManyArguments(String value, int someInt){
+ beforeCalled = true;
}
public void argumentTest(Object object){