home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgLangD.iso
/
VCAFE.3.0A
/
Main.bin
/
DTClass.java
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Java Source
|
1998-12-04
|
87.6 KB
|
2,541 lines
/*
* Copyright 1998 Symantec Corporation, All Rights Reserved.
*/
package com.symantec.itools.vcafe.openapi.dtreflect;
import java.lang.reflect.*;
import java.util.*;
import java.io.*;
import com.symantec.itools.vcafe.openapi.VisualCafe;
import com.symantec.itools.vcafe.openapi.VisualProject;
import com.symantec.itools.vcafe.openapi.Range;
import com.symantec.itools.vcafe.openapi.ProjectFile;
import com.symantec.itools.vcafe.openapi.SourceFile;
/**
* DTClass is the root class for the dtreflect API for Design Time Reflection.
*
* <p>Design Time Reflection provides services analogous to the Java
* reflection API, based upon parse information gathered
* by Visual Cafe. Thus, classes reflected upon need not be compiled
* or in a compilable state.
*
* <p>There are several significant differences between the dtreflect and
* reflect packages:
*
* <p>dtreflect usually does not throw an exception when a
* class, method, field, etc. cannot be found. Instead, the API uniformly
* returns null, allowing simpler caller code. The nonNull()
* methods allow callers to quickly and conveniently convert null
* returns to NullPointerException if this is desired.
*
* <p>The DTListener interface combined with the notify()/notifyAll()
* methods allows a dtreflect user to listen to specific/all classes
* for changes. The validate() method of a dtreflect object verifies
* that the information in the object is up-to-date. validate() should
* also be called when a dtreflect object is serialized in, as the underlying
* class, method, etc. may no longer exist or may have changed.
*
* <p>To avoid confusion, the forName() method is renamed findClass().
* <p>Since classes may be unique to projects and different classes
* with the same name may exist in different projects, findClass() requires a
* Project argument. The findSystemClass() method returns information
* about classes that are common to all open projects.
*
* <p> dtreflect objects obtain their information from a parser for project files
* and from compiled code for files outside the project. Because a parser
* is more forgiving than the compiler, some information may be incomplete
* or innacurate. In particular, variable, method return and argument types may
* not be fully qualified. Each object has a validate interface that verifies
* that all types used by the object could be used to create valid DTClass objects.
*/
public class DTClass implements Serializable
{
static final long serialVersionUID = 8946402831128459801L;
static final boolean DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS = false;
/**
* Converts the object to a string. The string representation is the
* string <code>"class"</code> or <code>"interface"</code> followed
* by a space and then the fully qualified name of the class.
* If this DTClass object represents a primitive type,
* returns the name of the primitive type.
*
* @return a string representation of this class object.
*/
public String toString() {
return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+ getName();
}
/**
* Returns the <code>DTClass</code> object associated with the class
* with the given string name.
*
* <p>Given a project and the fully-qualified name for a class or interface, this
* method attempts to create a DTClass object for the class. If it
* succeeds, returns the DTClass object representing the class. If
* it fails, the method returns null.
*
* <p>For example, the following code fragment returns the runtime
* <code>DTClass</code> descriptor for the class named
* <code>com.user.MyClass</code>:
* <ul><code>
* DTClass t = DTClass.findClass(aproject, "com.user.MyClass")
* </code></ul>
*
* <p>Array classes are represented using standard notation, e.g.,
* "java.lang.String[]" and "byte[][]".
*
* <p>If the className names a system class or the project is null,
* findClass() is the same as findSystemClass(). NB: A project must
* be specified for a component library class, which is not in the
* system classpath.
*
* @param project the project context that defines the class.
* @param className the fully qualified name of the desired class.
* @return the <code>DTClass</code> descriptor for the class with the
* specified name. Returns null if class not found.
*
* @see com.symantec.itools.vcafe.openapi.VisualProject#getDTClassObject()
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTClass#findSystemClass()
*/
public static DTClass findClass(VisualProject project, String className) {
if (project != null)
return project.getDTClassObject(className);
return DTClass.findSystemClass(className);
}
/**
* Returns the <code>DTClass</code> object associated with the class
* with the given string name.
*
* <p>The class must be loadable from the system classpath.
*
* <p>For example, the following code fragment returns the runtime
* <code>DTClass</code> descriptor for the standard String class:
* <ul><code>
* DTClass t = DTClass.findSystemClass("java.lang.String")
* </code></ul>
*
* @param className the fully qualified name of the desired class.
* @return the <code>DTClass</code> descriptor for the class with the
* specified name. Returns null if class not found.
*/
public static DTClass findSystemClass(String className) {
if (className.charAt(0) == '[') // "[Ljava.lang.Object;" format!
className = classnameToString(className); // Convert it to "java.lang.Object[]" format
// Check the cache
DTClass systemClass = (DTClass) systemClassHash.get(className);
if (systemClass != null)
return systemClass;
int dim = scanDim(className);
String baseName = (dim > 0) ? componentName(className) : className;
// first check primitives
systemClass = getPrimitiveClass(baseName);
if (systemClass != null) {
if (dim != 0)
systemClass = new DTClass(systemClass, dim);
}
// otherwise may be component class
else {
try {
Class clazz = Class.forName(getClassname(className, dim));
systemClass = new DTClass(null, className, clazz, dim, false, false);
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: findSystemClass(" + baseName + ") threw " + e);
e.printStackTrace();
}
}
}
// Cache it
return DTClass.registerSystemClass(systemClass);
}
private static DTClass registerClass(DTClass dtClass, boolean replace) {
if (dtClass.project != null)
return DTClass.registerProjectClass(dtClass, replace);
return DTClass.registerSystemClass(dtClass);
}
private static DTClass registerProjectClass(DTClass dtClass, boolean replace) {
if (dtClass == null) return null;
return (DTClass) ((symantec.itools.vcafe.visual.PVisualProject)dtClass.project).registerDTClassObject(dtClass, replace);
}
private static DTClass registerSystemClass(DTClass systemClass) {
if (systemClass != null)
systemClassHash.put(systemClass.name, systemClass);
return systemClass;
}
/**
* Return true if class is in a project, as opposed to component
* library or system classpath.
*/
public boolean isProjectClass() {
return projectClass;
}
/**
* Return classloader for this class (project's classloader).
*/
public ClassLoader getProjectLoader() {
if (project == null) return null;
return project.getClassLoader();
}
/**
* Determines if the class or interface
* represented by this DTClass object is either the same as, or is a
* superclass or superinterface of, the class or interface
* represented by the specified DTClass parameter. It returns true
* if so, false otherwise. If this DTClass object represents a
* primitive type, returns true if the specified DTClass parameter
* is exactly this DTClass object, false otherwise.
*
* <p>Specifically, this method tests whether the type represented
* by the specified DTClass parameter can be converted to the type
* represented by this DTClass object via an identity conversion or
* via a widening reference conversion. See <em>The Java Language
* Specification</em>, sections 5.1.1 and 5.1.4 , for details.
*
* <p>This method works the same as Class.isAssignableFrom(), which
* means it is not accurate for primitive classes.
* @see isAssignable
* @exception NullPointerException if the specified DTClass parameter is null.
*/
public boolean isAssignableFrom(DTClass cls) {
if (this == VoidType || cls == VoidType || this == NullType) return false;
if (this == AnyType || cls == AnyType) return true;
if (cls == NullType)
return !primitive;
if (primitive || cls.primitive)
return this == cls;
else
return equals(cls) || cls.isSuperclass(this);
}
/**
* Determines if a value of a specified type can be assigned
* without explicit conversion or casting to a value of this type.
*
* <p>Differs from isAssignableFrom() in its treatment of primitive
* classes.
*
* <p>Specifically, this method tests whether the type represented
* by the specified DTClass parameter can be converted to the type
* represented by this DTClass object via an identity conversion,
* a widening reference conversion or a widening numeric conversion.
* See <em>The Java Language Specification</em>, sections 5.1.1, 5.1.4
* and 5.2, for details.
*
* <p>Note that a particular numeric constant value might be assignable
* via a narrowing conversion if its value fits in the destination
* type without loss of information, e.g., byte b = 52; where the
* constant 52 is an int. This must be tested using isAssignable(int)
* with the specific value.
*
* @exception NullPointerException if the specified DTClass parameter is null.
*/
public boolean isAssignable(DTClass cls) {
boolean assignable;
if (this == VoidType || cls == VoidType || this == NullType) {
assignable = false;
} else if (this == AnyType || cls == AnyType) {
assignable = true;
} else if (primitive) {
if (this == cls) {
assignable = true;
} else if (cls == ByteType) {
assignable = (this == ShortType || this == IntegerType || this == LongType || this == FloatType || this == DoubleType);
} else if (cls == ShortType) {
assignable = (this == IntegerType || this == LongType || this == FloatType || this == DoubleType);
} else if (cls == IntegerType) {
assignable = (this == LongType || this == FloatType || this == DoubleType);
} else if (cls == LongType) {
assignable = (this == FloatType || this == DoubleType);
} else if (cls == FloatType) {
assignable = (this == DoubleType);
} else {
assignable = false;
}
} else if (cls.primitive) {
assignable = cls == NullType;
} else {
assignable = equals(cls) || cls.isSuperclass(this);
}
return assignable;
}
/**
* Determines if a specified constant value can be assigned
* without explicit conversion or casting to a value of this type.
*
* <p>A particular numeric constant value is assignable if its value
* fits in the destination
* type without loss of information, e.g., byte b = 52; where the
* constant 52 is an int.
*/
public boolean isAssignable(long value) {
if (this == AnyType) return true;
return (this == ByteType &&
(value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)) ||
(this == ShortType &&
(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)) ||
(this == IntegerType &&
(value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE)) ||
(this == LongType);
}
/**
* Determines if the class or interface
* represented by this DTClass object implements or extends
* the class or interface represented by the specified DTClass parameter.
* It returns true if so, false otherwise. If this DTClass object represents a
* primitive type, returns true if the specified DTClass parameter
* is exactly this DTClass object, false otherwise.
*
* <p>For non-primitive types, returns what the implements operator
* would for corresponding Class objects.
*
* <p>This is the opposite of isAssignableFrom().
*
* @exception NullPointerException if the specified DTClass parameter is null.
*/
public boolean isImplementationOf(DTClass cls) {
return cls.isAssignableFrom(this);
}
/**
* Determines if the specified DTClass object represents an interface type.
*
* @return <code>true</code> if this object represents an interface;
* <code>false</code> otherwise.
*/
public boolean isInterface() {
return Modifier.isInterface(modifier);
}
/**
* If this DTClass object represents an array type, returns true,
* otherwise returns false.
*/
public boolean isArray() {
return dim != 0;
}
/**
* If this DTClass object represents an array type, returns the number of array dimensions,
* otherwise returns false.
*/
public int getDimensions() {
return dim;
}
/**
* Return an array with the bounds of each array dimension
* for the current class.The length of the returned int array
* is equal to the number of dimensions of the class.
* Returns empty array if the class is not an array.
*/
public int[] getBounds() {
int[] array = new int[dim];
if (dim > 0) {
int n = name.length()-1;
char[] chars = name.toCharArray();
for (int i = dim-1; i >=0; i--) {
int idim = 0, mul = 1;
char c;
while ((c = chars[--n]) >= '0' && c <= '9') {
idim += ((int)c - (int)'0') * mul;
mul *= 10;
}
--n;
array[i] = idim;
}
}
return array;
}
/**
* Determines if the specified DTClass object represents a primitive Java
* type.
*
* <p>There are nine predefined DTClass objects to represent the eight
* primitive Java types and void. These are created by the DTReflection API,
* and have the same names as the primitive types
* that they represent, namely boolean, byte, char, short, int,
* long, float, and double, and void.
*
* <p>These objects may only be accessed via the following public
* static final variables, and are the only DTClass objects for
* which this method returns true.
*
* com.symantec.itools.vcafe.openapi.dtreflect.DTClass.BooleanType
* com.symantec.itools.vcafe.openapi.dtreflect.DTClass.CharacterType
* com.symantec.itools.vcafe.openapi.dtreflect.DTClass.ByteType
* com.symantec.itools.vcafe.openapi.dtreflect.DTClass.ShortType
* com.symantec.itools.vcafe.openapi.dtreflect.DTClass.IntegerType
* com.symantec.itools.vcafe.openapi.dtreflect.DTClass.LongType
* com.symantec.itools.vcafe.openapi.dtreflect.DTClass.FloatType
* com.symantec.itools.vcafe.openapi.dtreflect.DTClass.DoubleType
* com.symantec.itools.vcafe.openapi.dtreflect.DTClass.VoidType
*/
public boolean isPrimitive() {
return primitive;
}
// Helpful constants. getPrimitiveClass() and getDTClassObject() always
// return these references for "boolean", "char", etc.
public static final DTClass BooleanType = DTClass.getPrimitiveClass("boolean");
public static final DTClass CharacterType = DTClass.getPrimitiveClass("char");
public static final DTClass ByteType = DTClass.getPrimitiveClass("byte");
public static final DTClass ShortType = DTClass.getPrimitiveClass("short");
public static final DTClass IntegerType = DTClass.getPrimitiveClass("int");
public static final DTClass LongType = DTClass.getPrimitiveClass("long");
public static final DTClass FloatType = DTClass.getPrimitiveClass("float");
public static final DTClass DoubleType = DTClass.getPrimitiveClass("double");
public static final DTClass VoidType = DTClass.getPrimitiveClass("void");
// A type that is assignable to/from any type
public static final DTClass AnyType = DTClass.getPrimitiveClass("*");
// A type that is assignable to any non-primitive type
public static final DTClass NullType = DTClass.getPrimitiveClass("null");
/**
* Returns the fully-qualified name of the type (class, interface,
* array, or primitive) represented by this DTClass object, as a String.
*
* <p>Array classes are named using standard notation, e.g.,
* "java.lang.String[]" and "byte[][]".
*/
public String getName() {
return name;
}
/**
* Returns the package of the type (class, interface, array, or primitive) represented
* by this DTClass object as a String, or null if the class isn't in a package
*/
public String getPackageName() {
return packageName;
}
/**
* Returns the unqualified name (package is excluded) of the type (class, interface,
* array, or primitive) represented by this DTClass object, as a String.
*
* <p>Array classes are named using standard notation, e.g.,
* "String[]" and "byte[][]".
*/
public String getUnqualifiedName() {
if (packageName == null || packageName.length() == 0) return name;
return name.substring(packageName.length() + 1);
}
/**
* Returns true if the argument object is a superclass of the current class.
*/
public boolean isSuperclass(DTClass superClass) {
if (primitive || superClass.primitive) return false;
// The both have to be arrays of the same dimension or neither can be arrays
// This can be checked by comparing dimension directly
if (dim != superClass.dim)
return false;
boolean bIsSuperclass = false;
// Look in our hash of checked superclasses, before checking deep.
if (checkedSuperclasses != null) {
Boolean b = (Boolean) checkedSuperclasses.get(superClass);
if (b != null)
return b.booleanValue();
} else {
checkedSuperclasses = new Hashtable();
}
// Determine if superClass is a super class of this class
if (!projectClass) {
try {
Class from = loadClass();
Class to = superClass.loadClass();
bIsSuperclass = to.isAssignableFrom(from);
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".isSuperclass(" + superClass.name + ") threw " + e);
e.printStackTrace();
}
}
} else {
bIsSuperclass = isSuperClass0(superClass);
}
// Cache the lookup value
checkedSuperclasses.put(superClass, new Boolean(bIsSuperclass));
return bIsSuperclass;
}
/**
* If this object represents any class other than the class
* </code>Object</code>, then the object that represents the superclass
* of that class is returned.
*
* <p>If this object is the one that represents the class
* </code>Object</code> or this object represents an interface,
* </code>null</code> is returned.
*
* @return the superclass of the class represented by this object.
*/
public DTClass getSuperclass() {
if (primitive)
return null;
if (gotSuperClass)
return superClass;
if (!projectClass) {
try {
Class clazz = loadComponentClass();
Class superClazz = clazz.getSuperclass();
superClass = new DTClass(project, superClazz.getName()+arrayPart(name), superClazz, scanDim(name), false, false);
superClass = DTClass.registerClass(superClass, false /*!replace*/);
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getSuperclass() threw " + e);
e.printStackTrace();
}
}
} else {
superClass = DTClass.registerProjectClass(getSuperclass0(), false/*!replace*/);
}
gotSuperClass = true;
return superClass;
}
/**
* Determines the interfaces implemented by the class or interface
* represented by this object.
*
* <p>If this object represents a class, the return value is an array
* containing objects representing all interfaces implemented by the
* class. The order of the interface objects in the array corresponds
* to the order of the interface names in the </code>implements</code>
* clause of the declaration of the class represented by this object.
*
* <p>If this object represents an interface, the array contains
* objects representing all interfaces extended by the interface. The
* order of the interface objects in the array corresponds to the
* order of the interface names in the </code>extends</code> clause of
* the declaration of the interface represented by this object.
*
* <p>If the class or interface implements no interfaces, the method
* returns an array of length 0.
*
* @return an array of interfaces implemented by this class.
*/
public DTClass[] getInterfaces() {
if (primitive || isArray()) return new DTClass[0];
if (!projectClass) {
try {
Class clazz = loadClass();
Class[] ifaces = clazz.getInterfaces();
return classToDTClassArray(ifaces);
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getInterfaces() threw " + e);
e.printStackTrace();
}
}
return new DTClass[0];
}
DTClass[] interfaces = getInterfaces0();
for (int i = 0; i < interfaces.length; i++)
interfaces[i] = DTClass.registerProjectClass(interfaces[i], false /*!replace*/);
return interfaces;
}
/**
* If this class represents an array type, returns the DTClass
* object representing the component type of the array; otherwise
* returns null.
*/
public DTClass getComponentType() {
return isArray() ? findClass(project, getComponentName()) : null;
}
/**
* If this class represents an array type, returns the name
* of the component type; otherwise
* returns the class name.
*/
public String getComponentName() {
if (dim > 0)
return componentName(name);
else
return name;
}
protected static int scanDim(String className) {
int i, dim = 0, n = className.length();
for (i = n-1; i >= 0; i--) {
char c = className.charAt(i);
if (c == '[') dim++;
if (!(c == '[' || c == ']' || (c >= '0' && c <= '9')))
break;
}
return dim;
}
protected static String componentName(String str) {
int len = str.indexOf('[');
if (len >= 0)
return str.substring(0,len);
return str;
}
static String arrayPart(String str) {
int len = str.indexOf('[');
if (len >= 0)
return str.substring(len);
return "";
}
/**
* Returns the Java language modifiers for this class or
* interface, encoded in an integer. The modifiers consist of the
* Java Virtual Machine's constants for public, protected,
* private, final, and interface; they should be decoded using the
* methods of class Modifier.
*
* <p>The modifier encodings are defined in <em>The Java Virtual
* Machine Specification</em>, table 4.1.
*
* @see java.lang.reflect.Modifier
*/
public int getModifiers() {
return modifier;
}
/**
* If the class or interface represented by this DTClass object is
* a member of another class, returns the DTClass object
* representing the class of which it is a member (its
* <em>declaring class</em>). Returns null if this class or
* interface is not a member of any other class.
*
*/
public DTClass getDeclaringClass(){
if (!(primitive || isArray())) {
if (projectClass) {
return DTClass.registerProjectClass(getDeclaringClass0(), false /*!replace*/);
}
try {
Class clazz = loadClass();
DTClass dtClass = new DTClass(project, clazz.getDeclaringClass());
return DTClass.registerClass(dtClass, false /*!replace*/);
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getDeclaringClass() threw " + e);
e.printStackTrace();
}
}
}
return null;
}
/**
* Returns an array containing DTClass objects representing all the
* public classes and interfaces that are members of the class
* represented by this DTClass object. This includes public class
* and interface members inherited from superclasses and public
* class and interface members declared by the class. Returns an
* array of length 0 if the class has no public member classes or
* interfaces, or if this DTClass object represents a primitive
* type.
*
*/
public DTClass[] getClasses() {
return getClasses(Member.PUBLIC);
}
/**
* Returns an array containing DTField objects reflecting all the
* accessible public fields of the class or interface represented
* by this DTClass object. Returns an array of length 0 if the
* class or interface has no accessible public fields, or if it
* represents an array type or a primitive type.
*
* <p>Specifically, if this DTClass object represents a class,
* returns the public fields of this class and of all its
* superclasses. If this DTClass object represents an interface,
* returns the fields of this interface and of all its
* superinterfaces. If this DTClass object represents an array type
* or a primitive type, returns an array of length 0.
*
* <p>The implicit length field for array types is not reflected
* by this method. User code should use the methods of class Array
* to manipulate arrays.
*
* <p>See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTField
*/
public DTField[] getFields() {
synchronized (cacheFlusher) {
if (publicFields == null)
publicFields = getFields(Member.PUBLIC);
cacheFlusher.scheduleCacheFlush(this);
return publicFields;
}
}
/**
* Returns an array containing DTMethod objects reflecting all the
* public <em>member</em> methods of the class or interface
* represented by this DTClass object, including those declared by
* the class or interface and and those inherited from
* superclasses and superinterfaces. Returns an array of length 0
* if the class or interface has no public member methods.
*
* <p>See <em>The Java Language Specification</em>, sections 8.2
* and 8.4.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTMethod
*/
public DTMethod[] getMethods() {
return getMethods(Member.PUBLIC);
}
/**
* Returns an array containing DTConstructor objects reflecting
* all the public constructors of the class represented by this
* DTClass object. An array of length 0 is returned if the class
* has no public constructors.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTConstructor
*/
public DTConstructor[] getConstructors() {
return getConstructors(Member.PUBLIC);
}
/**
* Returns a DTField object that reflects the specified public
* member field of the class or interface represented by
* this DTClass object. The name parameter is a String specifying
* the simple name of the desired field.
*
* <p>The field to be reflected is located by searching all the
* member fields of the class or interface represented by this
* DTClass object for a public field with the specified name.
*
* <p>See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
*
* @return field or null if no such field.
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTField
*/
public DTField getField(String name) {
return getField(name, Member.PUBLIC);
}
/**
* Returns a DTMethod object that reflects the specified public
* member method of the class or interface represented by this
* DTClass object. The name parameter is a String specifying the
* simple name the desired method, and the parameterTypes
* parameter is an array of DTClass objects that identify the
* method's formal parameter types, in declared order.
*
* <p>The method to reflect is located by searching all the member
* methods of the class or interface represented by this DTClass
* object for a public method with the specified name and exactly
* the same formal parameter types.
*
* <p>See <em>The Java Language Specification</em>, sections 8.2
* and 8.4.
*
* @return method or null if no such method.
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTMethod
*/
public DTMethod getMethod(String name, DTClass[] parameterTypes) {
return getMethod(name, parameterTypes, Member.PUBLIC);
}
/**
* Returns a DTMethod object that reflects the specified public
* member method of the class or interface represented by this
* DTClass object. The name parameter is a String specifying the
* simple name the desired method, and the parameterTypeNames
* parameter is an array of String objects that identify the
* method's formal parameter types, in declared order.
*
* <p>The method to reflect is located by searching all the member
* methods of the class or interface represented by this DTClass
* object for a public method with the specified name and exactly
* the same formal parameter types.
*
* <p>See <em>The Java Language Specification</em>, sections 8.2
* and 8.4.
*
* @return method or null if no such method.
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTMethod
*/
public DTMethod getMethod(String name, String[] parameterTypeNames) {
return getMethod(name, parameterTypeNames, Member.PUBLIC);
}
/**
* Returns a DTConstructor object that reflects the specified public
* constructor of the class represented by this DTClass object. The
* parameterTypes parameter is an array of DTClass objects that
* identify the constructor's formal parameter types, in declared
* order.
*
* <p>The constructor to reflect is located by searching all the
* constructors of the class represented by this DTClass object for
* a public constructor with the exactly the same formal parameter
* types.
*
* @return constructor or null if no such constructor.
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTConstructor
*/
public DTConstructor getConstructor(DTClass[] parameterTypes) {
return getConstructor(parameterTypes, Member.PUBLIC);
}
/**
* Returns a DTConstructor object that reflects the specified public
* constructor of the class represented by this DTClass object. The
* parameterTypeNames parameter is an array of String objects that
* identify the constructor's formal parameter types, in declared
* order.
*
* <p>The constructor to reflect is located by searching all the
* constructors of the class represented by this DTClass object for
* a public constructor with the exactly the same formal parameter
* types.
*
* @return constructor or null if no such constructor.
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTConstructor
*/
public DTConstructor getConstructor(String[] parameterTypeNames) {
return getConstructor(parameterTypeNames, Member.PUBLIC);
}
/**
* Returns an array of DTClass objects reflecting all the classes
* and interfaces declared as members of the class represented by
* this DTClass object. This includes public, protected, default
* (package) access, and private classes and interfaces declared
* by the class, but excludes inherited classes and interfaces.
* Returns an array of length 0 if the class declares no classes
* or interfaces as members, or if this DTClass object represents a
* primitive type.
*
*/
public DTClass[] getDeclaredClasses() {
return getClasses(Member.DECLARED);
}
/**
* Returns an array of DTField objects reflecting all the fields
* declared by the class or interface represented by this DTClass
* object. This includes public, protected, default (package)
* access, and private fields, but excludes inherited
* fields. Returns an array of length 0 if the class or interface
* declares no fields, or if this DTClass object represents a
* primitive type.
*
* See <em>The Java Language Specification</em>, sections 8.2 and
* 8.3.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTField
*/
public DTField[] getDeclaredFields() {
synchronized (cacheFlusher) {
if (declaredFields == null)
declaredFields = getFields(Member.DECLARED);
cacheFlusher.scheduleCacheFlush(this);
return declaredFields;
}
}
/**
* Returns an array of DTMethod objects reflecting all the methods
* declared by the class or interface represented by this DTClass
* object. This includes public, protected, default (package)
* access, and private methods, but excludes inherited
* methods. Returns an array of length 0 if the class or interface
* declares no methods, or if this DTClass object represents a
* primitive type.
*
* <p>See <em>The Java Language Specification</em>, section 8.2.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTMethod
*/
public DTMethod[] getDeclaredMethods() {
return getMethods(Member.DECLARED);
}
/**
* Returns an array of DTConstructor objects reflecting all the
* constructors declared by the class represented by this DTClass
* object. These are public, protected, default (package) access,
* and private constructors. Returns an array of length 0 if this
* DTClass object represents an interface or a primitive type.
*
* <p>See <em>The Java Language Specification</em>, section 8.2.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTConstructor
*/
public DTConstructor[] getDeclaredConstructors() {
return getConstructors(Member.DECLARED);
}
/**
* Returns a DTField object that reflects the specified declared
* field of the class or interface represented by this DTClass
* object. The name parameter is a String that specifies the
* simple name of the desired field.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTField
*/
public DTField getDeclaredField(String name) {
return getField(name, Member.DECLARED);
}
/**
* Returns a DTMethod object that reflects the specified declared
* method of the class or interface represented by this DTClass
* object. The name parameter is a String that specifies the
* simple name of the desired method, and the parameterTypes
* parameter is an array of DTClass objects that identify the
* method's formal parameter types, in declared order.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTMethod
*/
public DTMethod getDeclaredMethod(String name, DTClass[] parameterTypes) {
return getMethod(name, parameterTypes, Member.DECLARED);
}
/**
* Returns a DTMethod object that reflects the specified declared
* method of the class or interface represented by this DTClass
* object. The name parameter is a String that specifies the
* simple name of the desired method, and the parameterTypeNames
* parameter is an array of DTClass objects that identify the
* method's formal parameter types, in declared order.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTMethod
*/
public DTMethod getDeclaredMethod(String name, String[] parameterTypeNames) {
return getMethod(name, parameterTypeNames, Member.DECLARED);
}
/**
* Returns a DTConstructor object that reflects the specified declared
* constructor of the class or interface represented by this DTClass
* object. The parameterTypes parameter is an array of DTClass
* objects that identify the constructor's formal parameter types,
* in declared order.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTConstructor
*/
public DTConstructor getDeclaredConstructor(DTClass[] parameterTypes) {
return getConstructor(parameterTypes, Member.DECLARED);
}
/**
* Returns a DTConstructor object that reflects the specified declared
* constructor of the class or interface represented by this DTClass
* object. The parameterTypeNames parameter is an array of String
* objects that identify the constructor's formal parameter types,
* in declared order.
*
* @see com.symantec.itools.vcafe.openapi.dtreflect.DTConstructor
*/
public DTConstructor getDeclaredConstructor(String[] parameterTypeNames) {
return getConstructor(parameterTypeNames, Member.DECLARED);
}
/**
* Returns an array of DTMethod objects reflecting all the methods
* in the class or interface represented by this DTClass object that
* can be seen by accessibleBy.
* This includes all public methods, protected methods if accessibleBy is
* a subclass of this class (and they represent the same object), and
* methods with package access if accessibleBy is in the same package as this class.
* Inherited methods are included.
*
* Returns an array of length 0 if the class or interface declares no methods,
* or if this DTClass object represents a primitive type.
*
* @see getMethods
*/
public DTMethod[] getAccessibleMethods(DTClass accessibleByClass, boolean sameObject) {
if (!(primitive || isArray())) {
synchronized(cacheFlusher) {
// See if the list of accessible methods is in our toplevel cache
// (what we last searched for)
String accessibleMethodsKey = accessibleByClass.name + sameObject;
if (allAccessibleMethods != null && !accessibleMethodsKey.equals(allAccessibleMethodsKey)) {
allAccessibleMethods = null;
}
// Not in the toplevel cache. Walk the hierarchy to build the list
if (allAccessibleMethods == null) {
// Get the (filtered) list of methods
Hashtable dtMethodsHash = new Hashtable();
Vector dtMethodsVector = new Vector(100);
AccessibleMemberFilter accessFilter = new AccessibleMemberFilter(accessibleMethodsKey, accessibleByClass, sameObject);
getAccessibleMethodsImpl(accessFilter, dtMethodsHash, dtMethodsVector);
// Build an array of the methods
dtMethodsHash = null;
allAccessibleMethodsKey = accessibleMethodsKey;
allAccessibleMethods = new DTMethod[dtMethodsVector.size()];
dtMethodsVector.copyInto(allAccessibleMethods);
}
cacheFlusher.scheduleCacheFlush(this);
return allAccessibleMethods;
}
}
return new DTMethod[0];
}
// Worker function to walk down the hierarchy getting the accessible methods
private void getAccessibleMethodsImpl(AccessibleMemberFilter accessFilter, Hashtable dtMethodsHash, Vector dtMethodsVector) {
DTMethod[] dtMethods;
//
// First, get the list of ALL accessible methods at this level
//
// See if the list of accessible methods is in our cache
if (accessibleMethods == null) {
accessibleMethods = new Hashtable();
dtMethods = null;
} else {
dtMethods = (DTMethod[])accessibleMethods.get(accessFilter.membersKey);
}
// Not in the cache. Look 'em up.
if (dtMethods == null) {
if (projectClass) {
dtMethods = getAccessibleMethods0(accessFilter.accessibleByClass.name, accessFilter.isSameObject);
} else {
dtMethods = getMethods1(Member.DECLARED, (accessFilter.isSameClass ? null : accessFilter));
}
// Cache the methods we found (If we didn't find any, remember that too)
if (dtMethods == null)
dtMethods = new DTMethod[0];
accessibleMethods.put(accessFilter.membersKey, dtMethods);
}
//
// Next, filter out duplicates by only adding new methods to the Hashtable & Vector
//
for (int i = 0; i < dtMethods.length; i++) {
DTMethod dtMethod = dtMethods[i];
String methodName = dtMethod.toShortString();
if (!dtMethodsHash.containsKey(methodName)) {
dtMethodsHash.put(methodName, dtMethod);
dtMethodsVector.addElement(dtMethod);
}
}
//
// Now, get the superclass's accessible methods
//
DTClass superClass = this.getSuperclass();
if (superClass != null) {
accessFilter.adjustLevel(superClass);
superClass.getAccessibleMethodsImpl(accessFilter, dtMethodsHash, dtMethodsVector);
}
}
/**
* Returns an array of DTField objects reflecting all the fields
* in the class or interface represented by this DTClass object that
* can be seen by accessibleBy.
* This includes all public fields, protected fields if accessibleBy is
* a subclass of this class (and they represent the same object), and
* fields with package access if accessibleBy is in the same package as this class.
* Inherited fields are included.
*
* Returns an array of length 0 if the class or interface declares no fields,
* or if this DTClass object represents a primitive type.
*
* @see getFields
*/
public DTField[] getAccessibleFields(DTClass accessibleByClass, boolean sameObject) {
if (!(primitive || isArray())) {
synchronized(cacheFlusher) {
// See if the list of accessible fields is in our toplevel cache
// (what we last searched for)
String accessibleFieldsKey = accessibleByClass.name + sameObject;
if (allAccessibleFields != null && !accessibleFieldsKey.equals(allAccessibleFieldsKey)) {
allAccessibleFields = null;
}
// Not in the toplevel cache. Walk the hierarchy to build the list
if (allAccessibleFields == null) {
// Get the (filtered) list of fields
Hashtable dtFieldsHash = new Hashtable();
Vector dtFieldsVector = new Vector(100);
AccessibleMemberFilter accessFilter = new AccessibleMemberFilter(accessibleFieldsKey, accessibleByClass, sameObject);
getAccessibleFieldsImpl(accessFilter, dtFieldsHash, dtFieldsVector);
// Build an array of the fields
dtFieldsHash = null;
allAccessibleFieldsKey = accessibleFieldsKey;
allAccessibleFields = new DTField[dtFieldsVector.size()];
dtFieldsVector.copyInto(allAccessibleFields);
}
cacheFlusher.scheduleCacheFlush(this);
return allAccessibleFields;
}
}
return new DTField[0];
}
// Worker function to walk down the hierarchy getting the accessible fields
private void getAccessibleFieldsImpl(AccessibleMemberFilter accessFilter, Hashtable dtFieldsHash, Vector dtFieldsVector) {
DTField[] dtFields;
//
// First, get the list of ALL accessible fields at this level
//
// See if the list of accessible fields is in our cache
if (accessibleFields == null) {
accessibleFields = new Hashtable();
dtFields = null;
} else {
dtFields = (DTField[])accessibleFields.get(accessFilter.membersKey);
}
// Not in the cache. Look 'em up.
if (dtFields == null) {
if (projectClass) {
dtFields = getAccessibleFields0(accessFilter.accessibleByClass.name, accessFilter.isSameObject);
} else {
dtFields = getFields1(Member.DECLARED, (accessFilter.isSameClass ? null : accessFilter));
}
// Cache the fields we found (If we didn't find any, remember that too)
if (dtFields == null)
dtFields = new DTField[0];
accessibleFields.put(accessFilter.membersKey, dtFields);
}
//
// Next, filter out duplicates by only adding new fields to the Hashtable & Vector
//
for (int i = 0; i < dtFields.length; i++) {
DTField dtField = dtFields[i];
if (!dtFieldsHash.containsKey(dtField.name)) {
dtFieldsHash.put(dtField.name, dtField);
dtFieldsVector.addElement(dtField);
}
}
//
// Now, get the superclass's accessible fields
//
DTClass superClass = this.getSuperclass();
if (superClass != null) {
accessFilter.adjustLevel(superClass);
superClass.getAccessibleFieldsImpl(accessFilter, dtFieldsHash, dtFieldsVector);
}
}
class AccessibleMemberFilter implements AccessFilter {
String membersKey;
DTClass accessibleByClass;
String accessibleByPackage;
boolean isSameObject;
boolean isSameClass;
boolean isSuperclass;
boolean allowPackage;
boolean allowProtected;
AccessibleMemberFilter(String key, DTClass accessibleByClass, boolean isSameObject) {
this.membersKey = key;
this.accessibleByClass = accessibleByClass;
this.accessibleByPackage = accessibleByClass.getPackageName();
this.isSameObject = isSameObject;
if (isSameObject)
isSameClass = DTClass.this.name.equals(accessibleByClass.name);
this.isSuperclass = accessibleByClass.isSuperclass(DTClass.this); // this DTClass is a superclass of accessibleByClass;
// package and protected members can be accessed by any class in the same package
// protected members can be inherited, but not accessed by subclasses (must be the same object)
if (DTClass.this.getPackageName().equals(accessibleByPackage)) {
this.allowPackage = true;
this.allowProtected = true;
}
else if (isSameObject && isSuperclass) {
this.allowProtected = true;
}
}
void adjustLevel(DTClass dtClass) {
this.isSameClass = false;
this.isSuperclass = this.isSuperclass && accessibleByClass.isSuperclass(dtClass); // dtClass is a superclass of accessibleByClass
// package and protected members can be accessed by any class in the same package
// protected members can be inherited, but not accessed by subclasses (must be the same object)
if (dtClass.getPackageName().equals(accessibleByPackage)) {
this.allowPackage = true;
this.allowProtected = true;
}
else if (isSameObject && isSuperclass) {
this.allowPackage = false;
this.allowProtected = true;
}
else {
this.allowPackage = false;
this.allowProtected = false;
}
}
public boolean filterAccess(int modifiers) {
if (Modifier.isPublic(modifiers)) // Public are always visible
return false;
if (Modifier.isProtected(modifiers)) // Don't filter protected if allowing protected
return !allowProtected;
if (Modifier.isPrivate(modifiers)) // If filtering, always filter private
return true;
// Must be package
return !allowPackage; // Package are visible from same package
}
}
/**
* gets the text range from the beginning of the "class" statement to the closing brace
*/
public Range getSourceRange() {
if (primitive || isArray()) return null;
return getRange0(SOURCE_RANGE);
}
/**
* gets the text range from the beginning of the first line of the class' Javadoc comment
* to the closing asterisk-slash characters
*/
public Range getJavadocRange() {
if (primitive || isArray()) return null;
return getRange0(JAVADOC_RANGE);
}
/**
* gets the text range from the beginning of the member declaration to the semicolon
*/
Range getSourceRange(DTField field) {
if (primitive || isArray()) return null;
return getFieldRange0(field.getName(), SOURCE_RANGE);
}
/**
* gets the text range from the beginning of the first line of the field's Javadoc comment
* to the closing asterisk-slash characters
*/
Range getJavadocRange(DTField field) {
if (primitive || isArray()) return null;
return getFieldRange0(field.getName(), JAVADOC_RANGE);
}
/**
* gets the text range from the beginning of the method declaration to the closing brace
* (or semicolon for native or abstract members)
*/
Range getSourceRange(DTMethod method) {
if (primitive || isArray()) return null;
return getMethodRange0(method.getName(), ((method.parameters == null) ? null : method.getParameterTypeNames()), SOURCE_RANGE);
}
/**
* gets the text range from the beginning of the first line of the method's Javadoc comment
* to the closing asterisk-slash characters
*/
Range getJavadocRange(DTMethod method) {
if (primitive || isArray()) return null;
return getMethodRange0(method.getName(), ((method.parameters == null) ? null : method.getParameterTypeNames()), JAVADOC_RANGE);
}
/**
* gets the text range from the beginning of the member declaration to the closing brace
*/
Range getSourceRange(DTConstructor constructor) {
if (primitive || isArray()) return null;
return getConstructorRange0(((constructor.parameters == null) ? null : constructor.getParameterTypeNames()), SOURCE_RANGE);
}
/**
* Gets the text range from the beginning of the first line of the member's Javadoc comment
* to the closing asterisk-slash characters
*/
Range getJavadocRange(DTConstructor constructor) {
if (primitive || isArray()) return null;
return getConstructorRange0(((constructor.parameters == null) ? null : constructor.getParameterTypeNames()), JAVADOC_RANGE);
}
/**
* Renames a type to new name
* param newName: The new name of the class
* @return Success (true) or failure (false)...
*/
public boolean rename(String newName) {
if (primitive || isArray()) return false;
return renameClass0(newName);
}
/**
* Renames a field to new name
* @param field: the field we need to rename
* @param newName: The new name of the field
* @return Success (true) or failure (false)...
*/
boolean rename(DTField field, String newName) {
if (primitive || isArray()) return false;
return renameField0(field.getName(), newName);
}
/**
* Renames a method to new name
* @param method: the method we need to rename
* @param newName: The new name of the field
* @return: Success (true) or failure (false)...
*/
boolean rename(DTMethod method, String newName) {
if (primitive || isArray()) return false;
return renameMethod0(method.getName(), ((method.parameters == null) ? null : method.getParameterTypeNames()), newName);
}
/**
* Gets the closest member to the location. The closest member is the member with a
* source range or Javadoc range that surrounds the location
*/
public DTMember getClosestMember(int location) {
if (primitive || isArray()) return null;
return getClosestMember0(location);
}
/**
* Return true if the argument is a byte, short, int or long.
*/
public boolean isInteger() {
return this == LongType || this == IntegerType || this == ShortType || this == ByteType;
}
/**
* Return true if the argument is a number, i.e.,
* byte, short, int, long, float or double.
*/
public boolean isNumeric() {
return isInteger() || this == FloatType || this == DoubleType;
}
/**
* Return a DTClass object for the named primitive type.
* @return null if name is not a primitive type
*/
public static DTClass getPrimitiveClass(String name) {
if (primHash == null) {
primHash = new Hashtable();
primHash.put("boolean", new DTClass("boolean"));
primHash.put("char", new DTClass("char"));
primHash.put("byte", new DTClass("byte"));
primHash.put("short", new DTClass("short"));
primHash.put("int", new DTClass("int"));
primHash.put("long", new DTClass("long"));
primHash.put("float", new DTClass("float"));
primHash.put("double", new DTClass("double"));
primHash.put("void", new DTClass("void"));
primHash.put("*", new DTClass("*"));
primHash.put("null", new DTClass("null"));
}
return (DTClass) primHash.get(name);
}
/**
* Return the VisualProject that defines the class, or null for a system class.
*/
public VisualProject getProject() {
return project;
}
/**
* Return the ID of the ProjectFile that defines the class, or 0 for a system class.
*/
public int getProjectFileID() {
if (projectFileID == -1) { // Unknown?
if (primitive || isArray() || project == null) {
projectFileID = 0;
} else {
projectFileID = getProjectFileID0();
}
}
return projectFileID;
}
/**
* Return the ProjectFile that defines the class, or null for a system class.
*/
public ProjectFile getProjectFile() {
// Make sure projectFileID is setup
if (this.getProjectFileID() == 0) return null;
return project.getProjectFile(projectFileID);
}
/**
* Return the SourceFile that contains the class, or null if not found.
*/
public SourceFile getSourceFile() {
if (primitive || isArray()) return null;
return getSourceFile0();
}
/**
* Validate that the class still exists and the information about
* the class is correct. Sets the valid flag to the result of
* validate().
*
* @return true if the DTClass object is valid, false otherwise.
*/
public boolean validate() {
if (primitive) return true;
if (!projectClass) {
try {
Class clazz = loadClass();
return getModifiers() == clazz.getModifiers();
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".validate() threw " + e);
e.printStackTrace();
}
}
return valid = false;
}
return valid = validate0();
}
/**
* Return value of last validate().
*/
public boolean isValid() {
return valid;
}
/**
* Return true if the other class is the same as this.
* <p> If classes are equal and both are valid,
* all of the information about the class is the same.
*
* @param other class to be compared.
*/
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj instanceof DTClass) {
DTClass other = (DTClass) obj;
return this.equals(other);
}
return false;
}
/**
* Return true if the other class is the same as this.
* <p> If classes are equal and both are valid,
* all of the information about the class is the same.
*
* @param other class to be compared.
*/
public boolean equals(DTClass other) {
if (this == other) return true;
return (other != null) && name.equals(other.name);
}
/**
* nonNull does nothing except throw a NullPointerException if
* called with null DTClass reference
*
* @return reference to calling object
*/
public final DTClass nonNull() { return this; }
/**
* nonNull does nothing except throw a NullPointerException if
* called with null reference
*
* @return reference to calling object
*/
public final Object nonNull(Object obj) {
if (obj == null) throw new NullPointerException("nonNull() check failed");
return obj;
}
/**
* nonNull does nothing except throw a NullPointerException if
* called with a null DTClass[] reference or if any of its
* components are null.
*
# @param array of DTClass references
* @return reference to array argument
*/
public static final DTClass[] nonNull(DTClass[] array) {
for (int i = 0; i < array.length; i++)
array[i].nonNull();
return array;
}
private String packageName; // class's package
private String name; // class fully qualified name (includes packageName)
private int modifier; // standard flags
private int dim; // number of dimensions
private boolean primitive; // true if primitive class
private boolean projectClass; // true if defined by project
private transient VisualProject project; // containing project
private transient int projectFileID; // ID of file within its project
private transient boolean valid; // set by validate()
private transient Class clazz; // 'real' class for non-projectClasses
private static Hashtable primHash;
private static Hashtable systemClassHash = new Hashtable();
// Cached information
private transient Hashtable checkedSuperclasses = null;
private transient boolean gotSuperClass = false; // Need to differentiate gotSuperClass from superClass != null
private transient DTClass superClass = null; // because java.lang.Object's superClass IS null.
// Cached information that is periodically purged to free memory
private transient DTField[] publicFields = null;
private transient DTField[] declaredFields = null;
private transient Hashtable accessibleMethods = null; // Hash of accessible DECLARED method arrays
private transient DTMethod[] allAccessibleMethods = null; // Cache of last found list of accessible methods (includes superclasses)
private transient String allAccessibleMethodsKey = null;
private transient Hashtable accessibleFields = null; // Hash of accessible DECLARED field arrays
private transient DTField[] allAccessibleFields = null; // Cache of last found list of accessible fields (includes superclasses)
private transient String allAccessibleFieldsKey = null;
public static int cacheFlushDelay = 180000; // 3 minutes
private static CacheFlusher cacheFlusher = new CacheFlusher();
static class CacheFlusher implements java.awt.event.ActionListener {
com.sun.java.swing.Timer cacheFlushTimer;
Hashtable scheduledFlushes = new Hashtable();
CacheFlusher() {
cacheFlushTimer = new com.sun.java.swing.Timer(cacheFlushDelay, this);
cacheFlushTimer.setRepeats(false);
}
/**
* Invoked when the action occurs.
*/
synchronized public void actionPerformed(java.awt.event.ActionEvent e) {
Enumeration elements = scheduledFlushes.elements();
while (elements.hasMoreElements()) {
DTClass dtClass = (DTClass) elements.nextElement();
dtClass.publicFields = null;
dtClass.declaredFields = null;
dtClass.accessibleMethods = null;
dtClass.allAccessibleMethods = null;
dtClass.allAccessibleMethodsKey = null;
dtClass.accessibleFields = null;
dtClass.allAccessibleFields = null;
dtClass.allAccessibleFieldsKey = null;
}
scheduledFlushes.clear();
}
synchronized void scheduleCacheFlush(DTClass dtClass) {
if (!scheduledFlushes.containsKey(dtClass))
scheduledFlushes.put(dtClass, dtClass);
cacheFlushTimer.setInitialDelay(cacheFlushDelay);
cacheFlushTimer.restart();
}
}
// native methods
private static native boolean isProjectClass0(VisualProject project, String name);
private native DTClass[] getInterfaces0();
private native DTClass getSuperclass0();
private native DTClass getDeclaringClass0();
private native Vector getClasses0(int which);
private native boolean isSuperClass0(DTClass superClass);
private native boolean validate0();
private native DTField[] getFields0(int kind);
private native DTMethod[] getMethods0(int kind);
private native DTConstructor[] getConstructors0(int kind);
private native DTField getField0(String name, int kind);
private native DTMethod getMethod0(String name, String[] parameterTypes, int kind);
private native DTConstructor getConstructor0(String[] parameterTypes, int kind);
private native DTField[] getAccessibleFields0(String accessibleByClassName, boolean sameObject);
private native DTMethod[] getAccessibleMethods0(String accessibleByClassName, boolean sameObject);
private native int getProjectFileID0();
private native SourceFile getSourceFile0();
private native DTMember getClosestMember0(int location);
static final int SOURCE_RANGE = 0;
static final int JAVADOC_RANGE = 1;
private native Range getRange0(int rangeKind);
private native Range getFieldRange0(String name, int rangeKind);
private native Range getMethodRange0(String name, String[] parameterTypeNames, int rangeKind);
private native Range getConstructorRange0(String[] parameterTypeNames, int rangeKind);
private native boolean renameClass0(String newName);
private native boolean renameField0(String sOldName, String newName);
private native boolean renameMethod0(String name, String[] parameterTypeNames, String newName);
private static boolean isProjectClass(VisualProject project, String name) {
if (project == null) return false;
return isProjectClass0(project,name);
}
private static String classesToString(Class[] classes) {
StringBuffer buf = new StringBuffer();
int i, n = classes.length;
for (i = 0; i < n; i++) {
if (i > 0) buf.append(',');
buf.append(classToString(classes[i]));
}
return buf.toString();
}
private static String classToString(Class clazz) {
return classnameToString(clazz.getName());
}
protected static String classnameToString(String name) {
int n = name.length();
if (n == 0) return "";
if (name.charAt(0) != '[')
return name;
// array classes are signature-encoded
StringBuffer buf = new StringBuffer();
int i, dim = 0;
Vector bounds = new Vector();
dimloop: for (i = 0; i < n && name.charAt(i) == '['; i++) {
dim++;
int bound = 0;
char c;
while (i+1 < n && (c = name.charAt(i+1)) >= '0' && c <= '9') {
bound = bound*10 + (int)c - (int)'0';
i++;
}
bounds.addElement(new Integer(bound));
}
if (i >= n) throw new NullPointerException();
char code = name.charAt(i);
switch (code) {
case 'B':
buf.append("byte");
break;
case 'C':
buf.append("char");
break;
case 'D':
buf.append("double");
break;
case 'F':
buf.append("float");
break;
case 'I':
buf.append("int");
break;
case 'J':
buf.append("long");
break;
case 'S':
buf.append("short");
break;
case 'V':
buf.append("void");
break;
case 'Z':
buf.append("boolean");
break;
case 'L':
buf.append(name.substring(i+1,n-1));
break;
default:
buf.append(name.substring(i));
}
for (i = 0; i < dim; i++) {
buf.append("[");
Integer bound = (Integer) bounds.elementAt(i);
if (bound.intValue() > 0)
buf.append(bound.toString());
buf.append("]");
}
return buf.toString();
}
private DTClass[] classToDTClassArray(Class[] classes) {
int i, n = classes.length;
DTClass[] array = new DTClass[n];
for (i = 0; i < n; i++)
array[i] = classToDTClass(classes[i]);
return array;
}
private DTClass classToDTClass(Class clazz) {
String dtname = classToString(clazz);
DTClass dtClass = new DTClass(project, dtname, clazz, scanDim(dtname), clazz.isPrimitive(),
isProjectClass(project,componentName(dtname)));
return DTClass.registerClass(dtClass, false /*!replace*/);
}
private static Class[] dtclassToClassArray(DTClass[] dtclasses) throws ClassNotFoundException {
int i, n = dtclasses.length;
Class[] classes = new Class[n];
for (i = 0; i < n; i++) {
DTClass dtclass = dtclasses[i];
if (dtclass.primitive) {
Class clazz = null;
if (dtclass == DTClass.BooleanType)
clazz = Boolean.TYPE;
else if (dtclass == DTClass.CharacterType)
clazz = Character.TYPE;
else if (dtclass == DTClass.ByteType)
clazz = Byte.TYPE;
else if (dtclass == DTClass.ShortType)
clazz = Short.TYPE;
else if (dtclass == DTClass.IntegerType)
clazz = Integer.TYPE;
else if (dtclass == DTClass.LongType)
clazz = Long.TYPE;
else if (dtclass == DTClass.FloatType)
clazz = Float.TYPE;
else if (dtclass == DTClass.DoubleType)
clazz = Double.TYPE;
else if (dtclass == DTClass.VoidType)
clazz = Void.TYPE;
classes[i] = clazz;
} else
classes[i] = dtclass.loadClass();
}
return classes;
}
private Class[] stringToClassArray(String[] classNames) throws ClassNotFoundException {
int i, n = classNames.length;
Class[] classes = new Class[n];
for (i = 0; i < n; i++) {
String className = classNames[i];
DTClass primitive = getPrimitiveClass(className);
if (primitive != null) {
Class clazz = null;
if (primitive == DTClass.BooleanType)
clazz = Boolean.TYPE;
else if (primitive == DTClass.CharacterType)
clazz = Character.TYPE;
else if (primitive == DTClass.ByteType)
clazz = Byte.TYPE;
else if (primitive == DTClass.ShortType)
clazz = Short.TYPE;
else if (primitive == DTClass.IntegerType)
clazz = Integer.TYPE;
else if (primitive == DTClass.LongType)
clazz = Long.TYPE;
else if (primitive == DTClass.FloatType)
clazz = Float.TYPE;
else if (primitive == DTClass.DoubleType)
clazz = Double.TYPE;
else if (primitive == DTClass.VoidType)
clazz = Void.TYPE;
classes[i] = clazz;
} else {
classes[i] = loadClass(className);
}
}
return classes;
}
private DTField[] getFields(int which) {
if (!(primitive || isArray())) {
if (projectClass) {
DTField[] dtFields = getFields0(which);
//
// If we may have gotten inherited fields, need to fixup the member classes
// to refer to DTClasses in our cache.
//
if (which == Member.PUBLIC) {
Hashtable memberDTClassHash = null;
for (int i = 0; i < dtFields.length; i++) {
DTField dtField = dtFields[i];
if (dtField.clazz != this) {
DTClass memberDTClass;
if (memberDTClassHash == null) {
memberDTClassHash = new Hashtable();
memberDTClass = null;
} else {
memberDTClass = (DTClass) memberDTClassHash.get(dtField.clazz);
}
if (memberDTClass == null) {
memberDTClass = DTClass.registerClass(dtField.clazz, false /*!replace*/);
memberDTClassHash.put(memberDTClass, memberDTClass);
}
if (dtField.clazz != memberDTClass)
dtField.clazz = memberDTClass;
}
}
}
return dtFields;
}
else {
return getFields1(which, null);
}
}
return new DTField[0];
}
interface AccessFilter {
/** return true if a member with this access level should not be included */
public boolean filterAccess(int accessModifiers);
}
private DTField[] getFields1(int which, AccessFilter accessFilter) {
try {
Class clazz = loadClass();
Field[] fields = which == Member.PUBLIC ? clazz.getFields() : clazz.getDeclaredFields();
int n = fields.length;
DTField[] dtfields = null;
Vector vdtfields = null;
Hashtable memberDTClassHash = null;
if (accessFilter == null)
dtfields = new DTField[n];
else
vdtfields = new Vector(n, 0); // Start with the size of the array, no incrementing will be necessary
for (int i = 0; i < n; i++) {
Field field = fields[i];
int fieldModifiers = field.getModifiers();
if (accessFilter != null && accessFilter.filterAccess(fieldModifiers))
continue;
// Determine in which class this field is declared
DTClass memberDTClass = null;
if (which == Member.DECLARED) {
memberDTClass = this; // Obviously must be declared in this class
} else {
Class memberClazz = field.getDeclaringClass();
if (memberClazz.equals(clazz)) { // Declared in this class
memberDTClass = this;
} else { // Search the hash of known classes
if (memberDTClassHash == null)
memberDTClassHash = new Hashtable();
else
memberDTClass = (DTClass) memberDTClassHash.get(memberClazz);
if (memberDTClass == null) {
memberDTClass = new DTClass(project, memberClazz);
memberDTClass = DTClass.registerClass(memberDTClass, false /*!replace*/);
memberDTClassHash.put(memberClazz, memberDTClass);
}
}
}
DTField dtfield = new DTField(memberDTClass,
field.getName(),
fieldModifiers,
classToString(field.getType()));
if (accessFilter == null)
dtfields[i] = dtfield;
else
vdtfields.addElement(dtfield);
}
if (accessFilter != null) {
dtfields = new DTField[vdtfields.size()];
vdtfields.copyInto(dtfields);
}
return dtfields;
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getFields() threw " + e);
e.printStackTrace();
}
}
return new DTField[0];
}
private DTMethod[] getMethods(int which) {
if (!(primitive || isArray())) {
if (projectClass) {
DTMethod[] dtMethods = getMethods0(which);
//
// If we may have gotten inherited methods, need to fixup the member classes
// to refer to DTClasses in our cache.
//
if (which == Member.PUBLIC) {
Hashtable memberDTClassHash = null;
for (int i = 0; i < dtMethods.length; i++) {
DTMethod dtMethod = dtMethods[i];
if (dtMethod.clazz != this) {
DTClass memberDTClass;
if (memberDTClassHash == null) {
memberDTClassHash = new Hashtable();
memberDTClass = null;
} else {
memberDTClass = (DTClass) memberDTClassHash.get(dtMethod.clazz);
}
if (memberDTClass == null) {
memberDTClass = DTClass.registerClass(dtMethod.clazz, false /*!replace*/);
memberDTClassHash.put(memberDTClass, memberDTClass);
}
if (dtMethod.clazz != memberDTClass)
dtMethod.clazz = memberDTClass;
}
}
}
return dtMethods;
}
else {
return getMethods1(which, null);
}
}
return new DTMethod[0];
}
private DTMethod[] getMethods1(int which, AccessFilter accessFilter) {
try {
Class clazz = loadClass();
Method[] methods = which == Member.PUBLIC ? clazz.getMethods() : clazz.getDeclaredMethods();
int n = methods.length;
DTMethod[] dtmethods = null;
Vector vdtmethods = null;
Hashtable memberDTClassHash = null;
if (accessFilter == null)
dtmethods = new DTMethod[n];
else
vdtmethods = new Vector(n, 0); // Start with the size of the array, no incrementing will be necessary
for (int i = 0; i < n; i++) {
Method method = methods[i];
int methodModifiers = method.getModifiers();
if (accessFilter != null && accessFilter.filterAccess(methodModifiers))
continue;
// Determine in which class this method is declared
DTClass memberDTClass = null;
if (which == Member.DECLARED) {
memberDTClass = this; // Obviously must be declared in this class
} else {
Class memberClazz = method.getDeclaringClass();
if (memberClazz.equals(clazz)) { // Declared in this class
memberDTClass = this;
} else { // Search the hash of known classes
if (memberDTClassHash == null)
memberDTClassHash = new Hashtable();
else
memberDTClass = (DTClass) memberDTClassHash.get(memberClazz);
if (memberDTClass == null) {
memberDTClass = new DTClass(project, memberClazz);
memberDTClass = DTClass.registerClass(memberDTClass, false /*!replace*/);
memberDTClassHash.put(memberClazz, memberDTClass);
}
}
}
DTMethod dtmethod = new DTMethod(memberDTClass,
method.getName(),
methodModifiers,
classToString(method.getReturnType()),
classesToString(method.getParameterTypes()),
"",
classesToString(method.getExceptionTypes()));
if (accessFilter == null)
dtmethods[i] = dtmethod;
else
vdtmethods.addElement(dtmethod);
}
if (accessFilter != null) {
dtmethods = new DTMethod[vdtmethods.size()];
vdtmethods.copyInto(dtmethods);
}
return dtmethods;
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getMethods() threw " + e);
e.printStackTrace();
}
}
return new DTMethod[0];
}
private DTConstructor[] getConstructors(int which) {
if (!(primitive || isArray())) {
if (projectClass) {
return getConstructors0(which);
}
try {
Class clazz = loadClass();
Constructor[] constructors = which == Member.PUBLIC ? clazz.getConstructors() : clazz.getDeclaredConstructors();
int n = constructors.length;
DTConstructor[] dtconstructors = new DTConstructor[n];
Hashtable memberDTClassHash = null;
for (int i = 0; i < n; i++) {
Constructor constructor = constructors[i];
// Determine in which class this constructor is declared
DTClass memberDTClass = null;
if (which == Member.DECLARED) {
memberDTClass = this; // Obviously must be declared in this class
} else {
Class memberClazz = constructor.getDeclaringClass();
if (memberClazz.equals(clazz)) { // Declared in this class
memberDTClass = this;
} else { // Search the hash of known classes
if (memberDTClassHash == null)
memberDTClassHash = new Hashtable();
else
memberDTClass = (DTClass) memberDTClassHash.get(memberClazz);
if (memberDTClass == null) {
memberDTClass = new DTClass(project, memberClazz);
memberDTClass = DTClass.registerClass(memberDTClass, false /*!replace*/);
memberDTClassHash.put(memberClazz, memberDTClass);
}
}
}
dtconstructors[i] = new DTConstructor(memberDTClass,
constructor.getName(),
constructor.getModifiers(),
classesToString(constructor.getParameterTypes()),
"",
classesToString(constructor.getExceptionTypes()));
}
return dtconstructors;
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getConstructors() threw " + e);
e.printStackTrace();
}
}
}
return new DTConstructor[0];
}
private DTClass[] getClasses(int which) {
if (!(primitive || isArray())) {
if (projectClass) {
Vector v = getClasses0(which);
if (v == null) return new DTClass[0];
DTClass[] dtclasses = new DTClass[v.size()];
v.copyInto(dtclasses);
for (int i = 0; i < dtclasses.length; i++) {
dtclasses[i] = DTClass.registerProjectClass(dtclasses[i], false /*!replace*/);
}
return dtclasses;
}
try {
Class clazz = loadClass();
Class[] classes = which == Member.PUBLIC ? clazz.getClasses() : clazz.getDeclaredClasses();
return classToDTClassArray(classes);
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getClasses() threw " + e);
e.printStackTrace();
}
}
}
return new DTClass[0];
}
private DTField getField(String fieldName, int which) {
if (!(primitive || isArray())) {
if (projectClass) {
return getField0(fieldName, which);
}
try {
Class clazz = loadClass();
Field field = which == Member.PUBLIC ? clazz.getField(fieldName) : clazz.getDeclaredField(fieldName);
// Determine in which class this field is declared
DTClass memberDTClass = null;
if (which == Member.DECLARED) {
memberDTClass = this; // Obviously must be declared in this class
} else {
Class memberClazz = field.getDeclaringClass();
if (memberClazz.equals(clazz)) { // Declared in this class
memberDTClass = this;
} else { // (Maybe) Make a new DTClass for the member's Class
memberDTClass = new DTClass(project, memberClazz);
memberDTClass = DTClass.registerClass(memberDTClass, false /*!replace*/);
}
}
return new DTField(memberDTClass,
field.getName(),
field.getModifiers(),
classToString(field.getType()));
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getField(" + fieldName + ") threw " + e);
e.printStackTrace();
}
}
}
return null;
}
private DTMethod getMethod(String methodName, DTClass[] parameterTypes, int which) {
if (!(primitive || isArray())) {
if (projectClass) {
// Convert parameterTypes into names
String[] parameterTypeNames;
if (parameterTypes == null) {
parameterTypeNames = null;
} else {
parameterTypeNames = new String[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++)
parameterTypeNames[i] = parameterTypes[i].name;
}
return getMethod0(methodName, parameterTypeNames, which);
}
try {
Class clazz = loadClass();
Class[] types = dtclassToClassArray(parameterTypes);
Method method = which == Member.PUBLIC ? clazz.getMethod(methodName,types) : clazz.getDeclaredMethod(methodName,types);
// Determine in which class this method is declared
DTClass memberDTClass = null;
if (which == Member.DECLARED) {
memberDTClass = this; // Obviously must be declared in this class
} else {
Class memberClazz = method.getDeclaringClass();
if (memberClazz.equals(clazz)) { // Declared in this class
memberDTClass = this;
} else { // (Maybe) Make a new DTClass for the member's Class
memberDTClass = new DTClass(project, memberClazz);
memberDTClass = DTClass.registerClass(memberDTClass, false /*!replace*/);
}
}
return new DTMethod(memberDTClass,
method.getName(),
method.getModifiers(),
classToString(method.getReturnType()),
classesToString(method.getParameterTypes()),
"",
classesToString(method.getExceptionTypes()));
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getMethod(" + methodName + ") threw " + e);
e.printStackTrace();
}
}
}
return null;
}
private DTMethod getMethod(String methodName, String[] parameterTypeNames, int which) {
if (!(primitive || isArray())) {
if (projectClass) {
return getMethod0(methodName, parameterTypeNames, which);
}
try {
Class clazz = loadClass();
Class[] types = stringToClassArray(parameterTypeNames);
Method method = which == Member.PUBLIC ? clazz.getMethod(methodName,types) : clazz.getDeclaredMethod(methodName,types);
// Determine in which class this method is declared
DTClass memberDTClass = null;
if (which == Member.DECLARED) {
memberDTClass = this; // Obviously must be declared in this class
} else {
Class memberClazz = method.getDeclaringClass();
if (memberClazz.equals(clazz)) { // Declared in this class
memberDTClass = this;
} else { // (Maybe) Make a new DTClass for the member's Class
memberDTClass = new DTClass(project, memberClazz);
memberDTClass = DTClass.registerClass(memberDTClass, false /*!replace*/);
}
}
return new DTMethod(memberDTClass,
method.getName(),
method.getModifiers(),
classToString(method.getReturnType()),
classesToString(method.getParameterTypes()),
"",
classesToString(method.getExceptionTypes()));
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getMethod(" + methodName + ") threw " + e);
e.printStackTrace();
}
}
}
return null;
}
private DTConstructor getConstructor(DTClass[] parameterTypes, int which) {
if (!(primitive || isArray())) {
if (projectClass) {
// Convert parameterTypes into names
String[] parameterTypeNames;
if (parameterTypes == null) {
parameterTypeNames = null;
} else {
parameterTypeNames = new String[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++)
parameterTypeNames[i] = parameterTypes[i].name;
}
return getConstructor0(parameterTypeNames, which);
}
try {
Class clazz = loadClass();
Class[] types = dtclassToClassArray(parameterTypes);
Constructor constructor = which == Member.PUBLIC ? clazz.getConstructor(types) : clazz.getDeclaredConstructor(types);
// Determine in which class this constructor is declared
DTClass memberDTClass = null;
if (which == Member.DECLARED) {
memberDTClass = this; // Obviously must be declared in this class
} else {
Class memberClazz = constructor.getDeclaringClass();
if (memberClazz.equals(clazz)) { // Declared in this class
memberDTClass = this;
} else { // (Maybe) Make a new DTClass for the member's Class
memberDTClass = new DTClass(project, memberClazz);
memberDTClass = DTClass.registerClass(memberDTClass, false /*!replace*/);
}
}
return new DTConstructor(memberDTClass,
constructor.getName(),
constructor.getModifiers(),
classesToString(constructor.getParameterTypes()),
"",
classesToString(constructor.getExceptionTypes()));
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getConstructor() threw " + e);
e.printStackTrace();
}
}
}
return null;
}
private DTConstructor getConstructor(String[] parameterTypeNames, int which) {
if (!(primitive || isArray())) {
if (projectClass) {
return getConstructor0(parameterTypeNames, which);
}
try {
Class clazz = loadClass();
Class[] types = stringToClassArray(parameterTypeNames);
Constructor constructor = which == Member.PUBLIC ? clazz.getConstructor(types) : clazz.getDeclaredConstructor(types);
// Determine in which class this constructor is declared
DTClass memberDTClass = null;
if (which == Member.DECLARED) {
memberDTClass = this; // Obviously must be declared in this class
} else {
Class memberClazz = constructor.getDeclaringClass();
if (memberClazz.equals(clazz)) { // Declared in this class
memberDTClass = this;
} else { // (Maybe) Make a new DTClass for the member's Class
memberDTClass = new DTClass(project, memberClazz);
memberDTClass = DTClass.registerClass(memberDTClass, false /*!replace*/);
}
}
return new DTConstructor(memberDTClass,
constructor.getName(),
constructor.getModifiers(),
classesToString(constructor.getParameterTypes()),
"",
classesToString(constructor.getExceptionTypes()));
} catch (Exception e) {
if (DEBUG_DTCLASS_JAVA_LANG_CLASS_EXCEPTIONS) {
System.out.println(" DTClass: " + name + ".getConstructor() threw " + e);
e.printStackTrace();
}
}
}
return null;
}
/**
* Derive a java class name, given a name in our internal format.
* for example, this turns "java.lang.Object[]",1 into "[Ljava.lang.Object;"
*/
protected static String getClassname(String name, int dim) {
if (dim == 0) return name;
StringBuffer classnameBuffer = new StringBuffer();
for (int i = 0; i < dim; i++) {
classnameBuffer.append("[");
}
classnameBuffer.append("L");
classnameBuffer.append(componentName(name));
return classnameBuffer.append(";").toString();
}
private String getClassname() {
if (dim > 0)
return getClassname(name, dim);
else
return name;
}
/**
* Gets the Class object for this DTClass. If this DTClass refers to an array, the
* array Class is returned (rather than the array's component class).
* for example, for "java.lang.Object[]", the Class for "[Ljava.lang.Object;" is returned.
*/
private Class loadClass() throws ClassNotFoundException {
if (clazz != null) return clazz;
String classname = getClassname();
if (project != null) {
ClassLoader loader = getProjectLoader();
clazz = loader.loadClass(classname);
} else {
clazz = Class.forName(classname);
}
return clazz;
}
/**
* Gets the Class object for this DTClass. If this DTClass refers to an array, the
* array's component Class is returned.
* for example, for "java.lang.Object[]", the Class for "java.lang.Object" is returned.
*/
private Class loadComponentClass() throws ClassNotFoundException {
if (project != null) {
ClassLoader loader = getProjectLoader();
return loader.loadClass(getComponentName());
} else {
return Class.forName(getComponentName());
}
}
/**
* Gets the Class object for the className. If className refers to an array, the
* array Class is returned (rather than the array's component class).
*/
private Class loadClass(String className) throws ClassNotFoundException {
String classname = DTClass.getClassname(className, scanDim(className));
if (project != null) {
ClassLoader loader = getProjectLoader();
return loader.loadClass(classname);
} else {
return Class.forName(classname);
}
}
/*
private Class loadClass() throws ClassNotFoundException {
if (clazz != null) return clazz;
// ??? use component name until clear how array names encoded
// may need two methods then, as some depend on this behavior
if (project != null) {
ClassLoader loader = getProjectLoader();
clazz = loader.loadClass(getComponentName());
} else {
clazz = Class.forName(getComponentName());
}
return clazz;
}
private Class loadClass(String className) throws ClassNotFoundException {
// ??? use component name until clear how array names encoded
// may need two methods then, as some depend on this behavior
if (project != null) {
ClassLoader loader = getProjectLoader();
return loader.loadClass(className);
} else {
return Class.forName(className);
}
}
*/
/**
* Constructor used locally for primitive types (boolean, char, etc).
*/
private DTClass(String primitiveName) {
this.project = null;
this.projectFileID = 0;
this.name = primitiveName;
this.packageName = null;
this.modifier = Modifier.PUBLIC|Modifier.FINAL;
this.dim = 0;
this.primitive = true;
this.projectClass = false;
}
/**
* Constructor used locally for primitive array types (boolean[], char[], etc).
*/
protected DTClass(DTClass primitiveType, int dim) {
if (!primitiveType.primitive || primitiveType.dim > 0 || primitiveType.packageName != null)
throw new IllegalArgumentException();
this.project = null;
this.projectFileID = 0;
this.name = primitiveType.name;
this.packageName = null;
this.modifier = primitiveType.modifier;
this.dim = dim;
this.primitive = true;
this.projectClass = false;
for (int i = 0; i < dim; i++) {
name += "[]";
}
}
/**
* Constructor used locally to make a DTClass from a system java.lang.Class
*/
private DTClass(VisualProject project, Class clazz) {
this.project = project;
this.projectFileID = -1; // unknown
this.name = clazz.getName();
int lastDot = name.lastIndexOf('.');
if (lastDot == -1)
this.packageName = "";
else
this.packageName = name.substring(0, lastDot-1);
this.modifier = clazz.getModifiers();
this.dim = 0;
this.primitive = false;
this.projectClass = false;
this.clazz = clazz;
// a class may have a project but not be a project class;
// the project is used to obtain the project loader
}
/**
* Constructor used locally to make a DTClass, usually from a system java.lang.Class
*/
protected DTClass(VisualProject project, String name, Class clazz, int dim, boolean primitive, boolean projectClass) {
this.project = project;
this.projectFileID = -1; // unknown
int lastDot = name.lastIndexOf('.');
if (lastDot == -1)
this.packageName = "";
else
this.packageName = name.substring(0, lastDot-1);
this.name = name;
this.modifier = clazz.getModifiers();
this.dim = dim;
this.primitive = primitive;
this.projectClass = projectClass;
this.clazz = clazz;
// a class may have a project but not be a project class;
// the project is used to obtain the project loader
}
/**
* Constructor used by native methods.
*/
private DTClass(VisualProject project, int projectFileID, String name, String packageName, int modifier, int dim, boolean projectClass) {
this.project = project;
this.projectFileID = projectFileID;
this.packageName = packageName;
this.name = name;
this.modifier = modifier;
this.dim = dim;
this.primitive = false;
this.projectClass = projectClass;
// a class may have a project but not be a project class;
// the project is used to obtain the project loader
}
protected DTClass() { }
/**
* Override.
*/
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException { // no good can come from suppressing exceptions here
in.defaultReadObject();
boolean hadProject = in.readBoolean();
this.projectFileID = -1; // unknown
if (hadProject)
project = ((VisualProject.ProjectInputStream)in).getProject();
validate();
if (valid)
DTClass.registerClass(this, true /*replace*/);
}
/**
* Override.
*/
private void writeObject(java.io.ObjectOutputStream out)
throws IOException, ClassNotFoundException {
out.defaultWriteObject();
out.writeBoolean(project != null);
}
}