/**
* Copyright (C) 2013 Kametic <epo.jemba@kametic.com>
*
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3, 29 June 2007;
* or any later version
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* 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.nuunframework.kernel.commons.specification.reflect;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.ArrayUtils;
import org.nuunframework.kernel.commons.specification.AbstractSpecification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ClassMethodsAnnotatedWith extends AbstractSpecification<Class<?>>
{
Logger logger = LoggerFactory.getLogger(ClassMethodsAnnotatedWith.class);
private MethodAnnotatedWith methodAnnotatedWith;
public ClassMethodsAnnotatedWith(Class<? extends Annotation> annotation)
{
methodAnnotatedWith = new MethodAnnotatedWith(annotation);
}
@Override
public boolean isSatisfiedBy(Class<?> candidate)
{
if (null != candidate)
{
try {
Class<?>[] clazzes = getAllInterfacesAndClasses(candidate);
for(Class<?> clazz : clazzes)
{
for ( Method method : clazz.getDeclaredMethods() )
{
if ( methodAnnotatedWith.isSatisfiedBy(method) )
{
return true;
}
}
}
}
catch (Throwable cnfe)
{
logger.warn("Exception on isSatisfiedBy () " + cnfe.getMessage());
}
}
return false;
}
Class<?>[] getAllInterfacesAndClasses(Class<?> clazz) {
return getAllInterfacesAndClasses(new Class[] { clazz } );
}
//This method walks up the inheritance hierarchy to make sure we get every class/interface that could
//possibly contain the declaration of the annotated method we're looking for.
@SuppressWarnings("unchecked")
Class<?>[] getAllInterfacesAndClasses ( Class<?>[] classes )
{
if(0 == classes.length )
{
return classes;
}
else
{
List<Class<?>> extendedClasses = new ArrayList<Class<?>>();
// all interfaces hierarchy
for (Class<?> clazz: classes) {
if (clazz != null)
{
Class<?>[] interfaces = clazz.getInterfaces();
if (interfaces != null)
{
extendedClasses.addAll((List<? extends Class<?>>) Arrays.asList( interfaces ) );
}
Class<?> superclass = clazz.getSuperclass();
if (superclass != null && superclass != Object.class)
{
extendedClasses.addAll((List<? extends Class<?>>) Arrays.asList( superclass ) );
}
}
}
//Class::getInterfaces() gets only interfaces/classes implemented/extended directly by a given class.
//We need to walk the whole way up the tree.
return (Class[]) ArrayUtils.addAll( classes, getAllInterfacesAndClasses( extendedClasses.toArray(new Class[extendedClasses.size()])));
}
}
}