BATCH-2185: Updated to support annotation based listener configuration via javaconfig
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2013 the original author or authors.
|
||||
* Copyright 2006-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,22 +15,17 @@
|
||||
*/
|
||||
package org.springframework.batch.core.step.builder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.batch.operations.BatchRuntimeException;
|
||||
|
||||
import org.springframework.batch.core.ChunkListener;
|
||||
import org.springframework.batch.core.JobInterruptedException;
|
||||
import org.springframework.batch.core.SkipListener;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.StepListener;
|
||||
import org.springframework.batch.core.annotation.AfterChunk;
|
||||
import org.springframework.batch.core.annotation.AfterChunkError;
|
||||
import org.springframework.batch.core.annotation.BeforeChunk;
|
||||
import org.springframework.batch.core.annotation.OnSkipInProcess;
|
||||
import org.springframework.batch.core.annotation.OnSkipInRead;
|
||||
import org.springframework.batch.core.annotation.OnSkipInWrite;
|
||||
import org.springframework.batch.core.listener.StepListenerFactoryBean;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.FatalStepExecutionException;
|
||||
@@ -59,6 +54,7 @@ import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.batch.repeat.RepeatOperations;
|
||||
import org.springframework.batch.repeat.support.RepeatTemplate;
|
||||
import org.springframework.batch.support.ReflectionUtils;
|
||||
import org.springframework.classify.BinaryExceptionClassifier;
|
||||
import org.springframework.classify.Classifier;
|
||||
import org.springframework.classify.SubclassClassifier;
|
||||
@@ -77,12 +73,27 @@ import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.batch.operations.BatchRuntimeException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A step builder for fully fault tolerant chunk-oriented item processing steps. Extends {@link SimpleStepBuilder} with
|
||||
* additional properties for retry and skip of failed items.
|
||||
*
|
||||
* @author Dave Syer
|
||||
<<<<<<< HEAD
|
||||
* @author Chris Schaefer
|
||||
=======
|
||||
* @author Michael Minella
|
||||
>>>>>>> 2c62f20... BATCH-2185: Updated to support annotation based listener configuration via javaconfig
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
@@ -180,6 +191,45 @@ public class FaultTolerantStepBuilder<I, O> extends SimpleStepBuilder<I, O> {
|
||||
return tasklet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers objects using the annotation based listener configuration.
|
||||
*
|
||||
* @param listener the object that has a method configured with listener annotation
|
||||
* @return this for fluent chaining
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public SimpleStepBuilder listener(Object listener) {
|
||||
super.listener(listener);
|
||||
|
||||
Set<Method> skipListenerMethods = new HashSet<Method>();
|
||||
skipListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnSkipInRead.class));
|
||||
skipListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnSkipInProcess.class));
|
||||
skipListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnSkipInWrite.class));
|
||||
|
||||
Set<Method> chunkListenerMethods = new HashSet<Method>();
|
||||
chunkListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), BeforeChunk.class));
|
||||
chunkListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterChunk.class));
|
||||
chunkListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterChunkError.class));
|
||||
|
||||
if(skipListenerMethods.size() > 0) {
|
||||
StepListenerFactoryBean factory = new StepListenerFactoryBean();
|
||||
factory.setDelegate(listener);
|
||||
skipListeners.add((SkipListener) factory.getObject());
|
||||
}
|
||||
|
||||
if(chunkListenerMethods.size() > 0) {
|
||||
StepListenerFactoryBean factory = new StepListenerFactoryBean();
|
||||
factory.setDelegate(listener);
|
||||
super.listener(new TerminateOnExceptionChunkListenerDelegate((ChunkListener) factory.getObject()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
SimpleStepBuilder result = this;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a skip listener.
|
||||
*
|
||||
@@ -608,7 +658,7 @@ public class FaultTolerantStepBuilder<I, O> extends SimpleStepBuilder<I, O> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the provided {@link RetryPolicy} so that it never retries explicitly non-retryable
|
||||
* Wrap the provided {@link org.springframework.retry.RetryPolicy} so that it never retries explicitly non-retryable
|
||||
* exceptions.
|
||||
*/
|
||||
private RetryPolicy getFatalExceptionAwareProxy(RetryPolicy retryPolicy) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2013 the original author or authors.
|
||||
* Copyright 2006-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,16 +15,21 @@
|
||||
*/
|
||||
package org.springframework.batch.core.step.builder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.batch.core.ChunkListener;
|
||||
import org.springframework.batch.core.ItemProcessListener;
|
||||
import org.springframework.batch.core.ItemReadListener;
|
||||
import org.springframework.batch.core.ItemWriteListener;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.StepListener;
|
||||
import org.springframework.batch.core.annotation.AfterProcess;
|
||||
import org.springframework.batch.core.annotation.AfterRead;
|
||||
import org.springframework.batch.core.annotation.AfterWrite;
|
||||
import org.springframework.batch.core.annotation.BeforeProcess;
|
||||
import org.springframework.batch.core.annotation.BeforeRead;
|
||||
import org.springframework.batch.core.annotation.BeforeWrite;
|
||||
import org.springframework.batch.core.annotation.OnProcessError;
|
||||
import org.springframework.batch.core.annotation.OnReadError;
|
||||
import org.springframework.batch.core.annotation.OnWriteError;
|
||||
import org.springframework.batch.core.listener.StepListenerFactoryBean;
|
||||
import org.springframework.batch.core.step.item.ChunkOrientedTasklet;
|
||||
import org.springframework.batch.core.step.item.SimpleChunkProcessor;
|
||||
@@ -39,8 +44,15 @@ import org.springframework.batch.repeat.CompletionPolicy;
|
||||
import org.springframework.batch.repeat.RepeatOperations;
|
||||
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
|
||||
import org.springframework.batch.repeat.support.RepeatTemplate;
|
||||
import org.springframework.batch.support.ReflectionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Step builder for simple item processing (chunk oriented) steps. Items are read and cached in chunks, and then
|
||||
* processed (transformed) and written (optionally either the processor or the writer can be omitted) all in the same
|
||||
@@ -230,6 +242,39 @@ public class SimpleStepBuilder<I, O> extends AbstractTaskletStepBuilder<SimpleSt
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers objects using the annotation based listener configuration.
|
||||
*
|
||||
* @param listener the object that has a method configured with listener annotation
|
||||
* @return this for fluent chaining
|
||||
*/
|
||||
@Override
|
||||
public SimpleStepBuilder listener(Object listener) {
|
||||
super.listener(listener);
|
||||
|
||||
Set<Method> itemListenerMethods = new HashSet<Method>();
|
||||
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), BeforeRead.class));
|
||||
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterRead.class));
|
||||
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), BeforeProcess.class));
|
||||
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterProcess.class));
|
||||
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), BeforeWrite.class));
|
||||
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterWrite.class));
|
||||
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnReadError.class));
|
||||
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnProcessError.class));
|
||||
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnWriteError.class));
|
||||
|
||||
if(itemListenerMethods.size() > 0) {
|
||||
StepListenerFactoryBean factory = new StepListenerFactoryBean();
|
||||
factory.setDelegate(listener);
|
||||
itemListeners.add((StepListener) factory.getObject());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
SimpleStepBuilder result = this;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register an item reader listener.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2011 the original author or authors.
|
||||
* Copyright 2006-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,24 +15,32 @@
|
||||
*/
|
||||
package org.springframework.batch.core.step.builder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.annotation.AfterStep;
|
||||
import org.springframework.batch.core.annotation.BeforeStep;
|
||||
import org.springframework.batch.core.listener.StepListenerFactoryBean;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.step.AbstractStep;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.support.ReflectionUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A base class and utility for other step builders providing access to common properties like job repository and
|
||||
* transaction manager.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Michael Minella
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public abstract class StepBuilderHelper<B extends StepBuilderHelper<B>> {
|
||||
@@ -76,6 +84,28 @@ public abstract class StepBuilderHelper<B extends StepBuilderHelper<B>> {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers objects using the annotation based listener configuration.
|
||||
*
|
||||
* @param listener the object that has a method configured with listener annotation
|
||||
* @return this for fluent chaining
|
||||
*/
|
||||
public B listener(Object listener) {
|
||||
Set<Method> stepExecutionListenerMethods = new HashSet<Method>();
|
||||
stepExecutionListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), BeforeStep.class));
|
||||
stepExecutionListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterStep.class));
|
||||
|
||||
if(stepExecutionListenerMethods.size() > 0) {
|
||||
StepListenerFactoryBean factory = new StepListenerFactoryBean();
|
||||
factory.setDelegate(listener);
|
||||
properties.addStepExecutionListener((StepExecutionListener) factory.getObject());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
B result = (B) this;
|
||||
return result;
|
||||
}
|
||||
|
||||
public B listener(StepExecutionListener listener) {
|
||||
properties.addStepExecutionListener(listener);
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2014 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.
|
||||
@@ -16,19 +16,28 @@
|
||||
package org.springframework.batch.core.step.builder;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.*;
|
||||
import org.springframework.batch.core.annotation.*;
|
||||
import org.springframework.batch.core.configuration.xml.DummyItemWriter;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.support.ListItemReader;
|
||||
import org.springframework.batch.item.support.PassThroughItemProcessor;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Michael Minella
|
||||
*
|
||||
*/
|
||||
public class StepBuilderTests {
|
||||
@@ -49,6 +58,167 @@ public class StepBuilderTests {
|
||||
}
|
||||
});
|
||||
builder.build().execute(execution);
|
||||
assertEquals(BatchStatus.COMPLETED, execution.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListeners() throws Exception {
|
||||
JobRepository jobRepository = new MapJobRepositoryFactoryBean().getJobRepository();
|
||||
StepExecution execution = jobRepository.createJobExecution("foo", new JobParameters()).createStepExecution("step");
|
||||
jobRepository.add(execution);
|
||||
PlatformTransactionManager transactionManager = new ResourcelessTransactionManager();
|
||||
TaskletStepBuilder builder = new StepBuilder("step")
|
||||
.repository(jobRepository)
|
||||
.transactionManager(transactionManager)
|
||||
.listener(new InterfaceBasedStepExecutionListener())
|
||||
.listener(new AnnotationBasedStepExecutionListener())
|
||||
.tasklet(new Tasklet() {
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext)
|
||||
throws Exception {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
builder.build().execute(execution);
|
||||
assertEquals(BatchStatus.COMPLETED, execution.getStatus());
|
||||
assertEquals(1, InterfaceBasedStepExecutionListener.beforeStepCount);
|
||||
assertEquals(1, InterfaceBasedStepExecutionListener.afterStepCount);
|
||||
assertEquals(1, AnnotationBasedStepExecutionListener.beforeStepCount);
|
||||
assertEquals(1, AnnotationBasedStepExecutionListener.afterStepCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemListeners() throws Exception {
|
||||
JobRepository jobRepository = new MapJobRepositoryFactoryBean().getJobRepository();
|
||||
StepExecution execution = jobRepository.createJobExecution("foo", new JobParameters()).createStepExecution("step");
|
||||
jobRepository.add(execution);
|
||||
PlatformTransactionManager transactionManager = new ResourcelessTransactionManager();
|
||||
|
||||
List<String> items = new ArrayList<String>() {{
|
||||
add("1");
|
||||
add("2");
|
||||
add("3");
|
||||
}};
|
||||
|
||||
ItemReader<String> reader = new ListItemReader<String>(items);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
SimpleStepBuilder<String, String> builder = new StepBuilder("step")
|
||||
.repository(jobRepository)
|
||||
.transactionManager(transactionManager)
|
||||
.<String, String>chunk(3)
|
||||
.reader(reader)
|
||||
.processor(new PassThroughItemProcessor<String>())
|
||||
.writer(new DummyItemWriter())
|
||||
.listener(new AnnotationBasedStepExecutionListener());
|
||||
builder.build().execute(execution);
|
||||
|
||||
assertEquals(BatchStatus.COMPLETED, execution.getStatus());
|
||||
assertEquals(1, AnnotationBasedStepExecutionListener.beforeStepCount);
|
||||
assertEquals(1, AnnotationBasedStepExecutionListener.afterStepCount);
|
||||
assertEquals(4, AnnotationBasedStepExecutionListener.beforeReadCount);
|
||||
assertEquals(3, AnnotationBasedStepExecutionListener.afterReadCount);
|
||||
assertEquals(3, AnnotationBasedStepExecutionListener.beforeProcessCount);
|
||||
assertEquals(3, AnnotationBasedStepExecutionListener.afterProcessCount);
|
||||
assertEquals(1, AnnotationBasedStepExecutionListener.beforeWriteCount);
|
||||
assertEquals(1, AnnotationBasedStepExecutionListener.afterWriteCount);
|
||||
assertEquals(2, AnnotationBasedStepExecutionListener.beforeChunkCount);
|
||||
assertEquals(2, AnnotationBasedStepExecutionListener.afterChunkCount);
|
||||
}
|
||||
|
||||
public static class InterfaceBasedStepExecutionListener implements StepExecutionListener {
|
||||
|
||||
static int beforeStepCount = 0;
|
||||
static int afterStepCount = 0;
|
||||
|
||||
@Override
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
beforeStepCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||
afterStepCount++;
|
||||
return stepExecution.getExitStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static class AnnotationBasedStepExecutionListener {
|
||||
|
||||
static int beforeStepCount = 0;
|
||||
static int afterStepCount = 0;
|
||||
static int beforeReadCount = 0;
|
||||
static int afterReadCount = 0;
|
||||
static int beforeProcessCount = 0;
|
||||
static int afterProcessCount = 0;
|
||||
static int beforeWriteCount = 0;
|
||||
static int afterWriteCount = 0;
|
||||
static int beforeChunkCount = 0;
|
||||
static int afterChunkCount = 0;
|
||||
|
||||
public AnnotationBasedStepExecutionListener() {
|
||||
beforeStepCount = 0;
|
||||
afterStepCount = 0;
|
||||
beforeReadCount = 0;
|
||||
afterReadCount = 0;
|
||||
beforeProcessCount = 0;
|
||||
afterProcessCount = 0;
|
||||
beforeWriteCount = 0;
|
||||
afterWriteCount = 0;
|
||||
beforeChunkCount = 0;
|
||||
afterChunkCount = 0;
|
||||
}
|
||||
|
||||
@BeforeStep
|
||||
public void beforeStep() {
|
||||
beforeStepCount++;
|
||||
}
|
||||
|
||||
@AfterStep
|
||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||
afterStepCount++;
|
||||
return stepExecution.getExitStatus();
|
||||
}
|
||||
|
||||
@BeforeRead
|
||||
public void beforeRead() {
|
||||
beforeReadCount++;
|
||||
}
|
||||
|
||||
@AfterRead
|
||||
public void afterRead() {
|
||||
afterReadCount++;
|
||||
}
|
||||
|
||||
@BeforeProcess
|
||||
public void beforeProcess() {
|
||||
beforeProcessCount++;
|
||||
}
|
||||
|
||||
@AfterProcess
|
||||
public void afterProcess() {
|
||||
afterProcessCount++;
|
||||
}
|
||||
|
||||
@BeforeWrite
|
||||
public void beforeWrite() {
|
||||
beforeWriteCount++;
|
||||
}
|
||||
|
||||
@AfterWrite
|
||||
public void setAfterWrite() {
|
||||
afterWriteCount++;
|
||||
}
|
||||
|
||||
@BeforeChunk
|
||||
public void beforeChunk() {
|
||||
beforeChunkCount++;
|
||||
}
|
||||
|
||||
@AfterChunk
|
||||
public void afterChunk() {
|
||||
afterChunkCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2014 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.core.annotation.AnnotationUtils;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides reflection based utilities for Spring Batch that are not available
|
||||
* via Spring Core
|
||||
*
|
||||
* @author Michael Minella
|
||||
* @since 2.2.6
|
||||
*/
|
||||
public class ReflectionUtils {
|
||||
|
||||
private ReflectionUtils() {}
|
||||
|
||||
/**
|
||||
* Returns a {@link java.util.Set} of {@link java.lang.reflect.Method} instances that
|
||||
* are annotated with the annotation provided.
|
||||
*
|
||||
* @param clazz The class to search for a method with the given annotation type
|
||||
* @param annotationType The type of annotation to look for
|
||||
* @return a set of {@link java.lang.reflect.Method} instances if any are found, an empty set if not.
|
||||
*/
|
||||
public static final Set<Method> findMethod(Class clazz, Class<? extends Annotation> annotationType) {
|
||||
|
||||
Method [] declaredMethods = org.springframework.util.ReflectionUtils.getAllDeclaredMethods(clazz);
|
||||
Set<Method> results = new HashSet<Method>();
|
||||
|
||||
for (Method curMethod : declaredMethods) {
|
||||
Annotation annotation = AnnotationUtils.findAnnotation(curMethod, annotationType);
|
||||
|
||||
if(annotation != null) {
|
||||
results.add(curMethod);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2014 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.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Michael Minella
|
||||
* @since 2.2.6
|
||||
*/
|
||||
public class ReflectionUtilsTests {
|
||||
|
||||
@Test
|
||||
public void testFindAnnotatedMethod() {
|
||||
Set<Method> methods = ReflectionUtils.findMethod(AnnotatedClass.class, Transactional.class);
|
||||
assertEquals(1, methods.size());
|
||||
assertEquals("toString", methods.iterator().next().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindNoAnnotatedMethod() {
|
||||
Set<Method> methods = ReflectionUtils.findMethod(AnnotatedClass.class, Autowired.class);
|
||||
assertEquals(0, methods.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindAnnotatedMethodHierarchy() {
|
||||
Set<Method> methods = ReflectionUtils.findMethod(AnnotatedSubClass.class, Transactional.class);
|
||||
assertEquals(2, methods.size());
|
||||
|
||||
boolean toStringFound = false;
|
||||
boolean methodOneFound = false;
|
||||
|
||||
Iterator<Method> iterator = methods.iterator();
|
||||
|
||||
String name = iterator.next().getName();
|
||||
|
||||
if(name.equals("toString")) {
|
||||
toStringFound = true;
|
||||
} else if(name.equals("methodOne")) {
|
||||
methodOneFound = true;
|
||||
}
|
||||
|
||||
name = iterator.next().getName();
|
||||
|
||||
if(name.equals("toString")) {
|
||||
toStringFound = true;
|
||||
} else if(name.equals("methodOne")) {
|
||||
methodOneFound = true;
|
||||
}
|
||||
|
||||
assertTrue(toStringFound && methodOneFound);
|
||||
}
|
||||
|
||||
public static class AnnotatedClass {
|
||||
|
||||
public void methodOne() {
|
||||
System.err.println("This is method 1");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public String toString() {
|
||||
return "AnnoatedClass";
|
||||
}
|
||||
}
|
||||
|
||||
public static class AnnotatedSubClass extends AnnotatedClass {
|
||||
|
||||
@Transactional
|
||||
public void methodOne() {
|
||||
System.err.println("This is method 1 in the sub class");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user