You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
827 lines
24 KiB
827 lines
24 KiB
/*
|
|
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*/
|
|
package com.sun.org.apache.bcel.internal.classfile;
|
|
|
|
/* ====================================================================
|
|
* The Apache Software License, Version 1.1
|
|
*
|
|
* Copyright (c) 2001 The Apache Software Foundation. All rights
|
|
* reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* 3. The end-user documentation included with the redistribution,
|
|
* if any, must include the following acknowledgment:
|
|
* "This product includes software developed by the
|
|
* Apache Software Foundation (http://www.apache.org/)."
|
|
* Alternately, this acknowledgment may appear in the software itself,
|
|
* if and wherever such third-party acknowledgments normally appear.
|
|
*
|
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
|
* "Apache BCEL" must not be used to endorse or promote products
|
|
* derived from this software without prior written permission. For
|
|
* written permission, please contact apache@apache.org.
|
|
*
|
|
* 5. Products derived from this software may not be called "Apache",
|
|
* "Apache BCEL", nor may "Apache" appear in their name, without
|
|
* prior written permission of the Apache Software Foundation.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
* ====================================================================
|
|
*
|
|
* This software consists of voluntary contributions made by many
|
|
* individuals on behalf of the Apache Software Foundation. For more
|
|
* information on the Apache Software Foundation, please see
|
|
* <http://www.apache.org/>.
|
|
*/
|
|
|
|
import com.sun.org.apache.bcel.internal.Constants;
|
|
import com.sun.org.apache.bcel.internal.util.SyntheticRepository;
|
|
import com.sun.org.apache.bcel.internal.util.ClassVector;
|
|
import com.sun.org.apache.bcel.internal.util.ClassQueue;
|
|
import com.sun.org.apache.bcel.internal.generic.Type;
|
|
import com.sun.org.apache.xalan.internal.utils.SecuritySupport;
|
|
|
|
import java.io.*;
|
|
import java.util.StringTokenizer;
|
|
|
|
/**
|
|
* Represents a Java class, i.e., the data structures, constant pool,
|
|
* fields, methods and commands contained in a Java .class file.
|
|
* See <a href="ftp://java.sun.com/docs/specs/">JVM
|
|
* specification</a> for details.
|
|
|
|
* The intent of this class is to represent a parsed or otherwise existing
|
|
* class file. Those interested in programatically generating classes
|
|
* should see the <a href="../generic/ClassGen.html">ClassGen</a> class.
|
|
|
|
* @version $Id: JavaClass.java,v 1.4 2007-07-19 04:34:42 ofung Exp $
|
|
* @see com.sun.org.apache.bcel.internal.generic.ClassGen
|
|
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
|
|
*/
|
|
public class JavaClass extends AccessFlags implements Cloneable, Node {
|
|
private String file_name;
|
|
private String package_name;
|
|
private String source_file_name = "<Unknown>";
|
|
private int class_name_index;
|
|
private int superclass_name_index;
|
|
private String class_name;
|
|
private String superclass_name;
|
|
private int major, minor; // Compiler version
|
|
private ConstantPool constant_pool; // Constant pool
|
|
private int[] interfaces; // implemented interfaces
|
|
private String[] interface_names;
|
|
private Field[] fields; // Fields, i.e., variables of class
|
|
private Method[] methods; // methods defined in the class
|
|
private Attribute[] attributes; // attributes defined in the class
|
|
private byte source = HEAP; // Generated in memory
|
|
|
|
public static final byte HEAP = 1;
|
|
public static final byte FILE = 2;
|
|
public static final byte ZIP = 3;
|
|
|
|
static boolean debug = false; // Debugging on/off
|
|
static char sep = '/'; // directory separator
|
|
|
|
/**
|
|
* In cases where we go ahead and create something,
|
|
* use the default SyntheticRepository, because we
|
|
* don't know any better.
|
|
*/
|
|
private transient com.sun.org.apache.bcel.internal.util.Repository repository =
|
|
SyntheticRepository.getInstance();
|
|
|
|
/**
|
|
* Constructor gets all contents as arguments.
|
|
*
|
|
* @param class_name_index Index into constant pool referencing a
|
|
* ConstantClass that represents this class.
|
|
* @param superclass_name_index Index into constant pool referencing a
|
|
* ConstantClass that represents this class's superclass.
|
|
* @param file_name File name
|
|
* @param major Major compiler version
|
|
* @param minor Minor compiler version
|
|
* @param access_flags Access rights defined by bit flags
|
|
* @param constant_pool Array of constants
|
|
* @param interfaces Implemented interfaces
|
|
* @param fields Class fields
|
|
* @param methods Class methods
|
|
* @param attributes Class attributes
|
|
* @param source Read from file or generated in memory?
|
|
*/
|
|
public JavaClass(int class_name_index,
|
|
int superclass_name_index,
|
|
String file_name,
|
|
int major,
|
|
int minor,
|
|
int access_flags,
|
|
ConstantPool constant_pool,
|
|
int[] interfaces,
|
|
Field[] fields,
|
|
Method[] methods,
|
|
Attribute[] attributes,
|
|
byte source)
|
|
{
|
|
if(interfaces == null) // Allowed for backward compatibility
|
|
interfaces = new int[0];
|
|
if(attributes == null)
|
|
this.attributes = new Attribute[0];
|
|
if(fields == null)
|
|
fields = new Field[0];
|
|
if(methods == null)
|
|
methods = new Method[0];
|
|
|
|
this.class_name_index = class_name_index;
|
|
this.superclass_name_index = superclass_name_index;
|
|
this.file_name = file_name;
|
|
this.major = major;
|
|
this.minor = minor;
|
|
this.access_flags = access_flags;
|
|
this.constant_pool = constant_pool;
|
|
this.interfaces = interfaces;
|
|
this.fields = fields;
|
|
this.methods = methods;
|
|
this.attributes = attributes;
|
|
this.source = source;
|
|
|
|
// Get source file name if available
|
|
for(int i=0; i < attributes.length; i++) {
|
|
if(attributes[i] instanceof SourceFile) {
|
|
source_file_name = ((SourceFile)attributes[i]).getSourceFileName();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* According to the specification the following entries must be of type
|
|
* `ConstantClass' but we check that anyway via the
|
|
* `ConstPool.getConstant' method.
|
|
*/
|
|
class_name = constant_pool.getConstantString(class_name_index,
|
|
Constants.CONSTANT_Class);
|
|
class_name = Utility.compactClassName(class_name, false);
|
|
|
|
int index = class_name.lastIndexOf('.');
|
|
if(index < 0)
|
|
package_name = "";
|
|
else
|
|
package_name = class_name.substring(0, index);
|
|
|
|
if(superclass_name_index > 0) { // May be zero -> class is java.lang.Object
|
|
superclass_name = constant_pool.getConstantString(superclass_name_index,
|
|
Constants.CONSTANT_Class);
|
|
superclass_name = Utility.compactClassName(superclass_name, false);
|
|
}
|
|
else
|
|
superclass_name = "java.lang.Object";
|
|
|
|
interface_names = new String[interfaces.length];
|
|
for(int i=0; i < interfaces.length; i++) {
|
|
String str = constant_pool.getConstantString(interfaces[i], Constants.CONSTANT_Class);
|
|
interface_names[i] = Utility.compactClassName(str, false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Constructor gets all contents as arguments.
|
|
*
|
|
* @param class_name_index Class name
|
|
* @param superclass_name_index Superclass name
|
|
* @param file_name File name
|
|
* @param major Major compiler version
|
|
* @param minor Minor compiler version
|
|
* @param access_flags Access rights defined by bit flags
|
|
* @param constant_pool Array of constants
|
|
* @param interfaces Implemented interfaces
|
|
* @param fields Class fields
|
|
* @param methods Class methods
|
|
* @param attributes Class attributes
|
|
*/
|
|
public JavaClass(int class_name_index,
|
|
int superclass_name_index,
|
|
String file_name,
|
|
int major,
|
|
int minor,
|
|
int access_flags,
|
|
ConstantPool constant_pool,
|
|
int[] interfaces,
|
|
Field[] fields,
|
|
Method[] methods,
|
|
Attribute[] attributes) {
|
|
this(class_name_index, superclass_name_index, file_name, major, minor, access_flags,
|
|
constant_pool, interfaces, fields, methods, attributes, HEAP);
|
|
}
|
|
|
|
|
|
/**
|
|
* Called by objects that are traversing the nodes of the tree implicitely
|
|
* defined by the contents of a Java class. I.e., the hierarchy of methods,
|
|
* fields, attributes, etc. spawns a tree of objects.
|
|
*
|
|
* @param v Visitor object
|
|
*/
|
|
public void accept(Visitor v) {
|
|
v.visitJavaClass(this);
|
|
}
|
|
|
|
/* Print debug information depending on `JavaClass.debug'
|
|
*/
|
|
static final void Debug(String str) {
|
|
if(debug)
|
|
System.out.println(str);
|
|
}
|
|
|
|
/**
|
|
* Dump class to a file.
|
|
*
|
|
* @param file Output file
|
|
* @throws IOException
|
|
*/
|
|
public void dump(File file) throws IOException
|
|
{
|
|
String parent = file.getParent();
|
|
|
|
if(parent != null) {
|
|
File dir = new File(parent);
|
|
|
|
if(dir != null)
|
|
dir.mkdirs();
|
|
}
|
|
|
|
dump(new DataOutputStream(new FileOutputStream(file)));
|
|
}
|
|
|
|
/**
|
|
* Dump class to a file named file_name.
|
|
*
|
|
* @param file_name Output file name
|
|
* @exception IOException
|
|
*/
|
|
public void dump(String file_name) throws IOException
|
|
{
|
|
dump(new File(file_name));
|
|
}
|
|
|
|
/**
|
|
* @return class in binary format
|
|
*/
|
|
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();
|
|
}
|
|
|
|
/**
|
|
* Dump Java class to output stream in binary format.
|
|
*
|
|
* @param file Output stream
|
|
* @exception IOException
|
|
*/
|
|
public void dump(OutputStream file) throws IOException {
|
|
dump(new DataOutputStream(file));
|
|
}
|
|
|
|
/**
|
|
* Dump Java class to output stream in binary format.
|
|
*
|
|
* @param file Output stream
|
|
* @exception IOException
|
|
*/
|
|
public void dump(DataOutputStream file) throws IOException
|
|
{
|
|
file.writeInt(0xcafebabe);
|
|
file.writeShort(minor);
|
|
file.writeShort(major);
|
|
|
|
constant_pool.dump(file);
|
|
|
|
file.writeShort(access_flags);
|
|
file.writeShort(class_name_index);
|
|
file.writeShort(superclass_name_index);
|
|
|
|
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);
|
|
|
|
if(attributes != null) {
|
|
file.writeShort(attributes.length);
|
|
for(int i=0; i < attributes.length; i++)
|
|
attributes[i].dump(file);
|
|
}
|
|
else
|
|
file.writeShort(0);
|
|
|
|
file.close();
|
|
}
|
|
|
|
/**
|
|
* @return Attributes of the class.
|
|
*/
|
|
public Attribute[] getAttributes() { return attributes; }
|
|
|
|
/**
|
|
* @return Class name.
|
|
*/
|
|
public String getClassName() { return class_name; }
|
|
|
|
/**
|
|
* @return Package name.
|
|
*/
|
|
public String getPackageName() { return package_name; }
|
|
|
|
/**
|
|
* @return Class name index.
|
|
*/
|
|
public int getClassNameIndex() { return class_name_index; }
|
|
|
|
/**
|
|
* @return Constant pool.
|
|
*/
|
|
public ConstantPool getConstantPool() { return constant_pool; }
|
|
|
|
/**
|
|
* @return Fields, i.e., variables of the class. Like the JVM spec
|
|
* mandates for the classfile format, these fields are those specific to
|
|
* this class, and not those of the superclass or superinterfaces.
|
|
*/
|
|
public Field[] getFields() { return fields; }
|
|
|
|
/**
|
|
* @return File name of class, aka SourceFile attribute value
|
|
*/
|
|
public String getFileName() { return file_name; }
|
|
|
|
/**
|
|
* @return Names of implemented interfaces.
|
|
*/
|
|
public String[] getInterfaceNames() { return interface_names; }
|
|
|
|
/**
|
|
* @return Indices in constant pool of implemented interfaces.
|
|
*/
|
|
public int[] getInterfaceIndices() { return interfaces; }
|
|
|
|
/**
|
|
* @return Major number of class file version.
|
|
*/
|
|
public int getMajor() { return major; }
|
|
|
|
/**
|
|
* @return Methods of the class.
|
|
*/
|
|
public Method[] getMethods() { return methods; }
|
|
|
|
/**
|
|
* @return A com.sun.org.apache.bcel.internal.classfile.Method corresponding to
|
|
* java.lang.reflect.Method if any
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* @return Minor number of class file version.
|
|
*/
|
|
public int getMinor() { return minor; }
|
|
|
|
/**
|
|
* @return sbsolute path to file where this class was read from
|
|
*/
|
|
public String getSourceFileName() { return source_file_name; }
|
|
|
|
/**
|
|
* @return Superclass name.
|
|
*/
|
|
public String getSuperclassName() { return superclass_name; }
|
|
|
|
/**
|
|
* @return Class name index.
|
|
*/
|
|
public int getSuperclassNameIndex() { return superclass_name_index; }
|
|
|
|
static {
|
|
// Debugging ... on/off
|
|
String debug = null, sep = null;
|
|
|
|
try {
|
|
debug = SecuritySupport.getSystemProperty("JavaClass.debug");
|
|
// Get path separator either / or \ usually
|
|
sep = SecuritySupport.getSystemProperty("file.separator");
|
|
}
|
|
catch (SecurityException e) {
|
|
// falls through
|
|
}
|
|
|
|
if(debug != null)
|
|
JavaClass.debug = new Boolean(debug).booleanValue();
|
|
|
|
if(sep != null)
|
|
try {
|
|
JavaClass.sep = sep.charAt(0);
|
|
} catch(StringIndexOutOfBoundsException e) {} // Never reached
|
|
}
|
|
|
|
/**
|
|
* @param attributes .
|
|
*/
|
|
public void setAttributes(Attribute[] attributes) {
|
|
this.attributes = attributes;
|
|
}
|
|
|
|
/**
|
|
* @param class_name .
|
|
*/
|
|
public void setClassName(String class_name) {
|
|
this.class_name = class_name;
|
|
}
|
|
|
|
/**
|
|
* @param class_name_index .
|
|
*/
|
|
public void setClassNameIndex(int class_name_index) {
|
|
this.class_name_index = class_name_index;
|
|
}
|
|
|
|
/**
|
|
* @param constant_pool .
|
|
*/
|
|
public void setConstantPool(ConstantPool constant_pool) {
|
|
this.constant_pool = constant_pool;
|
|
}
|
|
|
|
/**
|
|
* @param fields .
|
|
*/
|
|
public void setFields(Field[] fields) {
|
|
this.fields = fields;
|
|
}
|
|
|
|
/**
|
|
* Set File name of class, aka SourceFile attribute value
|
|
*/
|
|
public void setFileName(String file_name) {
|
|
this.file_name = file_name;
|
|
}
|
|
|
|
/**
|
|
* @param interface_names .
|
|
*/
|
|
public void setInterfaceNames(String[] interface_names) {
|
|
this.interface_names = interface_names;
|
|
}
|
|
|
|
/**
|
|
* @param interfaces .
|
|
*/
|
|
public void setInterfaces(int[] interfaces) {
|
|
this.interfaces = interfaces;
|
|
}
|
|
|
|
/**
|
|
* @param major .
|
|
*/
|
|
public void setMajor(int major) {
|
|
this.major = major;
|
|
}
|
|
|
|
/**
|
|
* @param methods .
|
|
*/
|
|
public void setMethods(Method[] methods) {
|
|
this.methods = methods;
|
|
}
|
|
|
|
/**
|
|
* @param minor .
|
|
*/
|
|
public void setMinor(int minor) {
|
|
this.minor = minor;
|
|
}
|
|
|
|
/**
|
|
* Set absolute path to file this class was read from.
|
|
*/
|
|
public void setSourceFileName(String source_file_name) {
|
|
this.source_file_name = source_file_name;
|
|
}
|
|
|
|
/**
|
|
* @param superclass_name .
|
|
*/
|
|
public void setSuperclassName(String superclass_name) {
|
|
this.superclass_name = superclass_name;
|
|
}
|
|
|
|
/**
|
|
* @param superclass_name_index .
|
|
*/
|
|
public void setSuperclassNameIndex(int superclass_name_index) {
|
|
this.superclass_name_index = superclass_name_index;
|
|
}
|
|
|
|
/**
|
|
* @return String representing class contents.
|
|
*/
|
|
public String toString() {
|
|
String access = Utility.accessToString(access_flags, true);
|
|
access = access.equals("")? "" : (access + " ");
|
|
|
|
StringBuffer buf = new StringBuffer(access +
|
|
Utility.classOrInterface(access_flags) +
|
|
" " +
|
|
class_name + " extends " +
|
|
Utility.compactClassName(superclass_name,
|
|
false) + '\n');
|
|
int size = interfaces.length;
|
|
|
|
if(size > 0) {
|
|
buf.append("implements\t\t");
|
|
|
|
for(int i=0; i < size; i++) {
|
|
buf.append(interface_names[i]);
|
|
if(i < size - 1)
|
|
buf.append(", ");
|
|
}
|
|
|
|
buf.append('\n');
|
|
}
|
|
|
|
buf.append("filename\t\t" + file_name + '\n');
|
|
buf.append("compiled from\t\t" + source_file_name + '\n');
|
|
buf.append("compiler version\t" + major + "." + minor + '\n');
|
|
buf.append("access flags\t\t" + access_flags + '\n');
|
|
buf.append("constant pool\t\t" + constant_pool.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(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();
|
|
}
|
|
|
|
/**
|
|
* @return deep copy of this class
|
|
*/
|
|
public JavaClass copy() {
|
|
JavaClass c = null;
|
|
|
|
try {
|
|
c = (JavaClass)clone();
|
|
} catch(CloneNotSupportedException e) {}
|
|
|
|
c.constant_pool = constant_pool.copy();
|
|
c.interfaces = (int[])interfaces.clone();
|
|
c.interface_names = (String[])interface_names.clone();
|
|
|
|
c.fields = new Field[fields.length];
|
|
for(int i=0; i < fields.length; i++)
|
|
c.fields[i] = fields[i].copy(c.constant_pool);
|
|
|
|
c.methods = new Method[methods.length];
|
|
for(int i=0; i < methods.length; i++)
|
|
c.methods[i] = methods[i].copy(c.constant_pool);
|
|
|
|
c.attributes = new Attribute[attributes.length];
|
|
for(int i=0; i < attributes.length; i++)
|
|
c.attributes[i] = attributes[i].copy(c.constant_pool);
|
|
|
|
return c;
|
|
}
|
|
|
|
public final boolean isSuper() {
|
|
return (access_flags & Constants.ACC_SUPER) != 0;
|
|
}
|
|
|
|
public final boolean isClass() {
|
|
return (access_flags & Constants.ACC_INTERFACE) == 0;
|
|
}
|
|
|
|
/** @return returns either HEAP (generated), FILE, or ZIP
|
|
*/
|
|
public final byte getSource() {
|
|
return source;
|
|
}
|
|
|
|
/********************* New repository functionality *********************/
|
|
|
|
/**
|
|
* Gets the ClassRepository which holds its definition. By default
|
|
* this is the same as SyntheticRepository.getInstance();
|
|
*/
|
|
public com.sun.org.apache.bcel.internal.util.Repository getRepository() {
|
|
return repository;
|
|
}
|
|
|
|
/**
|
|
* Sets the ClassRepository which loaded the JavaClass.
|
|
* Should be called immediately after parsing is done.
|
|
*/
|
|
public void setRepository(com.sun.org.apache.bcel.internal.util.Repository repository) {
|
|
this.repository = repository;
|
|
}
|
|
|
|
/** Equivalent to runtime "instanceof" operator.
|
|
*
|
|
* @return true if this JavaClass is derived from teh super class
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* @return true, if clazz is an implementation of interface inter
|
|
*/
|
|
public boolean implementationOf(JavaClass inter) {
|
|
if(!inter.isInterface()) {
|
|
throw new IllegalArgumentException(inter.getClassName() + " is no interface");
|
|
}
|
|
|
|
if(this.equals(inter)) {
|
|
return true;
|
|
}
|
|
|
|
JavaClass[] super_interfaces = getAllInterfaces();
|
|
|
|
for(int i=0; i < super_interfaces.length; i++) {
|
|
if(super_interfaces[i].equals(inter)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return the superclass for this JavaClass object, or null if this
|
|
* is java.lang.Object
|
|
*/
|
|
public JavaClass getSuperClass() {
|
|
if("java.lang.Object".equals(getClassName())) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return repository.loadClass(getSuperclassName());
|
|
} catch(ClassNotFoundException e) {
|
|
System.err.println(e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return list of super classes of this class in ascending order, i.e.,
|
|
* java.lang.Object is always the last element
|
|
*/
|
|
public JavaClass[] getSuperClasses() {
|
|
JavaClass clazz = this;
|
|
ClassVector vec = new ClassVector();
|
|
|
|
for(clazz = clazz.getSuperClass(); clazz != null;
|
|
clazz = clazz.getSuperClass())
|
|
{
|
|
vec.addElement(clazz);
|
|
}
|
|
|
|
return vec.toArray();
|
|
}
|
|
|
|
/**
|
|
* Get interfaces directly implemented by this JavaClass.
|
|
*/
|
|
public JavaClass[] getInterfaces() {
|
|
String[] interfaces = getInterfaceNames();
|
|
JavaClass[] classes = new JavaClass[interfaces.length];
|
|
|
|
try {
|
|
for(int i = 0; i < interfaces.length; i++) {
|
|
classes[i] = repository.loadClass(interfaces[i]);
|
|
}
|
|
} catch(ClassNotFoundException e) {
|
|
System.err.println(e);
|
|
return null;
|
|
}
|
|
|
|
return classes;
|
|
}
|
|
|
|
/**
|
|
* Get all interfaces implemented by this JavaClass (transitively).
|
|
*/
|
|
public JavaClass[] getAllInterfaces() {
|
|
ClassQueue queue = new ClassQueue();
|
|
ClassVector vec = new ClassVector();
|
|
|
|
queue.enqueue(this);
|
|
|
|
while(!queue.empty()) {
|
|
JavaClass clazz = queue.dequeue();
|
|
|
|
JavaClass souper = clazz.getSuperClass();
|
|
JavaClass[] interfaces = clazz.getInterfaces();
|
|
|
|
if(clazz.isInterface()) {
|
|
vec.addElement(clazz);
|
|
} else {
|
|
if(souper != null) {
|
|
queue.enqueue(souper);
|
|
}
|
|
}
|
|
|
|
for(int i = 0; i < interfaces.length; i++) {
|
|
queue.enqueue(interfaces[i]);
|
|
}
|
|
}
|
|
|
|
return vec.toArray();
|
|
}
|
|
}
|