//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package java.lang;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import sun.reflect.ConstantPool;
import sun.reflect.annotation.AnnotationType;
/**
* MJI model class for java.lang.Class library abstraction
*
* This is a JPF specific version of a system class because we can't use the real,
* platform VM specific version (it's native all over the place, its field
* structure isn't documented, most of its methods are private, hence we can't
* even instantiate it properly).
*
* Note that this class never gets seen by the real VM - it's for JPF's eyes only.
*
* For now, it's only a fragment to test the mechanism, and provide basic
* class.getName() / Class.ForName() support (which is (almost) enough for
* Java assertion support
*/
// native peer uses
public final class Class<T> implements Serializable, GenericDeclaration, Type, AnnotatedElement {
/** don't use serialVersionUID from JDK 1.1 for interoperability */
private static final long serialVersionUID = 3206093459760846163L + 1;
// we init this on demand (from MJIEnv) since it's not used too often
private static Annotation[] emptyAnnotations; // = new Annotation[0];
private String name;
private ClassLoader classLoader;
/**
* search global id of the corresponding ClassInfo, which factors in the classloader
*/
private int nativeId;
/**
* to be set during <clinit> of the corresponding class
*/
private boolean isPrimitive;
private Class() {}
public native boolean isArray ();
public native Annotation[] getAnnotations();
public native <A extends Annotation> A getAnnotation( Class<A> annotationCls);
// those are from Java 6
public native boolean isAnnotation ();
public native boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
public native Class<?> getComponentType ();
public native Field[] getFields() throws SecurityException;
public native Field getDeclaredField (String fieldName) throws NoSuchFieldException,
SecurityException;
public native Field[] getDeclaredFields () throws SecurityException;
public native Method getDeclaredMethod (String mthName, Class<?>... paramTypes)
throws NoSuchMethodException, SecurityException;
public native Method getMethod (String mthName, Class<?>... paramTypes)
throws NoSuchMethodException, SecurityException;
public native Method[] getDeclaredMethods () throws SecurityException;
public native Method[] getMethods () throws SecurityException;
public native Constructor<?>[] getDeclaredConstructors() throws SecurityException;
public native Constructor<?>[] getConstructors() throws SecurityException;
private native byte[] getByteArrayFromResourceStream(String name);
public InputStream getResourceAsStream (String name) {
byte[] byteArray = getByteArrayFromResourceStream(name);
if (byteArray == null) return null;
return new ByteArrayInputStream(byteArray);
}
private native String getResolvedName (String rname);
public URL getResource (String rname) {
String resolvedName = getResolvedName(rname);
return getClassLoader().getResource(resolvedName);
}
public Package getPackage() {
// very very crude version for now, only supports the package name
String pkgName = null;
int idx = name.lastIndexOf('.');
if (idx >=0){
pkgName = name.substring(0,idx);
Package pkg = new Package(pkgName,
"spectitle", "specversion", "specvendor",
"impltitle", "implversion", "implvendor",
null, getClassLoader());
return pkg;
} else { // weird, but there is no Package object for the default package
return null;
}
}
//--- enum support ()
// Java 1.5
public native T[] getEnumConstants();
// Java 6
T[] getEnumConstantsShared() {
return getEnumConstants();
}
// lazy initialized map for field name -> Enum constants
// <2do> we should move this to the native side, since Enum constants don't change
private transient Map<String, T> enumConstantDirectory = null;
// package private helper for Enum.valueOf()
Map<String,T> enumConstantDirectory() {
if (enumConstantDirectory == null) {
Map<String,T> map = new HashMap<String,T>();
T[] ae = getEnumConstants();
for (T e: ae) {
map.put(((Enum<?>)e).name(), e);
}
enumConstantDirectory = map;
}
return enumConstantDirectory;
}
public native Constructor<T> getDeclaredConstructor (Class<?>... paramTypes)
throws NoSuchMethodException, SecurityException;
public native Field getField (String fieldName) throws NoSuchFieldException,
SecurityException;
public native boolean isInstance (Object o);
public native boolean isAssignableFrom (Class<?> clazz);
public native boolean isInterface();
public native Constructor<T> getConstructor (Class<?>... argTypes) throws NoSuchMethodException, SecurityException;
public native int getModifiers();
public native Class<?>[] getInterfaces();
// no use to have a ctor, we can't call it
public String getName () {
return name;
}
/**
* @see JDK
*/
public String getSimpleName () {
if (isArray()) {
return getComponentType().getSimpleName() + "[]";
}
String simpleName = getSimpleBinaryName();
if (simpleName == null) { // top level class
simpleName = getName();
return simpleName.substring(simpleName.lastIndexOf('.')+1); // strip the package name
}
int length = simpleName.length();
if (length < 1 || simpleName.charAt(0) != '$')
throw new InternalError("Malformed class name");
int index = 1;
while (index < length && isAsciiDigit(simpleName.charAt(index)))
index++;
return simpleName.substring(index);
}
/**
* @see JDK
*/
private static boolean isAsciiDigit(char c) {
return '0' <= c && c <= '9';
}
/**
* @see JDK
*/
private String getSimpleBinaryName() {
Class<?> enclosingClass = getEnclosingClass();
if (enclosingClass == null) // top level class
return null;
// Otherwise, strip the enclosing class' name
try {
return getName().substring(enclosingClass.getName().length());
} catch (IndexOutOfBoundsException ex) {
throw new InternalError("Malformed class name");
}
}
static native Class<?> getPrimitiveClass (String clsName);
/**
* this one is in JPF reflection land, it's 'native' for us
*/
public static native Class<?> forName (String clsName) throws ClassNotFoundException;
public static Class<?> forName (String clsName, boolean initialize, ClassLoader loader) throws ClassNotFoundException {
Class<?> cls;
if (loader == null){
cls = forName(clsName);
} else {
cls = loader.loadClass(clsName);
}
if (initialize) {
cls.initialize0();
}
return cls;
}
/**
* forces clinit without explicit field or method access
*/
private native void initialize0 ();
public boolean isPrimitive () {
return isPrimitive;
}
public native Class<? super T> getSuperclass ();
public native T newInstance () throws InstantiationException,
IllegalAccessException;
public String toString () {
return (isInterface() ? "interface " : "class ") + name;
}
@SuppressWarnings("unchecked")
public T cast(Object o) {
if (o != null && !isInstance(o)) throw new ClassCastException();
return (T) o;
}
@SuppressWarnings("unchecked")
public <U> Class<? extends U> asSubclass(Class<U> clazz) {
if (clazz.isAssignableFrom(this)) {
return (Class<? extends U>) this;
} else {
throw new ClassCastException("" + this + " is not a " + clazz);
}
}
native public boolean desiredAssertionStatus ();
public ClassLoader getClassLoader() {
return classLoader;
}
native ConstantPool getConstantPool();
native void setAnnotationType (AnnotationType at);
native AnnotationType getAnnotationType();
@SuppressWarnings("unchecked")
public TypeVariable<Class<T>>[] getTypeParameters() {
return new TypeVariable[0];//throw new UnsupportedOperationException(); TODO implement
}
public Type getGenericSuperclass() {
throw new UnsupportedOperationException();
}
public Type[] getGenericInterfaces() {
throw new UnsupportedOperationException();
}
public Object[] getSigners() {
throw new UnsupportedOperationException();
}
void setSigners(Object[] signers) {
// signers = null; // Get rid of IDE warning
throw new UnsupportedOperationException();
}
public Method getEnclosingMethod() {
throw new UnsupportedOperationException();
}
public Constructor<?> getEnclosingConstructor() {
throw new UnsupportedOperationException();
}
public Class<?> getDeclaringClass() {
throw new UnsupportedOperationException();
}
public native Class<?> getEnclosingClass();
public String getCanonicalName() {
throw new UnsupportedOperationException();
}
public boolean isAnonymousClass() {
throw new UnsupportedOperationException();
}
public boolean isLocalClass() {
throw new UnsupportedOperationException();
}
public boolean isMemberClass() {
throw new UnsupportedOperationException();
}
public Class<?>[] getClasses() {
throw new UnsupportedOperationException();
}
public Class<?>[] getDeclaredClasses() throws SecurityException {
throw new UnsupportedOperationException();
}
public java.security.ProtectionDomain getProtectionDomain() {
throw new UnsupportedOperationException();
}
void setProtectionDomain0(java.security.ProtectionDomain pd) {
// pd = null; // Get rid of IDE warning
throw new UnsupportedOperationException();
}
public boolean isEnum() {
throw new UnsupportedOperationException();
}
public Annotation[] getDeclaredAnnotations() {
throw new UnsupportedOperationException();
}
public boolean isSynthetic (){
final int SYNTHETIC = 0x00001000;
return (getModifiers() & SYNTHETIC) != 0;
}
}