OPEN - issue BATCH-1108: Add composite ItemWriter/Processor based on Classifier
First draft of classifier features added. Also refactored MethodInvoker abstraction into infrastructure.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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<T> implements LineMapper<T>, InitializingBean {
|
||||
|
||||
private PrefixMatchingCompositeLineTokenizer tokenizer = new PrefixMatchingCompositeLineTokenizer();
|
||||
private Map<String, FieldSetMapper<T>> fieldSetMappers = null;
|
||||
|
||||
private PatternMatcher<FieldSetMapper<T>> 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<String, LineTokenizer> tokenizers) {
|
||||
@@ -75,13 +76,15 @@ public class PrefixMatchingCompositeLineMapper<T> implements LineMapper<T>, Init
|
||||
}
|
||||
|
||||
public void setFieldSetMappers(Map<String, FieldSetMapper<T>> fieldSetMappers) {
|
||||
this.fieldSetMappers = new LinkedHashMap<String, FieldSetMapper<T>>();
|
||||
Assert.isTrue(!fieldSetMappers.isEmpty(), "The 'fieldSetMappers' property must be non-empty");
|
||||
LinkedHashMap<String, FieldSetMapper<T>> map = new LinkedHashMap<String, FieldSetMapper<T>>();
|
||||
for (String key : fieldSetMappers.keySet()) {
|
||||
FieldSetMapper<T> value = fieldSetMappers.get(key);
|
||||
if (!key.endsWith("*")) {
|
||||
key = key + "*";
|
||||
}
|
||||
this.fieldSetMappers.put(key, value);
|
||||
map.put(key, value);
|
||||
}
|
||||
this.patternMatcher = new PatternMatcher<FieldSetMapper<T>>(map);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String, LineTokenizer> tokenizers = null;
|
||||
private PatternMatcher<LineTokenizer> 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<String, LineTokenizer> tokenizers) {
|
||||
this.tokenizers = new LinkedHashMap<String, LineTokenizer>();
|
||||
Assert.isTrue(!tokenizers.isEmpty(), "The 'tokenizers' property must be non-empty");
|
||||
LinkedHashMap<String, LineTokenizer> map = new LinkedHashMap<String, LineTokenizer>();
|
||||
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<LineTokenizer>(map);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T> implements ItemWriter<T> {
|
||||
|
||||
private Classifier<T, ItemWriter<? super T>> classifier = new ClassifierSupport<T, ItemWriter<? super T>>(null);
|
||||
|
||||
/**
|
||||
* @param classifier the classifier to set
|
||||
*/
|
||||
public void setClassifier(Classifier<T, ItemWriter<? super T>> 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<ItemWriter<? super T>, List<T>> map = new HashMap<ItemWriter<? super T>, List<T>>();
|
||||
|
||||
for (T item : items) {
|
||||
ItemWriter<? super T> key = classifier.classify(item);
|
||||
if (!map.containsKey(key)) {
|
||||
map.put(key, new ArrayList<T>());
|
||||
}
|
||||
map.get(key).add(item);
|
||||
}
|
||||
|
||||
for (ItemWriter<? super T> writer : map.keySet()) {
|
||||
writer.write(map.get(writer));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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<C, T> implements Classifier<C, T> {
|
||||
|
||||
private Classifier<C, String> router;
|
||||
|
||||
private Classifier<String, T> 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<C, String> router, Classifier<String, T> 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<String, T> map) {
|
||||
this.matcher = new PatternMatchingClassifier<T>(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. <br/>
|
||||
*
|
||||
* @param delegate the delegate object used to create a router classifier
|
||||
*/
|
||||
public void setRouterDelegate(Object delegate) {
|
||||
this.router = new ClassifierAdapter<C,String>(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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,8 +26,8 @@ package org.springframework.batch.support;
|
||||
public interface Classifier<C, T> {
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -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<C, T> implements Classifier<C, T> {
|
||||
|
||||
private MethodInvoker invoker;
|
||||
|
||||
private Classifier<C, T> 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<C, T> delegate) {
|
||||
classifier = delegate;
|
||||
}
|
||||
|
||||
public void setDelegate(Classifier<C, T> 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.<C, T> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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<Method> annotatedMethod = new AtomicReference<Method>();
|
||||
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 <C, T> MethodInvoker getMethodInvokerForSingleArgument(Object candidate) {
|
||||
final AtomicReference<Method> methodHolder = new AtomicReference<Method>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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<S> {
|
||||
|
||||
private Map<String, S> map = new HashMap<String, S>();
|
||||
private List<String> sorted = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Initialize a new {@link PatternMatcher} with a map of patterns to values
|
||||
* @param map a map from String patterns to values
|
||||
*/
|
||||
public PatternMatcher(Map<String, S> map) {
|
||||
super();
|
||||
this.map = map;
|
||||
// Sort keys to start with the most specific
|
||||
sorted = new ArrayList<String>(map.keySet());
|
||||
Collections.sort(sorted, new Comparator<String>() {
|
||||
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.
|
||||
*
|
||||
* <p>
|
||||
* 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> S match(String line, Map<String, S> 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<String> sorted = new ArrayList<String>(map.keySet());
|
||||
Collections.sort(sorted, new Comparator<String>() {
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<T> implements Classifier<String, T> {
|
||||
|
||||
private PatternMatcher<T> 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<String, T>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<String, T> values) {
|
||||
super();
|
||||
this.values = new PatternMatcher<T>(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* A map from pattern to value
|
||||
* @param values the pattern map to set
|
||||
*/
|
||||
public void setPatternMap(Map<String, T> values) {
|
||||
this.values = new PatternMatcher<T>(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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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{
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
@@ -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<String, String> classifier = new BackToBackPatternClassifier<String, String>();
|
||||
|
||||
private Map<String, String> map;
|
||||
|
||||
@Before
|
||||
public void createMap() {
|
||||
map = new HashMap<String, String>();
|
||||
map.put("foo", "bar");
|
||||
map.put("*", "spam");
|
||||
}
|
||||
|
||||
@Test(expected=NullPointerException.class)
|
||||
public void testNoClassifiers() {
|
||||
classifier.classify("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromConstructor() {
|
||||
classifier = new BackToBackPatternClassifier<String, String>(new PatternMatchingClassifier<String>(Collections
|
||||
.singletonMap("oof", "bucket")), new PatternMatchingClassifier<String>(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"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String, Integer> adapter = new ClassifierAdapter<String, Integer>();
|
||||
|
||||
@Test
|
||||
public void testClassifierAdapterObject() {
|
||||
adapter = new ClassifierAdapter<String, Integer>(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<String, Integer>(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<String, Integer>(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<String, Integer>(
|
||||
new org.springframework.batch.support.Classifier<String, Integer>() {
|
||||
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<String, Integer>() {
|
||||
public Integer classify(String classifiable) {
|
||||
return Integer.valueOf(classifiable);
|
||||
}
|
||||
});
|
||||
assertEquals(23, adapter.classify("23").intValue());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Integer>(map).match("apple").intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchPrefixSubsuming() {
|
||||
assertEquals(3, PatternMatcher.match("animal", map).intValue());
|
||||
assertEquals(3, new PatternMatcher<Integer>(map).match("animal").intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchPrefixUnrelated() {
|
||||
assertEquals(4, PatternMatcher.match("biggest", map).intValue());
|
||||
assertEquals(4, new PatternMatcher<Integer>(map).match("biggest").intValue());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testMatchPrefix_noMatch() {
|
||||
PatternMatcher.match("bat", map);
|
||||
public void testMatchPrefixNoMatch() {
|
||||
new PatternMatcher<Integer>(map).match("bat");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchPrefixDefaultValueUnrelated() {
|
||||
assertEquals(5, PatternMatcher.match("biggest", defaultMap).intValue());
|
||||
assertEquals(5, new PatternMatcher<Integer>(defaultMap).match("biggest").intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchPrefixDefaultValueEmptyString() {
|
||||
assertEquals(1, PatternMatcher.match("", defaultMap).intValue());
|
||||
assertEquals(1, new PatternMatcher<Integer>(defaultMap).match("").intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchPrefixDefaultValueNoMatch() {
|
||||
assertEquals(1, PatternMatcher.match("bat", defaultMap).intValue());
|
||||
assertEquals(1, new PatternMatcher<Integer>(defaultMap).match("bat").intValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> classifier = new PatternMatchingClassifier<String>();
|
||||
|
||||
private Map<String, String> map;
|
||||
|
||||
@Before
|
||||
public void createMap() {
|
||||
map = new HashMap<String, String>();
|
||||
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<String>(map);
|
||||
assertEquals("bar", classifier.classify("foo"));
|
||||
assertEquals("spam", classifier.classify("bucket"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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){
|
||||
Reference in New Issue
Block a user