diff options
Diffstat (limited to 'libjava/classpath/java/lang/Class.java')
-rw-r--r-- | libjava/classpath/java/lang/Class.java | 512 |
1 files changed, 499 insertions, 13 deletions
diff --git a/libjava/classpath/java/lang/Class.java b/libjava/classpath/java/lang/Class.java index c4235e6..090ac23 100644 --- a/libjava/classpath/java/lang/Class.java +++ b/libjava/classpath/java/lang/Class.java @@ -1,5 +1,5 @@ /* Class.java -- Representation of a Java class. - Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005 + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -39,17 +39,25 @@ exception statement from your version. */ package java.lang; import gnu.classpath.VMStackWalker; +import gnu.java.lang.reflect.ClassSignatureParser; import java.io.InputStream; import java.io.ObjectStreamClass; import java.io.Serializable; +import java.lang.annotation.Annotation; import java.lang.reflect.Array; +import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.GenericSignatureFormatError; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.MalformedParameterizedTypeException; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.net.URL; import java.security.AccessController; import java.security.AllPermission; @@ -87,17 +95,37 @@ import java.util.HashSet; * * @author John Keiser * @author Eric Blake (ebb9@email.byu.edu) + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) * @author Tom Tromey (tromey@cygnus.com) * @since 1.0 * @see ClassLoader */ -public final class Class implements Serializable +public final class Class + implements Serializable, Type, AnnotatedElement, GenericDeclaration { /** * Compatible with JDK 1.0+. */ private static final long serialVersionUID = 3206093459760846163L; + /** + * Flag indicating a synthetic member. + * Note that this duplicates a constant in Modifier. + */ + private static final int SYNTHETIC = 0x1000; + + /** + * Flag indiciating an annotation class. + */ + private static final int ANNOTATION = 0x2000; + + /** + * Flag indicating an enum constant or an enum class. + * Note that this duplicates a constant in Modifier. + */ + private static final int ENUM = 0x4000; + /** The class signers. */ private Object[] signers = null; /** The class protection domain. */ @@ -259,7 +287,7 @@ public final class Class implements Serializable ClassLoader loader = VMClass.getClassLoader(this); // Check if we may get the classloader SecurityManager sm = SecurityManager.current; - if (sm != null) + if (loader != null && sm != null) { // Get the calling classloader ClassLoader cl = VMStackWalker.getCallingClassLoader(); @@ -631,17 +659,16 @@ public final class Class implements Serializable public boolean equals(Object o) { - if(o instanceof MethodKey) + if (o instanceof MethodKey) { - MethodKey m = (MethodKey)o; - if(m.name.equals(name) && m.params.length == params.length && m.returnType == returnType) + MethodKey m = (MethodKey) o; + if (m.name.equals(name) && m.params.length == params.length + && m.returnType == returnType) { - for(int i = 0; i < params.length; i++) + for (int i = 0; i < params.length; i++) { - if(m.params[i] != params[i]) - { - return false; - } + if (m.params[i] != params[i]) + return false; } return true; } @@ -1252,8 +1279,60 @@ public final class Class implements Serializable } /** - * Like <code>getField(String)</code> but without the security checks and returns null - * instead of throwing NoSuchFieldException. + * <p> + * Casts this class to represent a subclass of the specified class. + * This method is useful for `narrowing' the type of a class so that + * the class object, and instances of that class, can match the contract + * of a more restrictive method. For example, if this class has the + * static type of <code>Class<Object></code>, and a dynamic type of + * <code>Class<Rectangle></code>, then, assuming <code>Shape</code> is + * a superclass of <code>Rectangle</code>, this method can be used on + * this class with the parameter, <code>Class<Shape></code>, to retain + * the same instance but with the type + * <code>Class<? extends Shape></code>. + * </p> + * <p> + * If this class can be converted to an instance which is parameterised + * over a subtype of the supplied type, <code>U</code>, then this method + * returns an appropriately cast reference to this object. Otherwise, + * a <code>ClassCastException</code> is thrown. + * </p> + * + * @param klass the class object, the parameterized type (<code>U</code>) of + * which should be a superclass of the parameterized type of + * this instance. + * @return a reference to this object, appropriately cast. + * @throws ClassCastException if this class can not be converted to one + * which represents a subclass of the specified + * type, <code>U</code>. + * @since 1.5 + */ + /* FIXME[GENERICS]: Should be <U> Class<? extends U> asSubClass(Class<U> klass */ + public Class asSubclass(Class klass) + { + if (! klass.isAssignableFrom(this)) + throw new ClassCastException(); + return this; /* FIXME[GENERICS]: Should cast to Class<? extends U> */ + } + + /** + * Returns the specified object, cast to this <code>Class</code>' type. + * + * @param obj the object to cast + * @throws ClassCastException if obj is not an instance of this class + * @since 1.5 + */ + /* FIXME[GENERICS]: Should be T cast(Object obj) */ + public Object cast(Object obj) + { + if (obj != null && ! isInstance(obj)) + throw new ClassCastException(); + return obj; /* FIXME[GENERICS]: Should be cast to T */ + } + + /** + * Like <code>getField(String)</code> but without the security checks and + * returns null instead of throwing NoSuchFieldException. */ private Field internalGetField(String name) { @@ -1306,4 +1385,411 @@ public final class Class implements Serializable sm.checkPackageAccess(pkg.getName()); } } + + /** + * Returns the enumeration constants of this class, or + * null if this class is not an <code>Enum</code>. + * + * @return an array of <code>Enum</code> constants + * associated with this class, or null if this + * class is not an <code>enum</code>. + * @since 1.5 + */ + /* FIXME[GENERICS]: T[] getEnumConstants() */ + public Object[] getEnumConstants() + { + if (isEnum()) + { + try + { + return (Object[]) + getMethod("values", new Class[0]).invoke(null, new Object[0]); + } + catch (NoSuchMethodException exception) + { + throw new Error("Enum lacks values() method"); + } + catch (IllegalAccessException exception) + { + throw new Error("Unable to access Enum class"); + } + catch (InvocationTargetException exception) + { + throw new + RuntimeException("The values method threw an exception", + exception); + } + } + else + { + return null; + } + } + + /** + * Returns true if this class is an <code>Enum</code>. + * + * @return true if this is an enumeration class. + * @since 1.5 + */ + public boolean isEnum() + { + int mod = VMClass.getModifiers (this, true); + return (mod & ENUM) != 0; + } + + /** + * Returns true if this class is a synthetic class, generated by + * the compiler. + * + * @return true if this is a synthetic class. + * @since 1.5 + */ + public boolean isSynthetic() + { + int mod = VMClass.getModifiers (this, true); + return (mod & SYNTHETIC) != 0; + } + + /** + * Returns true if this class is an <code>Annotation</code>. + * + * @return true if this is an annotation class. + * @since 1.5 + */ + public boolean isAnnotation() + { + int mod = VMClass.getModifiers (this, true); + return (mod & ANNOTATION) != 0; + } + + /** + * Returns the simple name for this class, as used in the source + * code. For normal classes, this is the content returned by + * <code>getName()</code> which follows the last ".". Anonymous + * classes have no name, and so the result of calling this method is + * "". The simple name of an array consists of the simple name of + * its component type, followed by "[]". Thus, an array with the + * component type of an anonymous class has a simple name of simply + * "[]". + * + * @return the simple name for this class. + * @since 1.5 + */ + public String getSimpleName() + { + return VMClass.getSimpleName(this); + } + + /** + * Returns this class' annotation for the specified annotation type, + * or <code>null</code> if no such annotation exists. + * + * @param annotationClass the type of annotation to look for. + * @return this class' annotation for the specified type, or + * <code>null</code> if no such annotation exists. + * @since 1.5 + */ + /* FIXME[GENERICS]: <T extends Annotation> T getAnnotation(Class <T>) */ + public Annotation getAnnotation(Class annotationClass) + { + Annotation foundAnnotation = null; + Annotation[] annotations = getAnnotations(); + for (int i = 0; i < annotations.length; i++) + if (annotations[i].annotationType() == annotationClass) + foundAnnotation = annotations[i]; + return foundAnnotation; + } + + /** + * Returns all annotations associated with this class. If there are + * no annotations associated with this class, then a zero-length array + * will be returned. The returned array may be modified by the client + * code, but this will have no effect on the annotation content of this + * class, and hence no effect on the return value of this method for + * future callers. + * + * @return this class' annotations. + * @since 1.5 + */ + public Annotation[] getAnnotations() + { + HashSet set = new HashSet(); + set.addAll(Arrays.asList(getDeclaredAnnotations())); + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + set.addAll(Arrays.asList(interfaces[i].getAnnotations())); + Class superClass = getSuperclass(); + if (superClass != null) + set.addAll(Arrays.asList(superClass.getAnnotations())); + return (Annotation[]) set.toArray(new Annotation[set.size()]); + } + + /** + * <p> + * Returns the canonical name of this class, as defined by section + * 6.7 of the Java language specification. Each package, top-level class, + * top-level interface and primitive type has a canonical name. A member + * class has a canonical name, if its parent class has one. Likewise, + * an array type has a canonical name, if its component type does. + * Local or anonymous classes do not have canonical names. + * </p> + * <p> + * The canonical name for top-level classes, top-level interfaces and + * primitive types is always the same as the fully-qualified name. + * For array types, the canonical name is the canonical name of its + * component type with `[]' appended. + * </p> + * <p> + * The canonical name of a member class always refers to the place where + * the class was defined, and is composed of the canonical name of the + * defining class and the simple name of the member class, joined by `.'. + * For example, if a <code>Person</code> class has an inner class, + * <code>M</code>, then both its fully-qualified name and canonical name + * is <code>Person.M</code>. A subclass, <code>Staff</code>, of + * <code>Person</code> refers to the same inner class by the fully-qualified + * name of <code>Staff.M</code>, but its canonical name is still + * <code>Person.M</code>. + * </p> + * <p> + * Where no canonical name is present, <code>null</code> is returned. + * </p> + * + * @return the canonical name of the class, or <code>null</code> if the + * class doesn't have a canonical name. + * @since 1.5 + */ + public String getCanonicalName() + { + return VMClass.getCanonicalName(this); + } + + /** + * Returns all annotations directly defined by this class. If there are + * no annotations associated with this class, then a zero-length array + * will be returned. The returned array may be modified by the client + * code, but this will have no effect on the annotation content of this + * class, and hence no effect on the return value of this method for + * future callers. + * + * @return the annotations directly defined by this class. + * @since 1.5 + */ + public Annotation[] getDeclaredAnnotations() + { + return VMClass.getDeclaredAnnotations(this); + } + + /** + * Returns the class which immediately encloses this class. If this class + * is a top-level class, this method returns <code>null</code>. + * + * @return the immediate enclosing class, or <code>null</code> if this is + * a top-level class. + * @since 1.5 + */ + /* FIXME[GENERICS]: Should return Class<?> */ + public Class getEnclosingClass() + { + return VMClass.getEnclosingClass(this); + } + + /** + * Returns the constructor which immediately encloses this class. If + * this class is a top-level class, or a local or anonymous class + * immediately enclosed by a type definition, instance initializer + * or static initializer, then <code>null</code> is returned. + * + * @return the immediate enclosing constructor if this class is + * declared within a constructor. Otherwise, <code>null</code> + * is returned. + * @since 1.5 + */ + /* FIXME[GENERICS]: Should return Constructor<?> */ + public Constructor getEnclosingConstructor() + { + return VMClass.getEnclosingConstructor(this); + } + + /** + * Returns the method which immediately encloses this class. If + * this class is a top-level class, or a local or anonymous class + * immediately enclosed by a type definition, instance initializer + * or static initializer, then <code>null</code> is returned. + * + * @return the immediate enclosing method if this class is + * declared within a method. Otherwise, <code>null</code> + * is returned. + * @since 1.5 + */ + public Method getEnclosingMethod() + { + return VMClass.getEnclosingMethod(this); + } + + /** + * <p> + * Returns an array of <code>Type</code> objects which represent the + * interfaces directly implemented by this class or extended by this + * interface. + * </p> + * <p> + * If one of the superinterfaces is a parameterized type, then the + * object returned for this interface reflects the actual type + * parameters used in the source code. Type parameters are created + * using the semantics specified by the <code>ParameterizedType</code> + * interface, and only if an instance has not already been created. + * </p> + * <p> + * The order of the interfaces in the array matches the order in which + * the interfaces are declared. For classes which represent an array, + * an array of two interfaces, <code>Cloneable</code> and + * <code>Serializable</code>, is always returned, with the objects in + * that order. A class representing a primitive type or void always + * returns an array of zero size. + * </p> + * + * @return an array of interfaces implemented or extended by this class. + * @throws GenericSignatureFormatError if the generic signature of one + * of the interfaces does not comply with that specified by the Java + * Virtual Machine specification, 3rd edition. + * @throws TypeNotPresentException if any of the superinterfaces refers + * to a non-existant type. + * @throws MalformedParameterizedTypeException if any of the interfaces + * refer to a parameterized type that can not be instantiated for + * some reason. + * @since 1.5 + * @see java.lang.reflect.ParameterizedType + */ + public Type[] getGenericInterfaces() + { + if (isPrimitive()) + return new Type[0]; + + String sig = VMClass.getClassSignature(this); + if (sig == null) + return getInterfaces(); + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getInterfaceTypes(); + } + + /** + * <p> + * Returns a <code>Type</code> object representing the direct superclass, + * whether class, interface, primitive type or void, of this class. + * If this class is an array class, then a class instance representing + * the <code>Object</code> class is returned. If this class is primitive, + * an interface, or a representation of either the <code>Object</code> + * class or void, then <code>null</code> is returned. + * </p> + * <p> + * If the superclass is a parameterized type, then the + * object returned for this interface reflects the actual type + * parameters used in the source code. Type parameters are created + * using the semantics specified by the <code>ParameterizedType</code> + * interface, and only if an instance has not already been created. + * </p> + * + * @return the superclass of this class. + * @throws GenericSignatureFormatError if the generic signature of the + * class does not comply with that specified by the Java + * Virtual Machine specification, 3rd edition. + * @throws TypeNotPresentException if the superclass refers + * to a non-existant type. + * @throws MalformedParameterizedTypeException if the superclass + * refers to a parameterized type that can not be instantiated for + * some reason. + * @since 1.5 + * @see java.lang.reflect.ParameterizedType + */ + public Type getGenericSuperclass() + { + if (isArray()) + return Object.class; + + if (isPrimitive() || isInterface() || this == Object.class) + return null; + + String sig = VMClass.getClassSignature(this); + if (sig == null) + return getSuperclass(); + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getSuperclassType(); + } + + /** + * Returns an array of <code>TypeVariable</code> objects that represents + * the type variables declared by this class, in declaration order. + * An array of size zero is returned if this class has no type + * variables. + * + * @return the type variables associated with this class. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + /* FIXME[GENERICS]: Should return TypeVariable<Class<T>> */ + public TypeVariable[] getTypeParameters() + { + String sig = VMClass.getClassSignature(this); + if (sig == null) + return new TypeVariable[0]; + + ClassSignatureParser p = new ClassSignatureParser(this, sig); + return p.getTypeParameters(); + } + + /** + * Returns true if an annotation for the specified type is associated + * with this class. This is primarily a short-hand for using marker + * annotations. + * + * @param annotationClass the type of annotation to look for. + * @return true if an annotation exists for the specified type. + * @since 1.5 + */ + /* FIXME[GENERICS]: Should be Class<? extends Annotation> */ + public boolean isAnnotationPresent(Class + annotationClass) + { + return getAnnotation(annotationClass) != null; + } + + /** + * Returns true if this object represents an anonymous class. + * + * @return true if this object represents an anonymous class. + * @since 1.5 + */ + public boolean isAnonymousClass() + { + return VMClass.isAnonymousClass(this); + } + + /** + * Returns true if this object represents an local class. + * + * @return true if this object represents an local class. + * @since 1.5 + */ + public boolean isLocalClass() + { + return VMClass.isLocalClass(this); + } + + /** + * Returns true if this object represents an member class. + * + * @return true if this object represents an member class. + * @since 1.5 + */ + public boolean isMemberClass() + { + return VMClass.isMemberClass(this); + } + + } |