001/* 002 * Copyright 2002-2008 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.batch.support; 018 019import java.lang.annotation.Annotation; 020import java.lang.annotation.ElementType; 021import java.lang.annotation.Target; 022import java.lang.reflect.Method; 023import java.util.concurrent.atomic.AtomicReference; 024 025import org.springframework.aop.support.AopUtils; 026import org.springframework.core.annotation.AnnotationUtils; 027import org.springframework.util.Assert; 028import org.springframework.util.ObjectUtils; 029import org.springframework.util.ReflectionUtils; 030 031/** 032 * {@link MethodResolver} implementation that finds a <em>single</em> Method on the 033 * given Class that contains the specified annotation type. 034 * 035 * @author Mark Fisher 036 */ 037public class AnnotationMethodResolver implements MethodResolver { 038 039 private Class<? extends Annotation> annotationType; 040 041 042 /** 043 * Create a {@link MethodResolver} for the specified Method-level annotation type. 044 * 045 * @param annotationType establish the annotation to be used. 046 */ 047 public AnnotationMethodResolver(Class<? extends Annotation> annotationType) { 048 Assert.notNull(annotationType, "annotationType must not be null"); 049 Assert.isTrue(ObjectUtils.containsElement( 050 annotationType.getAnnotation(Target.class).value(), ElementType.METHOD), 051 "Annotation [" + annotationType + "] is not a Method-level annotation."); 052 this.annotationType = annotationType; 053 } 054 055 056 /** 057 * Find a <em>single</em> Method on the Class of the given candidate object 058 * that contains the annotation type for which this resolver is searching. 059 * 060 * @param candidate the instance whose Class will be checked for the 061 * annotation 062 * 063 * @return a single matching Method instance or <code>null</code> if the 064 * candidate's Class contains no Methods with the specified annotation 065 * 066 * @throws IllegalArgumentException if more than one Method has the 067 * specified annotation 068 */ 069 @Override 070 public Method findMethod(Object candidate) { 071 Assert.notNull(candidate, "candidate object must not be null"); 072 Class<?> targetClass = AopUtils.getTargetClass(candidate); 073 if (targetClass == null) { 074 targetClass = candidate.getClass(); 075 } 076 return this.findMethod(targetClass); 077 } 078 079 /** 080 * Find a <em>single</em> Method on the given Class that contains the 081 * annotation type for which this resolver is searching. 082 * 083 * @param clazz the Class instance to check for the annotation 084 * 085 * @return a single matching Method instance or <code>null</code> if the 086 * Class contains no Methods with the specified annotation 087 * 088 * @throws IllegalArgumentException if more than one Method has the 089 * specified annotation 090 */ 091 @Override 092 public Method findMethod(final Class<?> clazz) { 093 Assert.notNull(clazz, "class must not be null"); 094 final AtomicReference<Method> annotatedMethod = new AtomicReference<Method>(); 095 ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { 096 @Override 097 public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { 098 Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType); 099 if (annotation != null) { 100 Assert.isNull(annotatedMethod.get(), "found more than one method on target class [" 101 + clazz + "] with the annotation type [" + annotationType + "]"); 102 annotatedMethod.set(method); 103 } 104 } 105 }); 106 return annotatedMethod.get(); 107 } 108 109}