/**************************************************************************************
* Copyright (c) Jonas Bon�r, Alexandre Vasseur. All rights reserved. *
* http://aspectwerkz.codehaus.org *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the LGPL license *
* a copy of which has been included with this distribution in the license.txt file. *
**************************************************************************************/
package org.codehaus.aspectwerkz.reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Constructor;
import org.codehaus.aspectwerkz.definition.DescriptorUtil;
import org.codehaus.aspectwerkz.expression.SubtypePatternType;
import org.codehaus.aspectwerkz.expression.regexp.TypePattern;
import org.codehaus.aspectwerkz.reflect.impl.java.JavaMethodInfo;
import org.codehaus.aspectwerkz.reflect.impl.java.JavaConstructorInfo;
import org.codehaus.aspectwerkz.transform.TransformationUtil;
import org.codehaus.aspectwerkz.transform.delegation.JavassistHelper;
/**
* Utility method for manipulating and managing ClassInfo hierarchies.
*
* @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r </a>
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
*/
public class ClassInfoHelper {
/**
* Matches a type.
*
* @param typePattern the pattern to try to parse against
* @param classInfo the info of the class
* @return
*/
public static boolean matchType(final TypePattern typePattern, final ClassInfo classInfo) {
SubtypePatternType type = typePattern.getSubtypePatternType();
if (type.equals(SubtypePatternType.MATCH_ON_ALL_METHODS)) {
return matchSuperClasses(classInfo, typePattern);
} else if (type.equals(SubtypePatternType.MATCH_ON_BASE_TYPE_METHODS_ONLY)) {
// TODO: matching on methods ONLY in base type needs to be completed
// TODO: needs to work together with the method and field matching somehow
return matchSuperClasses(classInfo, typePattern);
} else {
return typePattern.matches(classInfo.getName());
}
}
/**
* Tries to finds a parse at some superclass in the hierarchy. <p/>Only checks for a class parse to allow early
* filtering. <p/>Recursive.
*
* @param classInfo the class info
* @param pattern the type pattern
* @return boolean
*/
public static boolean matchSuperClasses(final ClassInfo classInfo, final TypePattern pattern) {
if ((classInfo == null) || (pattern == null)) {
return false;
}
// parse the class/super class
if (pattern.matches(classInfo.getName())) {
return true;
} else {
// parse the interfaces for the class
if (matchInterfaces(classInfo.getInterfaces(), classInfo, pattern)) {
return true;
}
// no parse; getClass the next superclass
return matchSuperClasses(classInfo.getSuperClass(), pattern);
}
}
/**
* Tries to finds a parse at some interface in the hierarchy. <p/>Only checks for a class parse to allow early
* filtering. <p/>Recursive.
*
* @param interfaces the interfaces
* @param classInfo the class info
* @param pattern the type pattern
* @return boolean
*/
public static boolean matchInterfaces(
final ClassInfo[] interfaces,
final ClassInfo classInfo,
final TypePattern pattern) {
if ((interfaces.length == 0) || (classInfo == null) || (pattern == null)) {
return false;
}
for (int i = 0; i < interfaces.length; i++) {
ClassInfo anInterface = interfaces[i];
if (pattern.matches(anInterface.getName())) {
return true;
} else {
if (matchInterfaces(anInterface.getInterfaces(), classInfo, pattern)) {
return true;
} else {
continue;
}
}
}
return false;
}
/**
* Creates a member info instance based on the signature etc.
*
* @param targetClass
* @param withinMethodName
* @param withinMethodSignature
* @return a member info instance
* @TODO: check if we have a constructor and not a method
*/
public static MemberInfo createMemberInfo(
final Class targetClass,
final String withinMethodName,
final String withinMethodSignature) {
MemberInfo withinMemberInfo = null;
String[] withinMethodParameterNames = DescriptorUtil.getParameters(withinMethodSignature);
// AW-272, call within constructor
// Note: in 1.0, within info comes from CtBehavior in Javassist, and thus ctor
// is not named <init> but the FQN of its declaring class
// see ConstructorCallTF and MethodCallTF
if (targetClass.getName().equals(withinMethodName)) {
Constructor[] targetConstructors = targetClass.getDeclaredConstructors();
for (int i = 0; i < targetConstructors.length; i++) {
Constructor constructor = targetConstructors[i];
Class[] parameterTypes = constructor.getParameterTypes();
if (withinMethodParameterNames.length == parameterTypes.length) {
boolean match = true;
for (int j = 0; j < parameterTypes.length; j++) {
String withinCtorParameterName = JavassistHelper
.convertJavassistTypeSignatureToReflectTypeSignature(withinMethodParameterNames[j]);
if (!parameterTypes[j].getName().equals(withinCtorParameterName)) {
match = false;
break;
}
}
if (match) {
withinMemberInfo = JavaConstructorInfo.getConstructorInfo(constructor);
break;
}
}
}
} else {
Method[] targetMethods = targetClass.getDeclaredMethods();
for (int i = 0; i < targetMethods.length; i++) {
Method method = targetMethods[i];
Class[] parameterTypes = method.getParameterTypes();
if (method.getName().equals(withinMethodName)
&& (withinMethodParameterNames.length == parameterTypes.length)) {
boolean match = true;
for (int j = 0; j < parameterTypes.length; j++) {
String withinMethodParameterName = JavassistHelper
.convertJavassistTypeSignatureToReflectTypeSignature(withinMethodParameterNames[j]);
if (!parameterTypes[j].getName().equals(withinMethodParameterName)) {
match = false;
break;
}
}
if (match) {
withinMemberInfo = JavaMethodInfo.getMethodInfo(method);
break;
}
}
}
}
return withinMemberInfo;
}
/**
* Checks if a method is static or not.
*
* @param methodInfo the info for the method
* @return boolean
*/
public static boolean isMethodStatic(final MethodInfo methodInfo) {
int modifiers = methodInfo.getModifiers();
if ((modifiers & Modifier.STATIC) != 0) {
return true;
} else {
return false;
}
}
/**
* Checks if a class implements a certain inteface, somewhere up in the class hierarchy.
*
* @param classInfo
* @param interfaceName
* @return true if we have a parse else false
*/
public static boolean implementsInterface(final ClassInfo classInfo, final String interfaceName) {
if ((classInfo == null) || (interfaceName == null)) {
return false;
// TODO odd comparison
// } else if (classInfo.getName().equals(null)) {
// return true;
} else {
ClassInfo[] interfaces = classInfo.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
ClassInfo anInterface = interfaces[i];
if (ClassInfoHelper.implementsInterface(anInterface, interfaceName)) {
return true;
}
}
return ClassInfoHelper.implementsInterface(classInfo.getSuperClass(), interfaceName);
}
}
/**
* Checks if a class has a certain class as super class, somewhere up in the class hierarchy.
*
* @param classInfo the meta-data for the class to parse
* @param className the name of the super class
* @return true if we have a parse else false
*/
public static boolean extendsSuperClass(final ClassInfo classInfo, final String className) {
if ((classInfo == null) || (className == null)) {
return false;
// TODO odd comparison
// } else if (classInfo.getName().equals(null)) {
// return true;
} else if (className.equals(classInfo.getName())) {
return true;
} else {
return ClassInfoHelper.extendsSuperClass(classInfo.getSuperClass(), className);
}
}
}