/**************************************************************************************
* 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.metadata;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.io.ObjectInputStream;
import java.io.ByteArrayInputStream;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.NotFoundException;
import javassist.bytecode.AttributeInfo;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.ConstantAttribute;
import javassist.bytecode.SourceFileAttribute;
import javassist.bytecode.LineNumberAttribute;
import javassist.bytecode.SyntheticAttribute;
import javassist.bytecode.InnerClassesAttribute;
import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
import org.codehaus.aspectwerkz.definition.attribute.CustomAttribute;
/**
* Convenience methods to construct <code>MetaDataBase</code> instances from Javassist classes.
*
* @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r</a>
* @author <a href="mailto:vta@medios.fi">Tibor Varga</a>
* @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
*/
public class JavassistMetaDataMaker extends MetaDataMaker {
/**
* Construct class meta-data from a Javassist <code>JavaClass</code> object.
*
* @param javaClass is the <code>JavaClass</code> object to extract details from.
* @return a <code>ClassMetaData</code> instance.
*/
public static ClassMetaData createClassMetaData(final CtClass javaClass) {
if (javaClass == null) {
throw new IllegalArgumentException("class can not be null");
}
String className = javaClass.getName().replace('/', '.');
if (s_classMetaDataCache.containsKey(className)) {
return (ClassMetaData)s_classMetaDataCache.get(className);
}
ClassMetaDataImpl classMetaData = new ClassMetaDataImpl();
classMetaData.setName(className);
classMetaData.setModifiers(javaClass.getModifiers());
// constructors
List constructorList = new ArrayList();
CtConstructor[] constructors = javaClass.getConstructors();
for (int i = 0; i < constructors.length; i++) {
CtConstructor constructor = constructors[i];
constructorList.add(createConstructorMetaData(constructor));
}
classMetaData.setConstructors(constructorList);
// methods
List methodList = new ArrayList();
CtMethod[] methods = javaClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
CtMethod method = methods[i];
methodList.add(createMethodMetaData(method));
}
classMetaData.setMethods(methodList);
// fields
List fieldList = new ArrayList();
CtField[] fields = javaClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
CtField field = fields[i];
fieldList.add(createFieldMetaData(field));
}
classMetaData.setFields(fieldList);
// attributes
// TODO not supported by Javassist ??
// for (Iterator attrs = javaClass.getClassFile().getAttributes().iterator(); attrs.hasNext();) {
// addAttribute(classMetaData, ((AttributeInfo)attrs.next()));
// }
// interfaces
List interfaceList = new ArrayList();
try {
CtClass[] interfaces = javaClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
CtClass anInterface = interfaces[i];
interfaceList.add(createInterfaceMetaData(anInterface));
}
} catch (NotFoundException e) {
System.err.println(
"AspectWerkz - <WARN> unable to build metadata for "
+ className + ", missing interface " + e.getMessage()
);
} finally {
classMetaData.setInterfaces(interfaceList);
}
try {
// super class
CtClass superClass = javaClass.getSuperclass();
if (superClass != null) { // has super class?
ClassMetaData superClassMetaData = createClassMetaData(superClass);
classMetaData.setSuperClass(superClassMetaData);
}
}
catch (NotFoundException e) {
System.err.println(
"AspectWerkz - <WARN> unable to build metadata for "
+ className + ", missing superclass " + e.getMessage()
);
}
synchronized (s_classMetaDataCache) {
s_classMetaDataCache.put(classMetaData.getName(), classMetaData);
}
return classMetaData;
}
/**
* Construct interface meta-data from a Javassist <code>JavaClass</code> object.
*
* @param javaClass is the <code>JavaClass</code> object to extract details from.
* @return a <code>InterfaceMetaData</code> instance.
*/
private static InterfaceMetaData createInterfaceMetaData(final CtClass javaClass)
throws NotFoundException {
if (javaClass == null) {
throw new IllegalArgumentException("class can not be null");
}
String className = javaClass.getName().replace('/', '.');
;
if (s_interfaceMetaDataCache.containsKey(className)) {
return (InterfaceMetaData)s_interfaceMetaDataCache.get(className);
}
InterfaceMetaDataImpl interfaceMetaData = new InterfaceMetaDataImpl();
interfaceMetaData.setName(className);
// TODO not supported by Javassist ??
// // attributes
// for (Iterator attrs = javaClass.getClassFile().getAttributes().iterator(); attrs.hasNext();) {
// addAttribute(interfaceMetaData, ((AttributeInfo)attrs.next()));
// }
//try {
List interfaceList = new ArrayList();
CtClass[] interfaces = javaClass.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
CtClass anInterface = interfaces[i];
interfaceList.add(createInterfaceMetaData(anInterface));
}
interfaceMetaData.setInterfaces(interfaceList);
//}
//catch (NotFoundException e) {
// throw new WrappedRuntimeException(e);
//}
synchronized (s_interfaceMetaDataCache) {
s_interfaceMetaDataCache.put(interfaceMetaData.getName(), interfaceMetaData);
}
return interfaceMetaData;
}
/**
* Construct method meta-data from a Javassist <code>CtMethod</code> object.
*
* @param method is the <code>CtMethod</code> object to extract details from.
* @return a <code>MethodMetaData</code> instance.
*/
public static MethodMetaData createMethodMetaData(final CtMethod method) {
if (method == null) {
throw new IllegalArgumentException("method can not be null");
}
MethodMetaDataImpl methodMetaData = new MethodMetaDataImpl();
methodMetaData.setName(method.getName());
//Javassist modifier is the same as java modifier used in ReflectionMetaDataMaker
methodMetaData.setModifiers(method.getModifiers());
try {
// return type
methodMetaData.setReturnType(method.getReturnType().getName().replace('/', '.'));
// parameters
CtClass[] javaParameters = method.getParameterTypes();
String[] parameterTypes = new String[javaParameters.length];
for (int j = 0; j < javaParameters.length; j++) {
parameterTypes[j] = javaParameters[j].getName().replace('/', '.');
;
}
methodMetaData.setParameterTypes(parameterTypes);
// exceptions
CtClass[] exceptionTables = method.getExceptionTypes();
String[] exceptions = new String[exceptionTables.length];
for (int k = 0; k < exceptionTables.length; k++) {
exceptions[k] = exceptionTables[k].getName().replace('/', '.');
}
methodMetaData.setExceptionTypes(exceptions);
// // attributes
// for (Iterator attrs = method.getMethodInfo().getAttributes().iterator(); attrs.hasNext();) {
// addAttribute(methodMetaData, ((AttributeInfo)attrs.next()));
// }
return methodMetaData;
}
catch (NotFoundException e) {
// might happen if one parameter type is not in classpath
System.err.println(
"AspectWerkz - <WARN> unable to build metadata for "
+ method.getDeclaringClass().getName().replace('/', '.') + "."
+ method.getSignature() +
": " + e.getMessage()
);
return MethodMetaData.NullMethodMetaData.NULL_METHOD_METADATA;
}
}
/**
* Construct field meta-data from a Javassist <code>CtField</code> object.
*
* @param field is the <code>CtField</code> object to extract details from.
* @return a <code>FieldMetaData</code> instance.
*/
public static FieldMetaData createFieldMetaData(final CtField field) {
if (field == null) {
throw new IllegalArgumentException("field can not be null");
}
FieldMetaDataImpl fieldMetaData = new FieldMetaDataImpl();
fieldMetaData.setName(field.getName());
fieldMetaData.setModifiers(field.getModifiers());
try {
fieldMetaData.setType(field.getType().getName().replace('/', '.'));
// // attributes
// for (Iterator attrs = field.getFieldInfo().getAttributes().iterator(); attrs.hasNext();) {
// addAttribute(fieldMetaData, ((AttributeInfo)attrs.next()));
// }
return fieldMetaData;
}
catch (NotFoundException e) {
// might happen if field type is not in classpath
System.err.println(
"AspectWerkz - <WARN> unable to build metadata for "
+ field.getDeclaringClass().getName().replace('/', '.') + "." + field.getName()
+ ": " + e.getMessage()
);
return FieldMetaData.NullFieldMetaData.NULL_FIELD_METADATA;
}
}
/**
* Construct method meta-data from a Javassist <code>CtConstructor</code> object.
*
* @param constructor is the <code>CtConstructor</code> object to extract details from.
* @return a <code>ConstructorMetaData</code> instance.
*/
public static ConstructorMetaData createConstructorMetaData(final CtConstructor constructor) {
if (constructor == null) {
throw new IllegalArgumentException("constructor can not be null");
}
ConstructorMetaDataImpl constructorMetaData = new ConstructorMetaDataImpl();
constructorMetaData.setName(CONSTRUCTOR_NAME);
//Javassist modifier is the same as java modifier used in ReflectionMetaDataMaker
constructorMetaData.setModifiers(constructor.getModifiers());
try {
// parameters
CtClass[] javaParameters = constructor.getParameterTypes();
String[] parameterTypes = new String[javaParameters.length];
for (int j = 0; j < javaParameters.length; j++) {
parameterTypes[j] = javaParameters[j].getName().replace('/', '.');
}
constructorMetaData.setParameterTypes(parameterTypes);
// exceptions
CtClass[] exceptionTables = constructor.getExceptionTypes();
String[] exceptions = new String[exceptionTables.length];
for (int k = 0; k < exceptionTables.length; k++) {
exceptions[k] = exceptionTables[k].getName().replace('/', '.');
}
constructorMetaData.setExceptionTypes(exceptions);
// TODO not supported by Javassist ??
// // attributes
// for (Iterator attrs =constructor.getMethodInfo().getAttributes().iterator(); attrs.hasNext();) {
// addAttribute(constructorMetaData, ((AttributeInfo)attrs.next()));
// }
return constructorMetaData;
}
catch (NotFoundException e) {
// might happen if one parameter type is not in classpath
System.err.println(
"AspectWerkz - <WARN> unable to build metadata for "
+ constructor.getDeclaringClass().getName().replace('/', '.')
+ ".<init> " + constructor.getSignature()
+ ": " + e.getMessage()
);
return ConstructorMetaData.NullConstructorMetaData.NULL_CONSTRUCTOR_METADATA;
}
}
// private static void addAttribute(final MemberMetaData memberMetaData, final AttributeInfo attributeInfo) {
// if (true || filter(attributeInfo)) {
// return;
// }
// byte[] serializedAttribute = attributeInfo.get();
// try {
// Object attribute = new ObjectInputStream(new ByteArrayInputStream(serializedAttribute)).readObject();
// if (attribute instanceof CustomAttribute) {
// memberMetaData.addAttribute((CustomAttribute)attribute);
// }
// }
// catch (Exception e) {
// throw new WrappedRuntimeException(e);
// }
// }
//
// /**
// * @param classMetaData
// * @param attributeInfo
// * @TODO ALEX - needed, not used?
// */
// private static void addAttribute(final ClassMetaData classMetaData, final AttributeInfo attributeInfo) {
// if (true || filter(attributeInfo)) {
// return;
// }
// byte[] serializedAttribute = attributeInfo.get();
// try {
// Object attribute = new ObjectInputStream(new ByteArrayInputStream(serializedAttribute)).readObject();
// if (attribute instanceof CustomAttribute) {
// classMetaData.addAttribute((CustomAttribute)attribute);
// }
// }
// catch (Exception e) {
// throw new WrappedRuntimeException(e);
// }
// }
//
// /**
// * @param interfaceMetaData
// * @param attributeInfo
// * @TODO ALEX - needed, not used?
// */
// private static void addAttribute(final InterfaceMetaData interfaceMetaData, final AttributeInfo attributeInfo) {
// if (true || filter(attributeInfo)) {
// return;
// }
// byte[] serializedAttribute = attributeInfo.get();
// try {
// Object attribute = new ObjectInputStream(new ByteArrayInputStream(serializedAttribute)).readObject();
// if (attribute instanceof CustomAttribute) {
// interfaceMetaData.addAttribute((CustomAttribute)attribute);
// }
// }
// catch (Exception e) {
// throw new WrappedRuntimeException(e);
// }
// }
/**
* @param attr
* @return
*/
private static boolean filter(final AttributeInfo attr) {
if (attr instanceof CodeAttribute ||
attr instanceof ConstantAttribute ||
attr instanceof SourceFileAttribute ||
attr instanceof LineNumberAttribute ||
attr instanceof SyntheticAttribute ||
attr instanceof InnerClassesAttribute) {
return true;
}
else {
return false;
}
}
}