loadInfoReflection: also handle constructors git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1088 379699f6-c40d-0410-875b-85095c16579ebranch_1_1
parent
6786a3fa35
commit
d524b1f2a8
@ -0,0 +1,793 @@ |
||||
/* ClassInfo Copyright (C) 1998-1999 Jochen Hoenicke. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2, or (at your option) |
||||
* any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; see the file COPYING. If not, write to |
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
* |
||||
* $Id$ |
||||
*/ |
||||
|
||||
package jode.bytecode; |
||||
import jode.GlobalOptions; |
||||
import java.io.DataInputStream; |
||||
import java.io.DataOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
///#ifdef JDK12
|
||||
///import java.lang.ref.WeakReference;
|
||||
///import java.lang.ref.ReferenceQueue;
|
||||
///#endif
|
||||
import @COLLECTIONS@.Map; |
||||
import @COLLECTIONS@.HashMap; |
||||
import @COLLECTIONS@.Iterator; |
||||
|
||||
import java.lang.reflect.Constructor; |
||||
import java.lang.reflect.Field; |
||||
import java.lang.reflect.Method; |
||||
import java.lang.reflect.Modifier; |
||||
|
||||
/** |
||||
* This class does represent a class similar to java.lang.Class. You |
||||
* can get the super class and the interfaces. |
||||
* |
||||
* The main difference to java.lang.Class is, that the objects are builded |
||||
* from a stream containing the .class file, and that it uses the |
||||
* <code>Type</code> to represent types instead of Class itself. |
||||
* |
||||
* @author Jochen Hoenicke |
||||
*/ |
||||
public class ClassInfo extends BinaryInfo { |
||||
|
||||
private static SearchPath classpath; |
||||
private static final Map classes = new HashMap(); |
||||
///#ifdef JDK12
|
||||
/// private static final ReferenceQueue queue = new ReferenceQueue();
|
||||
///#endif
|
||||
|
||||
private int status = 0; |
||||
|
||||
private boolean modified = false; |
||||
|
||||
private int modifiers = -1; |
||||
private String name; |
||||
private ClassInfo superclass; |
||||
private ClassInfo[] interfaces; |
||||
private FieldInfo[] fields; |
||||
private MethodInfo[] methods; |
||||
private InnerClassInfo[] outerClasses; |
||||
private InnerClassInfo[] innerClasses; |
||||
private InnerClassInfo[] extraClasses; |
||||
private String sourceFile; |
||||
|
||||
public final static ClassInfo javaLangObject = forName("java.lang.Object"); |
||||
|
||||
public static void setClassPath(String path) { |
||||
classpath = new SearchPath(path); |
||||
///#ifdef JDK12
|
||||
/// java.lang.ref.Reference died;
|
||||
/// while ((died = queue.poll()) != null) {
|
||||
/// classes.values().remove(died);
|
||||
/// }
|
||||
/// Iterator i = classes.values().iterator();
|
||||
/// while (i.hasNext()) {
|
||||
/// ClassInfo ci = (ClassInfo) ((WeakReference)i.next()).get();
|
||||
/// if (ci == null) {
|
||||
/// i.remove();
|
||||
/// continue;
|
||||
/// }
|
||||
///#else
|
||||
Iterator i = classes.values().iterator(); |
||||
while (i.hasNext()) { |
||||
ClassInfo ci = (ClassInfo) i.next(); |
||||
///#endif
|
||||
ci.status = 0; |
||||
ci.superclass = null; |
||||
ci.fields = null; |
||||
ci.interfaces = null; |
||||
ci.methods = null; |
||||
ci.removeAllAttributes(); |
||||
} |
||||
} |
||||
|
||||
public static boolean exists(String name) { |
||||
return classpath.exists(name.replace('.', '/') + ".class"); |
||||
} |
||||
|
||||
public static boolean isPackage(String name) { |
||||
return classpath.isDirectory(name.replace('.', '/')); |
||||
} |
||||
|
||||
public static Enumeration getClassesAndPackages(final String packageName) { |
||||
final Enumeration enum = |
||||
classpath.listFiles(packageName.replace('.','/')); |
||||
return new Enumeration() { |
||||
public boolean hasMoreElements() { |
||||
return enum.hasMoreElements(); |
||||
} |
||||
public Object nextElement() { |
||||
String name = (String) enum.nextElement(); |
||||
if (!name.endsWith(".class")) |
||||
// This is a package
|
||||
return name; |
||||
return name.substring(0, name.length()-6); |
||||
|
||||
} |
||||
}; |
||||
} |
||||
|
||||
public static ClassInfo forName(String name) { |
||||
if (name == null |
||||
|| name.indexOf(';') != -1 |
||||
|| name.indexOf('[') != -1 |
||||
|| name.indexOf('/') != -1) |
||||
throw new IllegalArgumentException("Illegal class name: "+name); |
||||
|
||||
///#ifdef JDK12
|
||||
/// java.lang.ref.Reference died;
|
||||
/// while ((died = queue.poll()) != null) {
|
||||
/// classes.values().remove(died);
|
||||
/// }
|
||||
/// WeakReference ref = (WeakReference) classes.get(name);
|
||||
/// ClassInfo clazz = (ref == null) ? null : (ClassInfo) ref.get();
|
||||
///#else
|
||||
ClassInfo clazz = (ClassInfo) classes.get(name); |
||||
///#endif
|
||||
if (clazz == null) { |
||||
clazz = new ClassInfo(name); |
||||
///#ifdef JDK12
|
||||
/// classes.put(name, new WeakReference(clazz, queue));
|
||||
///#else
|
||||
classes.put(name, clazz); |
||||
///#endif
|
||||
} |
||||
return clazz; |
||||
} |
||||
|
||||
private ClassInfo(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
protected void readAttribute(String name, int length, |
||||
ConstantPool cp, |
||||
DataInputStream input, |
||||
int howMuch) throws IOException { |
||||
if ((howMuch & ALL_ATTRIBUTES) != 0 && name.equals("SourceFile")) { |
||||
if (length != 2) |
||||
throw new ClassFormatException("SourceFile attribute" |
||||
+ " has wrong length"); |
||||
sourceFile = cp.getUTF8(input.readUnsignedShort()); |
||||
} else if ((howMuch & (OUTERCLASSES | INNERCLASSES)) != 0 |
||||
&& name.equals("InnerClasses")) { |
||||
int count = input.readUnsignedShort(); |
||||
int innerCount = 0, outerCount = 0, extraCount = 0; |
||||
InnerClassInfo[] innerClassInfo = new InnerClassInfo[count]; |
||||
for (int i=0; i< count; i++) { |
||||
int innerIndex = input.readUnsignedShort(); |
||||
int outerIndex = input.readUnsignedShort(); |
||||
int nameIndex = input.readUnsignedShort(); |
||||
String inner = cp.getClassName(innerIndex); |
||||
String outer = |
||||
outerIndex != 0 ? cp.getClassName(outerIndex) : null; |
||||
String innername = |
||||
nameIndex != 0 ? cp.getUTF8(nameIndex) : null; |
||||
int access = input.readUnsignedShort(); |
||||
if (innername != null && innername.length() == 0) |
||||
innername = null; |
||||
InnerClassInfo ici = new InnerClassInfo |
||||
(inner, outer, innername, access); |
||||
|
||||
if (outer != null && outer.equals(getName()) |
||||
&& innername != null) |
||||
innerClassInfo[innerCount++] = ici; |
||||
else |
||||
innerClassInfo[count - (++extraCount)] = ici; |
||||
} |
||||
{ |
||||
String lastOuterName = getName(); |
||||
for (int i = count - extraCount; i < count; i++) { |
||||
InnerClassInfo ici = innerClassInfo[i]; |
||||
if (ici.inner.equals(lastOuterName)) { |
||||
for (int j = i; j > count - extraCount; j--) |
||||
innerClassInfo[j] = innerClassInfo[j-1]; |
||||
innerClassInfo[count-extraCount] = ici; |
||||
extraCount--; |
||||
outerCount++; |
||||
lastOuterName = ici.outer; |
||||
} |
||||
} |
||||
} |
||||
if (innerCount > 0) { |
||||
innerClasses = new InnerClassInfo[innerCount]; |
||||
System.arraycopy(innerClassInfo, 0, |
||||
innerClasses, 0, innerCount); |
||||
} else |
||||
innerClasses = null; |
||||
|
||||
if (outerCount > 0) { |
||||
outerClasses = new InnerClassInfo[outerCount]; |
||||
System.arraycopy(innerClassInfo, innerCount, |
||||
outerClasses, 0, outerCount); |
||||
} else |
||||
outerClasses = null; |
||||
|
||||
if (extraCount > 0) { |
||||
extraClasses = new InnerClassInfo[extraCount]; |
||||
System.arraycopy(innerClassInfo, innerCount + outerCount, |
||||
extraClasses, 0, extraCount); |
||||
} else |
||||
extraClasses = null; |
||||
|
||||
if (length != 2 + 8 * count) |
||||
throw new ClassFormatException |
||||
("InnerClasses attribute has wrong length"); |
||||
} else |
||||
super.readAttribute(name, length, cp, input, howMuch); |
||||
} |
||||
|
||||
public void read(DataInputStream input, int howMuch) throws IOException { |
||||
/* Since we have to read the whole class anyway, we load all |
||||
* info, that we may need later and that does not take much memory. |
||||
*/ |
||||
howMuch |= FIELDS | METHODS | HIERARCHY | INNERCLASSES | OUTERCLASSES; |
||||
howMuch &= ~status; |
||||
/* header */ |
||||
if (input.readInt() != 0xcafebabe) |
||||
throw new ClassFormatException("Wrong magic"); |
||||
if (input.readUnsignedShort() > 3) |
||||
throw new ClassFormatException("Wrong minor"); |
||||
if (input.readUnsignedShort() != 45) |
||||
throw new ClassFormatException("Wrong major"); |
||||
|
||||
/* constant pool */ |
||||
ConstantPool cpool = new ConstantPool(); |
||||
cpool.read(input); |
||||
|
||||
/* always read modifiers, name, super, ifaces */ |
||||
{ |
||||
modifiers = input.readUnsignedShort(); |
||||
String className = cpool.getClassName(input.readUnsignedShort()); |
||||
if (!name.equals(className)) |
||||
throw new ClassFormatException("wrong name " + className); |
||||
String superName = cpool.getClassName(input.readUnsignedShort()); |
||||
superclass = superName != null ? ClassInfo.forName(superName) : null; |
||||
int count = input.readUnsignedShort(); |
||||
interfaces = new ClassInfo[count]; |
||||
for (int i=0; i< count; i++) { |
||||
interfaces[i] = ClassInfo.forName |
||||
(cpool.getClassName(input.readUnsignedShort())); |
||||
} |
||||
status |= HIERARCHY; |
||||
} |
||||
|
||||
/* fields */ |
||||
if ((howMuch & (FIELDS | ALL_ATTRIBUTES)) != 0) { |
||||
int count = input.readUnsignedShort(); |
||||
if ((howMuch & FIELDS) != 0) |
||||
fields = new FieldInfo[count]; |
||||
for (int i=0; i< count; i++) { |
||||
if ((howMuch & FIELDS) != 0) |
||||
fields[i] = new FieldInfo(this); |
||||
fields[i].read(cpool, input, howMuch); |
||||
} |
||||
} else { |
||||
byte[] skipBuf = new byte[6]; |
||||
int count = input.readUnsignedShort(); |
||||
for (int i=0; i< count; i++) { |
||||
input.readFully(skipBuf); // modifier, name, type
|
||||
skipAttributes(input); |
||||
} |
||||
} |
||||
|
||||
/* methods */ |
||||
if ((howMuch & (METHODS | ALL_ATTRIBUTES)) != 0) { |
||||
int count = input.readUnsignedShort(); |
||||
if ((howMuch & METHODS) != 0) |
||||
methods = new MethodInfo[count]; |
||||
for (int i=0; i< count; i++) { |
||||
if ((howMuch & METHODS) != 0) |
||||
methods[i] = new MethodInfo(this); |
||||
methods[i].read(cpool, input, howMuch); |
||||
} |
||||
} else { |
||||
byte[] skipBuf = new byte[6]; |
||||
int count = input.readUnsignedShort(); |
||||
for (int i=0; i< count; i++) { |
||||
input.readFully(skipBuf); // modifier, name, type
|
||||
skipAttributes(input); |
||||
} |
||||
} |
||||
|
||||
/* attributes */ |
||||
readAttributes(cpool, input, howMuch); |
||||
status |= howMuch; |
||||
} |
||||
|
||||
public void reserveSmallConstants(GrowableConstantPool gcp) { |
||||
for (int i=0; i < fields.length; i++) |
||||
fields[i].reserveSmallConstants(gcp); |
||||
|
||||
for (int i=0; i < methods.length; i++) |
||||
methods[i].reserveSmallConstants(gcp); |
||||
} |
||||
|
||||
public void prepareWriting(GrowableConstantPool gcp) { |
||||
gcp.putClassName(name); |
||||
gcp.putClassName(superclass.getName()); |
||||
for (int i=0; i < interfaces.length; i++) |
||||
gcp.putClassName(interfaces[i].getName()); |
||||
|
||||
for (int i=0; i < fields.length; i++) |
||||
fields[i].prepareWriting(gcp); |
||||
|
||||
for (int i=0; i < methods.length; i++) |
||||
methods[i].prepareWriting(gcp); |
||||
|
||||
if (sourceFile != null) { |
||||
gcp.putUTF8("SourceFile"); |
||||
gcp.putUTF8(sourceFile); |
||||
} |
||||
if (outerClasses != null || innerClasses != null |
||||
|| extraClasses != null) { |
||||
gcp.putUTF8("InnerClasses"); |
||||
int outerCount = outerClasses != null ? outerClasses.length : 0; |
||||
for (int i=outerCount; i-- > 0;) { |
||||
gcp.putClassName(outerClasses[i].inner); |
||||
if (outerClasses[i].outer != null) |
||||
gcp.putClassName(outerClasses[i].outer); |
||||
if (outerClasses[i].name != null) |
||||
gcp.putUTF8(outerClasses[i].name); |
||||
} |
||||
int innerCount = innerClasses != null ? innerClasses.length : 0; |
||||
for (int i=0; i< innerCount; i++) { |
||||
gcp.putClassName(innerClasses[i].inner); |
||||
if (innerClasses[i].outer != null) |
||||
gcp.putClassName(innerClasses[i].outer); |
||||
if (innerClasses[i].name != null) |
||||
gcp.putUTF8(innerClasses[i].name); |
||||
} |
||||
int extraCount = extraClasses != null ? extraClasses.length : 0; |
||||
for (int i=0; i< extraCount; i++) { |
||||
gcp.putClassName(extraClasses[i].inner); |
||||
if (extraClasses[i].outer != null) |
||||
gcp.putClassName(extraClasses[i].outer); |
||||
if (extraClasses[i].name != null) |
||||
gcp.putUTF8(extraClasses[i].name); |
||||
} |
||||
} |
||||
prepareAttributes(gcp); |
||||
} |
||||
|
||||
protected int getKnownAttributeCount() { |
||||
int count = 0; |
||||
if (sourceFile != null) |
||||
count++; |
||||
if (innerClasses != null || outerClasses != null |
||||
|| extraClasses != null) |
||||
count++; |
||||
return count; |
||||
} |
||||
|
||||
public void writeKnownAttributes(GrowableConstantPool gcp, |
||||
DataOutputStream output) |
||||
throws IOException { |
||||
if (sourceFile != null) { |
||||
output.writeShort(gcp.putUTF8("SourceFile")); |
||||
output.writeInt(2); |
||||
output.writeShort(gcp.putUTF8(sourceFile)); |
||||
} |
||||
if (outerClasses != null || innerClasses != null |
||||
|| extraClasses != null) { |
||||
output.writeShort(gcp.putUTF8("InnerClasses")); |
||||
int outerCount = (outerClasses != null) ? outerClasses.length : 0; |
||||
int innerCount = (innerClasses != null) ? innerClasses.length : 0; |
||||
int extraCount = (extraClasses != null) ? extraClasses.length : 0; |
||||
int count = outerCount + innerCount + extraCount; |
||||
output.writeInt(2 + count * 8); |
||||
output.writeShort(count); |
||||
for (int i=outerCount; i-- > 0; ) { |
||||
output.writeShort(gcp.putClassName(outerClasses[i].inner)); |
||||
output.writeShort(outerClasses[i].outer != null ? |
||||
gcp.putClassName(outerClasses[i].outer) : 0); |
||||
output.writeShort(outerClasses[i].name != null ? |
||||
gcp.putUTF8(outerClasses[i].name) : 0); |
||||
output.writeShort(outerClasses[i].modifiers); |
||||
} |
||||
for (int i=0; i< innerCount; i++) { |
||||
output.writeShort(gcp.putClassName(innerClasses[i].inner)); |
||||
output.writeShort(innerClasses[i].outer != null ? |
||||
gcp.putClassName(innerClasses[i].outer) : 0); |
||||
output.writeShort(innerClasses[i].name != null ? |
||||
gcp.putUTF8(innerClasses[i].name) : 0); |
||||
output.writeShort(innerClasses[i].modifiers); |
||||
} |
||||
for (int i=0; i< extraCount; i++) { |
||||
output.writeShort(gcp.putClassName(extraClasses[i].inner)); |
||||
output.writeShort(extraClasses[i].outer != null ? |
||||
gcp.putClassName(extraClasses[i].outer) : 0); |
||||
output.writeShort(extraClasses[i].name != null ? |
||||
gcp.putUTF8(extraClasses[i].name) : 0); |
||||
output.writeShort(extraClasses[i].modifiers); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void write(DataOutputStream out) throws IOException { |
||||
GrowableConstantPool gcp = new GrowableConstantPool(); |
||||
reserveSmallConstants(gcp); |
||||
prepareWriting(gcp); |
||||
|
||||
out.writeInt(0xcafebabe); |
||||
out.writeShort(3); |
||||
out.writeShort(45); |
||||
gcp.write(out); |
||||
|
||||
out.writeShort(modifiers); |
||||
out.writeShort(gcp.putClassName(name)); |
||||
out.writeShort(gcp.putClassName(superclass.getName())); |
||||
out.writeShort(interfaces.length); |
||||
for (int i=0; i < interfaces.length; i++) |
||||
out.writeShort(gcp.putClassName(interfaces[i].getName())); |
||||
|
||||
out.writeShort(fields.length); |
||||
for (int i=0; i < fields.length; i++) |
||||
fields[i].write(gcp, out); |
||||
|
||||
out.writeShort(methods.length); |
||||
for (int i=0; i < methods.length; i++) |
||||
methods[i].write(gcp, out); |
||||
|
||||
writeAttributes(gcp, out); |
||||
} |
||||
|
||||
public void loadInfoReflection(Class clazz, int howMuch) |
||||
throws SecurityException { |
||||
if ((howMuch & HIERARCHY) != 0) { |
||||
modifiers = clazz.getModifiers(); |
||||
if (clazz.getSuperclass() == null) |
||||
superclass = null; |
||||
else |
||||
superclass = ClassInfo.forName |
||||
(clazz.getSuperclass().getName()); |
||||
Class[] ifaces = clazz.getInterfaces(); |
||||
interfaces = new ClassInfo[ifaces.length]; |
||||
for (int i=0; i<ifaces.length; i++) |
||||
interfaces[i] = ClassInfo.forName(ifaces[i].getName()); |
||||
status |= HIERARCHY; |
||||
} |
||||
if ((howMuch & FIELDS) != 0 && fields == null) { |
||||
Field[] fs; |
||||
try { |
||||
fs = clazz.getDeclaredFields(); |
||||
} catch (SecurityException ex) { |
||||
fs = clazz.getFields(); |
||||
GlobalOptions.err.println |
||||
("Could only get public fields of class " |
||||
+ name + "."); |
||||
} |
||||
fields = new FieldInfo[fs.length]; |
||||
for (int i = fs.length; --i >= 0; ) { |
||||
String type = TypeSignature.getSignature(fs[i].getType()); |
||||
fields[i] = new FieldInfo |
||||
(this, fs[i].getName(), type, fs[i].getModifiers()); |
||||
} |
||||
} |
||||
if ((howMuch & METHODS) != 0 && methods == null) { |
||||
Constructor[] cs; |
||||
Method[] ms; |
||||
try { |
||||
cs = clazz.getDeclaredConstructors(); |
||||
ms = clazz.getDeclaredMethods(); |
||||
} catch (SecurityException ex) { |
||||
cs = clazz.getConstructors(); |
||||
ms = clazz.getMethods(); |
||||
GlobalOptions.err.println |
||||
("Could only get public methods of class " |
||||
+ name + "."); |
||||
} |
||||
methods = new MethodInfo[cs.length + ms.length]; |
||||
for (int i = cs.length; --i >= 0; ) { |
||||
String type = TypeSignature.getSignature |
||||
(cs[i].getParameterTypes(), void.class); |
||||
methods[i] = new MethodInfo |
||||
(this, "<init>", type, cs[i].getModifiers()); |
||||
} |
||||
for (int i = ms.length; --i >= 0; ) { |
||||
String type = TypeSignature.getSignature |
||||
(ms[i].getParameterTypes(), ms[i].getReturnType()); |
||||
methods[cs.length+i] = new MethodInfo |
||||
(this, ms[i].getName(), type, ms[i].getModifiers()); |
||||
} |
||||
} |
||||
if ((howMuch & INNERCLASSES) != 0 && innerClasses == null) { |
||||
Class[] is; |
||||
try { |
||||
is = clazz.getDeclaredClasses(); |
||||
} catch (SecurityException ex) { |
||||
is = clazz.getClasses(); |
||||
GlobalOptions.err.println |
||||
("Could only get public inner classes of class " |
||||
+ name + "."); |
||||
} |
||||
if (is.length > 0) { |
||||
innerClasses = new InnerClassInfo[is.length]; |
||||
for (int i = is.length; --i >= 0; ) { |
||||
String inner = is[i].getName(); |
||||
int dollar = inner.lastIndexOf('$'); |
||||
String name = inner.substring(dollar+1); |
||||
innerClasses[i] = new InnerClassInfo |
||||
(inner, getName(), name, is[i].getModifiers()); |
||||
} |
||||
} |
||||
} |
||||
if ((howMuch & OUTERCLASSES) != 0 && outerClasses == null) { |
||||
int count = 0; |
||||
Class declarer = clazz.getDeclaringClass(); |
||||
while (declarer != null) { |
||||
count++; |
||||
declarer = declarer.getDeclaringClass(); |
||||
} |
||||
if (count > 0) { |
||||
outerClasses = new InnerClassInfo[count]; |
||||
Class current = clazz; |
||||
for (int i = 0; i < count; i++) { |
||||
declarer = current.getDeclaringClass(); |
||||
String name = current.getName(); |
||||
int dollar = name.lastIndexOf('$'); |
||||
outerClasses[i] = new InnerClassInfo |
||||
(name, declarer.getName(), |
||||
name.substring(dollar+1), current.getModifiers()); |
||||
current = declarer; |
||||
} |
||||
} |
||||
} |
||||
status |= howMuch; |
||||
} |
||||
|
||||
public void loadInfo(int howMuch) { |
||||
if ((status & howMuch) == howMuch) |
||||
return; |
||||
if (modified) { |
||||
System.err.println("Allocating info 0x" |
||||
+ Integer.toHexString(howMuch) |
||||
+ " (status 0x" + Integer.toHexString(status) |
||||
+ ") in class " + this); |
||||
Thread.dumpStack(); |
||||
return; |
||||
} |
||||
try { |
||||
DataInputStream input = |
||||
new DataInputStream(classpath.getFile(name.replace('.', '/') |
||||
+ ".class")); |
||||
read(input, howMuch); |
||||
|
||||
} catch (IOException ex) { |
||||
String message = ex.getMessage(); |
||||
if ((howMuch & ~(FIELDS|METHODS|HIERARCHY |
||||
|INNERCLASSES|OUTERCLASSES)) != 0) { |
||||
GlobalOptions.err.println |
||||
("Can't read class " + name + "."); |
||||
ex.printStackTrace(GlobalOptions.err); |
||||
throw new NoClassDefFoundError(name); |
||||
} |
||||
// Try getting the info through the reflection interface
|
||||
// instead.
|
||||
Class clazz = null; |
||||
try { |
||||
clazz = Class.forName(name); |
||||
} catch (ClassNotFoundException ex2) { |
||||
} catch (NoClassDefFoundError ex2) { |
||||
} |
||||
try { |
||||
if (clazz != null) { |
||||
loadInfoReflection(clazz, howMuch); |
||||
return; |
||||
} |
||||
} catch (SecurityException ex2) { |
||||
GlobalOptions.err.println |
||||
(ex2+" while collecting info about class " + name + "."); |
||||
} |
||||
|
||||
// Give a warning and ``guess'' the hierarchie, methods etc.
|
||||
GlobalOptions.err.println |
||||
("Can't read class " + name + ", types may be incorrect. (" |
||||
+ ex.getClass().getName() |
||||
+ (message != null ? ": " + message : "") + ")"); |
||||
|
||||
if ((howMuch & HIERARCHY) != 0) { |
||||
modifiers = Modifier.PUBLIC; |
||||
if (name.equals("java.lang.Object")) |
||||
superclass = null; |
||||
else |
||||
superclass = javaLangObject; |
||||
interfaces = new ClassInfo[0]; |
||||
} |
||||
if ((howMuch & METHODS) != 0) |
||||
methods = new MethodInfo[0]; |
||||
if ((howMuch & FIELDS) != 0) |
||||
fields = new FieldInfo[0]; |
||||
status |= howMuch; |
||||
} |
||||
} |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public String getJavaName() { |
||||
/* Don't load attributes for class names not containing a |
||||
* dollar sign. |
||||
*/ |
||||
if (name.indexOf('$') == -1) |
||||
return getName(); |
||||
if (getOuterClasses() != null) { |
||||
int last = outerClasses.length-1; |
||||
StringBuffer sb = |
||||
new StringBuffer(outerClasses[last].outer != null |
||||
? outerClasses[last].outer : "METHOD"); |
||||
for (int i=last; i >= 0; i--) |
||||
sb.append(".").append(outerClasses[i].name != null |
||||
? outerClasses[i].name : "ANONYMOUS"); |
||||
return sb.toString(); |
||||
} |
||||
return getName(); |
||||
} |
||||
|
||||
public ClassInfo getSuperclass() { |
||||
if ((status & HIERARCHY) == 0) |
||||
loadInfo(HIERARCHY); |
||||
return superclass; |
||||
} |
||||
|
||||
public ClassInfo[] getInterfaces() { |
||||
if ((status & HIERARCHY) == 0) |
||||
loadInfo(HIERARCHY); |
||||
return interfaces; |
||||
} |
||||
|
||||
public int getModifiers() { |
||||
if ((status & HIERARCHY) == 0) |
||||
loadInfo(HIERARCHY); |
||||
return modifiers; |
||||
} |
||||
|
||||
public boolean isInterface() { |
||||
return Modifier.isInterface(getModifiers()); |
||||
} |
||||
|
||||
public FieldInfo findField(String name, String typeSig) { |
||||
if ((status & FIELDS) == 0) |
||||
loadInfo(FIELDS); |
||||
for (int i=0; i< fields.length; i++) |
||||
if (fields[i].getName().equals(name) |
||||
&& fields[i].getType().equals(typeSig)) |
||||
return fields[i]; |
||||
return null; |
||||
} |
||||
|
||||
public MethodInfo findMethod(String name, String typeSig) { |
||||
if ((status & METHODS) == 0) |
||||
loadInfo(METHODS); |
||||
for (int i=0; i< methods.length; i++) |
||||
if (methods[i].getName().equals(name) |
||||
&& methods[i].getType().equals(typeSig)) |
||||
return methods[i]; |
||||
return null; |
||||
} |
||||
|
||||
public MethodInfo[] getMethods() { |
||||
if ((status & METHODS) == 0) |
||||
loadInfo(METHODS); |
||||
return methods; |
||||
} |
||||
|
||||
public FieldInfo[] getFields() { |
||||
if ((status & FIELDS) == 0) |
||||
loadInfo(FIELDS); |
||||
return fields; |
||||
} |
||||
|
||||
public InnerClassInfo[] getOuterClasses() { |
||||
if ((status & OUTERCLASSES) == 0) |
||||
loadInfo(OUTERCLASSES); |
||||
return outerClasses; |
||||
} |
||||
|
||||
public InnerClassInfo[] getInnerClasses() { |
||||
if ((status & INNERCLASSES) == 0) |
||||
loadInfo(INNERCLASSES); |
||||
return innerClasses; |
||||
} |
||||
|
||||
public InnerClassInfo[] getExtraClasses() { |
||||
if ((status & INNERCLASSES) == 0) |
||||
loadInfo(INNERCLASSES); |
||||
return extraClasses; |
||||
} |
||||
|
||||
public String getSourceFile() { |
||||
return sourceFile; |
||||
} |
||||
|
||||
public void setName(String newName) { |
||||
name = newName; |
||||
modified = true; |
||||
} |
||||
|
||||
public void setSuperclass(ClassInfo newSuper) { |
||||
superclass = newSuper; |
||||
modified = true; |
||||
} |
||||
|
||||
public void setInterfaces(ClassInfo[] newIfaces) { |
||||
interfaces = newIfaces; |
||||
modified = true; |
||||
} |
||||
|
||||
public void setModifiers(int newModifiers) { |
||||
modifiers = newModifiers; |
||||
modified = true; |
||||
} |
||||
|
||||
public void setMethods(MethodInfo[] mi) { |
||||
methods = mi; |
||||
modified = true; |
||||
} |
||||
|
||||
public void setFields(FieldInfo[] fi) { |
||||
fields = fi; |
||||
modified = true; |
||||
} |
||||
|
||||
public void setOuterClasses(InnerClassInfo[] oc) { |
||||
outerClasses = oc; |
||||
modified = true; |
||||
} |
||||
|
||||
public void setInnerClasses(InnerClassInfo[] ic) { |
||||
innerClasses = ic; |
||||
modified = true; |
||||
} |
||||
|
||||
public void setExtraClasses(InnerClassInfo[] ec) { |
||||
extraClasses = ec; |
||||
modified = true; |
||||
} |
||||
|
||||
public void setSourceFile(String newSource) { |
||||
sourceFile = newSource; |
||||
modified = true; |
||||
} |
||||
|
||||
public boolean superClassOf(ClassInfo son) { |
||||
while (son != this && son != null) { |
||||
son = son.getSuperclass(); |
||||
} |
||||
return son == this; |
||||
} |
||||
|
||||
public boolean implementedBy(ClassInfo clazz) { |
||||
while (clazz != this && clazz != null) { |
||||
ClassInfo[] ifaces = clazz.getInterfaces(); |
||||
for (int i=0; i< ifaces.length; i++) { |
||||
if (implementedBy(ifaces[i])) |
||||
return true; |
||||
} |
||||
clazz = clazz.getSuperclass(); |
||||
} |
||||
return clazz == this; |
||||
} |
||||
|
||||
public String toString() { |
||||
return name; |
||||
} |
||||
} |
Loading…
Reference in new issue