package org.aspectj.apache.bcel.classfile;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;
import org.aspectj.apache.bcel.Constants;
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnos;
import org.aspectj.apache.bcel.generic.Type;
import org.aspectj.apache.bcel.util.SyntheticRepository;
public class JavaClass extends Modifiers implements Cloneable, Node {
private static final String[] NoInterfaceNames = new String[0];
private static final Field[] NoFields = new Field[0];
private static final Method[] NoMethod = new Method[0];
private static final int[] NoInterfaceIndices = new int[0];
private static final Attribute[] NoAttributes = new Attribute[0];
private String fileName;
private String packageName;
private String sourcefileName;
private int classnameIdx;
private int superclassnameIdx;
private String classname;
private String superclassname;
private int major, minor;
private ConstantPool cpool;
private int[] interfaces;
private String[] interfacenames;
private Field[] fields;
private Method[] methods;
private Attribute[] attributes;
private AnnotationGen[] annotations;
private boolean isGeneric = false;
private boolean isAnonymous = false;
private boolean isNested = false;
private boolean computedNestedTypeStatus = false;
private boolean annotationsOutOfDate = true;
private String signatureAttributeString = null;
private Signature signatureAttribute = null;
private boolean searchedForSignatureAttribute = false;
private transient org.aspectj.apache.bcel.util.Repository repository = null;
public JavaClass(int classnameIndex, int superclassnameIndex, String filename, int major, int minor, int access_flags,
ConstantPool cpool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes) {
if (interfaces == null) {
interfaces = NoInterfaceIndices;
}
this.classnameIdx = classnameIndex;
this.superclassnameIdx = superclassnameIndex;
this.fileName = filename;
this.major = major;
this.minor = minor;
this.modifiers = access_flags;
this.cpool = cpool;
this.interfaces = interfaces;
this.fields = (fields == null ? NoFields : fields);
this.methods = (methods == null ? NoMethod : methods);
this.attributes = (attributes == null ? NoAttributes : attributes);
annotationsOutOfDate = true;
SourceFile sfAttribute = AttributeUtils.getSourceFileAttribute(attributes);
sourcefileName = sfAttribute == null ? "<Unknown>" : sfAttribute.getSourceFileName();
classname = cpool.getConstantString(classnameIndex, Constants.CONSTANT_Class);
classname = Utility.compactClassName(classname, false);
int index = classname.lastIndexOf('.');
if (index < 0) {
packageName = "";
} else {
packageName = classname.substring(0, index);
}
if (superclassnameIndex > 0) {
superclassname = cpool.getConstantString(superclassnameIndex, Constants.CONSTANT_Class);
superclassname = Utility.compactClassName(superclassname, false);
} else {
superclassname = "java.lang.Object";
}
if (interfaces.length == 0) {
interfacenames = NoInterfaceNames;
} else {
interfacenames = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
String str = cpool.getConstantString(interfaces[i], Constants.CONSTANT_Class);
interfacenames[i] = Utility.compactClassName(str, false);
}
}
}
public void accept(ClassVisitor v) {
v.visitJavaClass(this);
}
public void dump(File file) throws IOException {
String parent = file.getParent();
if (parent != null) {
File dir = new File(parent);
dir.mkdirs();
}
dump(new DataOutputStream(new FileOutputStream(file)));
}
public void dump(String file_name) throws IOException {
dump(new File(file_name));
}
public byte[] getBytes() {
ByteArrayOutputStream s = new ByteArrayOutputStream();
DataOutputStream ds = new DataOutputStream(s);
try {
dump(ds);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ds.close();
} catch (IOException e2) {
e2.printStackTrace();
}
}
return s.toByteArray();
}
public void dump(OutputStream file) throws IOException {
dump(new DataOutputStream(file));
}
public void dump(DataOutputStream file) throws IOException {
file.writeInt(0xcafebabe);
file.writeShort(minor);
file.writeShort(major);
cpool.dump(file);
file.writeShort(modifiers);
file.writeShort(classnameIdx);
file.writeShort(superclassnameIdx);
file.writeShort(interfaces.length);
for (int i = 0; i < interfaces.length; i++) {
file.writeShort(interfaces[i]);
}
file.writeShort(fields.length);
for (int i = 0; i < fields.length; i++) {
fields[i].dump(file);
}
file.writeShort(methods.length);
for (int i = 0; i < methods.length; i++) {
methods[i].dump(file);
}
AttributeUtils.writeAttributes(attributes, file);
file.close();
}
public Attribute[] getAttributes() {
return attributes;
}
public AnnotationGen[] getAnnotations() {
if (annotationsOutOfDate) {
List<AnnotationGen> accumulatedAnnotations = new ArrayList<AnnotationGen>();
for (int i = 0; i < attributes.length; i++) {
Attribute attribute = attributes[i];
if (attribute instanceof RuntimeAnnos) {
RuntimeAnnos runtimeAnnotations = (RuntimeAnnos) attribute;
accumulatedAnnotations.addAll(runtimeAnnotations.getAnnotations());
}
}
annotations = accumulatedAnnotations.toArray(new AnnotationGen[] {});
annotationsOutOfDate = false;
}
return annotations;
}
public String getClassName() {
return classname;
}
public String getPackageName() {
return packageName;
}
public int getClassNameIndex() {
return classnameIdx;
}
public ConstantPool getConstantPool() {
return cpool;
}
public Field[] getFields() {
return fields;
}
public String getFileName() {
return fileName;
}
public String[] getInterfaceNames() {
return interfacenames;
}
public int[] getInterfaceIndices() {
return interfaces;
}
public int getMajor() {
return major;
}
public Method[] getMethods() {
return methods;
}
public Method getMethod(java.lang.reflect.Method m) {
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (m.getName().equals(method.getName()) && m.getModifiers() == method.getModifiers()
&& Type.getSignature(m).equals(method.getSignature())) {
return method;
}
}
return null;
}
public Method getMethod(java.lang.reflect.Constructor<?> c) {
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (method.getName().equals("<init>") && c.getModifiers() == method.getModifiers()
&& Type.getSignature(c).equals(method.getSignature())) {
return method;
}
}
return null;
}
public Field getField(java.lang.reflect.Field field) {
String fieldName = field.getName();
for (Field f : fields) {
if (f.getName().equals(fieldName)) {
return f;
}
}
return null;
}
public int getMinor() {
return minor;
}
public String getSourceFileName() {
return sourcefileName;
}
public String getSuperclassName() {
return superclassname;
}
public int getSuperclassNameIndex() {
return superclassnameIdx;
}
public void setAttributes(Attribute[] attributes) {
this.attributes = attributes;
annotationsOutOfDate = true;
}
public void setClassName(String class_name) {
this.classname = class_name;
}
public void setClassNameIndex(int class_name_index) {
this.classnameIdx = class_name_index;
}
public void setConstantPool(ConstantPool constant_pool) {
this.cpool = constant_pool;
}
public void setFields(Field[] fields) {
this.fields = fields;
}
public void setFileName(String file_name) {
this.fileName = file_name;
}
public void setInterfaceNames(String[] interface_names) {
this.interfacenames = interface_names;
}
public void setInterfaces(int[] interfaces) {
this.interfaces = interfaces;
}
public void setMajor(int major) {
this.major = major;
}
public void setMethods(Method[] methods) {
this.methods = methods;
}
public void setMinor(int minor) {
this.minor = minor;
}
public void setSourceFileName(String source_file_name) {
this.sourcefileName = source_file_name;
}
public void setSuperclassName(String superclass_name) {
this.superclassname = superclass_name;
}
public void setSuperclassNameIndex(int superclass_name_index) {
this.superclassnameIdx = superclass_name_index;
}
@Override
public String toString() {
String access = Utility.accessToString(modifiers, true);
access = access.equals("") ? "" : access + " ";
StringBuffer buf = new StringBuffer(access + Utility.classOrInterface(modifiers) + " " + classname + " extends "
+ Utility.compactClassName(superclassname, false) + '\n');
int size = interfaces.length;
if (size > 0) {
buf.append("implements\t\t");
for (int i = 0; i < size; i++) {
buf.append(interfacenames[i]);
if (i < size - 1) {
buf.append(", ");
}
}
buf.append('\n');
}
buf.append("filename\t\t" + fileName + '\n');
buf.append("compiled from\t\t" + sourcefileName + '\n');
buf.append("compiler version\t" + major + "." + minor + '\n');
buf.append("access flags\t\t" + modifiers + '\n');
buf.append("constant pool\t\t" + cpool.getLength() + " entries\n");
buf.append("ACC_SUPER flag\t\t" + isSuper() + "\n");
if (attributes.length > 0) {
buf.append("\nAttribute(s):\n");
for (int i = 0; i < attributes.length; i++) {
buf.append(indent(attributes[i]));
}
}
if (annotations != null && annotations.length > 0) {
buf.append("\nAnnotation(s):\n");
for (int i = 0; i < annotations.length; i++) {
buf.append(indent(annotations[i]));
}
}
if (fields.length > 0) {
buf.append("\n" + fields.length + " fields:\n");
for (int i = 0; i < fields.length; i++) {
buf.append("\t" + fields[i] + '\n');
}
}
if (methods.length > 0) {
buf.append("\n" + methods.length + " methods:\n");
for (int i = 0; i < methods.length; i++) {
buf.append("\t" + methods[i] + '\n');
}
}
return buf.toString();
}
private static final String indent(Object obj) {
StringTokenizer tok = new StringTokenizer(obj.toString(), "\n");
StringBuffer buf = new StringBuffer();
while (tok.hasMoreTokens()) {
buf.append("\t" + tok.nextToken() + "\n");
}
return buf.toString();
}
public final boolean isSuper() {
return (modifiers & Constants.ACC_SUPER) != 0;
}
public final boolean isClass() {
return (modifiers & Constants.ACC_INTERFACE) == 0;
}
public final boolean isAnonymous() {
computeNestedTypeStatus();
return this.isAnonymous;
}
public final boolean isNested() {
computeNestedTypeStatus();
return this.isNested;
}
private final void computeNestedTypeStatus() {
if (computedNestedTypeStatus) {
return;
}
for (int i = 0; i < attributes.length; i++) {
if (attributes[i] instanceof InnerClasses) {
InnerClass[] innerClasses = ((InnerClasses) attributes[i]).getInnerClasses();
for (int j = 0; j < innerClasses.length; j++) {
boolean innerClassAttributeRefersToMe = false;
String inner_class_name = cpool.getConstantString(innerClasses[j].getInnerClassIndex(),
Constants.CONSTANT_Class);
inner_class_name = Utility.compactClassName(inner_class_name);
if (inner_class_name.equals(getClassName())) {
innerClassAttributeRefersToMe = true;
}
if (innerClassAttributeRefersToMe) {
this.isNested = true;
if (innerClasses[j].getInnerNameIndex() == 0) {
this.isAnonymous = true;
}
}
}
}
}
this.computedNestedTypeStatus = true;
}
public final boolean isAnnotation() {
return (modifiers & Constants.ACC_ANNOTATION) != 0;
}
public final boolean isEnum() {
return (modifiers & Constants.ACC_ENUM) != 0;
}
public org.aspectj.apache.bcel.util.Repository getRepository() {
if (repository == null) {
repository = SyntheticRepository.getInstance();
}
return repository;
}
public void setRepository(org.aspectj.apache.bcel.util.Repository repository) {
this.repository = repository;
}
public final boolean instanceOf(JavaClass super_class) {
if (this.equals(super_class)) {
return true;
}
JavaClass[] super_classes = getSuperClasses();
for (int i = 0; i < super_classes.length; i++) {
if (super_classes[i].equals(super_class)) {
return true;
}
}
if (super_class.isInterface()) {
return implementationOf(super_class);
}
return false;
}
public boolean implementationOf(JavaClass inter) {
if (!inter.isInterface()) {
throw new IllegalArgumentException(inter.getClassName() + " is no interface");
}
if (this.equals(inter)) {
return true;
}
Collection<JavaClass> superInterfaces = getAllInterfaces();
for (JavaClass superInterface : superInterfaces) {
if (superInterface.equals(inter)) {
return true;
}
}
return false;
}
public JavaClass getSuperClass() {
if ("java.lang.Object".equals(getClassName())) {
return null;
}
try {
return getRepository().loadClass(getSuperclassName());
} catch (ClassNotFoundException e) {
System.err.println(e);
return null;
}
}
public JavaClass[] getSuperClasses() {
JavaClass clazz = this;
List<JavaClass> vec = new ArrayList<JavaClass>();
for (clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) {
vec.add(clazz);
}
return vec.toArray(new JavaClass[vec.size()]);
}
public JavaClass[] getInterfaces() {
String[] interfaces = getInterfaceNames();
JavaClass[] classes = new JavaClass[interfaces.length];
try {
for (int i = 0; i < interfaces.length; i++) {
classes[i] = getRepository().loadClass(interfaces[i]);
}
} catch (ClassNotFoundException e) {
System.err.println(e);
return null;
}
return classes;
}
public Collection<JavaClass> getAllInterfaces() {
Queue<JavaClass> queue = new LinkedList<JavaClass>();
List<JavaClass> interfaceList = new ArrayList<JavaClass>();
queue.add(this);
while (!queue.isEmpty()) {
JavaClass clazz = queue.remove();
JavaClass souper = clazz.getSuperClass();
JavaClass[] interfaces = clazz.getInterfaces();
if (clazz.isInterface()) {
interfaceList.add(clazz);
} else {
if (souper != null) {
queue.add(souper);
}
}
for (int i = 0; i < interfaces.length; i++) {
queue.add(interfaces[i]);
}
}
return interfaceList;
}
public final String getGenericSignature() {
loadGenericSignatureInfoIfNecessary();
return signatureAttributeString;
}
public boolean isGeneric() {
loadGenericSignatureInfoIfNecessary();
return isGeneric;
}
private void loadGenericSignatureInfoIfNecessary() {
if (!searchedForSignatureAttribute) {
signatureAttribute = AttributeUtils.getSignatureAttribute(attributes);
signatureAttributeString = signatureAttribute == null ? null : signatureAttribute.getSignature();
isGeneric = signatureAttribute != null && signatureAttributeString.charAt(0) == '<';
searchedForSignatureAttribute = true;
}
}
public final Signature getSignatureAttribute() {
loadGenericSignatureInfoIfNecessary();
return signatureAttribute;
}
}