Starting our own version of JPF with support for generics.
[jpf-core.git] / src / classes / java / lang / Class.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package java.lang;
19
20 import java.io.ByteArrayInputStream;
21 import java.io.InputStream;
22 import java.io.Serializable;
23 import java.lang.annotation.Annotation;
24 import java.lang.reflect.*;
25 import java.net.URL;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import sun.reflect.ConstantPool;
30 import sun.reflect.annotation.AnnotationType;
31 // TODO: DIRTY HACKS!
32 import sun.reflect.generics.factory.CoreReflectionFactory;
33 import sun.reflect.generics.factory.GenericsFactory;
34 import sun.reflect.generics.repository.ClassRepository;
35 import sun.reflect.generics.scope.ClassScope;
36
37 /**
38  * MJI model class for java.lang.Class library abstraction
39  *
40  * This is a JPF specific version of a system class because we can't use the real,
41  * platform VM specific version (it's native all over the place, its field
42  * structure isn't documented, most of its methods are private, hence we can't
43  * even instantiate it properly).
44  *
45  * Note that this class never gets seen by the real VM - it's for JPF's eyes only.
46  *
47  * For now, it's only a fragment to test the mechanism, and provide basic
48  * class.getName() / Class.ForName() support (which is (almost) enough for
49  * Java assertion support
50  */
51 @SuppressWarnings("unused")  // native peer uses
52 public final class Class<T> implements Serializable, GenericDeclaration, Type, AnnotatedElement {
53
54   /** don't use serialVersionUID from JDK 1.1 for interoperability */
55   private static final long serialVersionUID = 3206093459760846163L + 1;
56
57    // we init this on demand (from MJIEnv) since it's not used too often
58   private static Annotation[] emptyAnnotations; // = new Annotation[0];
59   
60   private String name;
61
62   private ClassLoader classLoader;
63   
64   /**
65    * search global id of the corresponding ClassInfo, which factors in the classloader
66    */
67   private int nativeId;
68
69   /**
70    * to be set during <clinit> of the corresponding class
71    */
72   private boolean isPrimitive;
73   
74   private Class() {}
75
76   public native boolean isArray ();
77
78   @Override
79   public native Annotation[] getAnnotations();
80
81   @Override
82   public native <A extends Annotation> A getAnnotation( Class<A> annotationCls);
83
84   // those are from Java 6
85   public native boolean isAnnotation ();
86   @Override
87   public native boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
88
89   public native Class<?> getComponentType ();
90
91   public native Field[] getFields() throws SecurityException;
92   
93   public native Field getDeclaredField (String fieldName) throws NoSuchFieldException,
94                                                           SecurityException;
95
96   public native Field[] getDeclaredFields () throws SecurityException;
97
98   public native Method getDeclaredMethod (String mthName, Class<?>... paramTypes)
99                             throws NoSuchMethodException, SecurityException;
100
101   public native Method getMethod (String mthName, Class<?>... paramTypes)
102                     throws NoSuchMethodException, SecurityException;
103
104   public native Method[] getDeclaredMethods () throws SecurityException;
105
106   public native Method[] getMethods () throws SecurityException;
107     
108   public native Constructor<?>[] getDeclaredConstructors() throws SecurityException;
109
110   public native Constructor<?>[] getConstructors() throws SecurityException;
111
112   private native byte[] getByteArrayFromResourceStream(String name);
113
114   public InputStream getResourceAsStream (String name) {
115     byte[] byteArray = getByteArrayFromResourceStream(name);
116     if (byteArray == null) return null;
117     return new ByteArrayInputStream(byteArray);
118   }
119
120   private native String getResolvedName (String rname);
121
122   public URL getResource (String rname) {
123     String resolvedName = getResolvedName(rname);
124     return getClassLoader().getResource(resolvedName);
125   }
126
127   public Package getPackage() {
128     // very very crude version for now, only supports the package name
129     String pkgName = null;
130
131     int idx = name.lastIndexOf('.');
132     if (idx >=0){
133       pkgName = name.substring(0,idx);
134
135       Package pkg = new Package(pkgName,
136                                 "spectitle", "specversion", "specvendor",
137                                 "impltitle", "implversion", "implvendor",
138                                  null, getClassLoader());
139         return pkg;
140
141     } else { // weird, but there is no Package object for the default package
142       return null;
143     }
144
145   }
146
147   //--- enum support ()
148   // Java 1.5
149   public native T[] getEnumConstants();
150
151   // Java 6
152   T[] getEnumConstantsShared() {
153     return getEnumConstants();
154   }
155   
156   // lazy initialized map for field name -> Enum constants
157   // <2do> we should move this to the native side, since Enum constants don't change
158   private transient Map<String, T> enumConstantDirectory = null;
159
160   // package private helper for Enum.valueOf()
161   Map<String,T> enumConstantDirectory() {
162     if (enumConstantDirectory == null) {
163       Map<String,T> map = new HashMap<String,T>();
164
165       T[] ae = getEnumConstants();
166       for (T e: ae) {
167         map.put(((Enum)e).name(), e);
168       }
169
170       enumConstantDirectory = map;
171     }
172     return enumConstantDirectory;
173   }
174
175
176   public native Constructor<T> getDeclaredConstructor (Class<?>... paramTypes)
177               throws NoSuchMethodException, SecurityException;
178
179   public native Field getField (String fieldName) throws NoSuchFieldException,
180                                                   SecurityException;
181
182   public native boolean isInstance (Object o);
183
184   public native boolean isAssignableFrom (Class<?> clazz);
185
186   public native boolean isInterface();
187
188   public native Constructor<T> getConstructor (Class<?>... argTypes) throws NoSuchMethodException, SecurityException;
189
190   public native int getModifiers();
191
192   public native Class<?>[] getInterfaces();
193
194   // no use to have a ctor, we can't call it
195   public String getName () {
196     return name;
197   }
198
199   public String getSimpleName () {
200     int idx; // <2do> not really - inner classes?
201     Class<?> enclosingClass = getEnclosingClass();
202     
203     if(enclosingClass!=null){
204       idx = enclosingClass.getName().length();
205     } else{
206       idx = name.lastIndexOf('.');
207     }
208     
209     return name.substring(idx+1);
210   }
211
212   static native Class<?> getPrimitiveClass (String clsName);
213
214    /**
215     * this one is in JPF reflection land, it's 'native' for us
216     */
217   public static native Class<?> forName (String clsName) throws ClassNotFoundException;
218
219   public static Class<?> forName (String clsName, boolean initialize, ClassLoader loader) throws ClassNotFoundException {
220     Class<?> cls;
221     if (loader == null){
222       cls = forName(clsName);
223     } else {
224       cls = loader.loadClass(clsName);
225     }
226     
227     if (initialize) {
228       cls.initialize0();
229     }
230     return cls;
231   }
232
233   /**
234    * forces clinit without explicit field or method access
235    */
236   private native void initialize0 ();
237   
238   public boolean isPrimitive () {
239     return isPrimitive;
240   }
241
242   public native Class<? super T> getSuperclass ();
243
244   public native T newInstance () throws InstantiationException,
245                                       IllegalAccessException;
246
247   @Override
248   public String toString () {
249     return (isInterface() ? "interface " : "class ") + name;
250   }
251
252   @SuppressWarnings("unchecked")
253   public T cast(Object o) {
254     if (o != null && !isInstance(o)) throw new ClassCastException();
255     return (T) o;
256   }
257   
258   @SuppressWarnings("unchecked")
259   public <U> Class<? extends U> asSubclass(Class<U> clazz) {
260     if (clazz.isAssignableFrom(this)) {
261       return (Class<? extends U>) this;
262     } else {
263       throw new ClassCastException("" + this + " is not a " + clazz);
264     }
265   }
266
267   native public boolean desiredAssertionStatus ();
268
269   public ClassLoader getClassLoader() {
270     return classLoader;
271   }
272
273   native ConstantPool getConstantPool();
274
275   native void setAnnotationType (AnnotationType at);
276
277   native AnnotationType getAnnotationType();
278   
279   // TODO: DIRTY HACKS!
280   //public native TypeVariable<Class<T>>[] getTypeParameters();
281   /*
282   @Override
283   public TypeVariable<Class<T>>[] getTypeParameters() {
284     throw new UnsupportedOperationException();
285   }
286   
287   // Generic info repository; lazily initialized
288   private volatile transient ClassRepository genericInfo;
289   
290   // Generic signature handling
291   //private native String getGenericSignature0();
292   
293   // accessor for factory
294   private GenericsFactory getFactory() {
295     // create scope and factory
296     return CoreReflectionFactory.make(this, ClassScope.make(this));
297   }
298   
299   // accessor for generic info repository;
300   // generic info is lazily initialized
301   private ClassRepository getGenericInfo() {
302         ClassRepository genericInfo = this.genericInfo;
303     if (genericInfo == null) {
304       //String signature = getGenericSignature0();
305           //String signature = "Ljava/lang/Object;";
306           String signature = null;
307       if (signature == null) {
308         genericInfo = ClassRepository.NONE;
309       } else {
310         genericInfo = ClassRepository.make(signature, getFactory());
311       }
312       this.genericInfo = genericInfo;
313     }
314     return (genericInfo != ClassRepository.NONE) ? genericInfo : null;
315   }
316   
317   @Override
318   public TypeVariable<Class<T>>[] getTypeParameters() {
319     //throw new UnsupportedOperationException();
320         ClassRepository info = getGenericInfo();
321     if (info != null)
322       return (TypeVariable<Class<T>>[])info.getTypeParameters();
323     else
324       return (TypeVariable<Class<T>>[])new TypeVariable<?>[0];
325   }*/
326   @Override
327   public TypeVariable<Class<T>>[] getTypeParameters() {
328     //throw new UnsupportedOperationException();
329     System.out.println("Calling getTypeParameters for: " + this.name);
330     TypeVariable[] typeVariables = (TypeVariable<Class<T>>[])new TypeVariable<?>[1];
331     //Object obj = new Object();
332     //typeVariables[0] = (TypeVariable<Class<T>>) obj;
333     return typeVariables;
334   }
335   // TODO: DIRTY HACKS!
336   
337   public Type getGenericSuperclass() {
338     throw new UnsupportedOperationException();
339   }
340   
341   public Type[] getGenericInterfaces() {
342     throw new UnsupportedOperationException();
343   }
344
345   public Object[] getSigners() {
346     throw new UnsupportedOperationException();
347   }
348
349   void setSigners(Object[] signers) {
350     signers = null;  // Get rid of IDE warning 
351     throw new UnsupportedOperationException();
352   }
353   
354   public Method getEnclosingMethod() {
355     throw new UnsupportedOperationException();
356   }
357
358   public Constructor<?> getEnclosingConstructor() {
359     throw new UnsupportedOperationException();
360   }
361
362   public Class<?> getDeclaringClass() {
363     throw new UnsupportedOperationException();
364   }
365
366   public native Class<?> getEnclosingClass();
367   
368   public String getCanonicalName() {
369     throw new UnsupportedOperationException();
370   }
371
372   public boolean isAnonymousClass() {
373     throw new UnsupportedOperationException();
374   }
375
376   public boolean isLocalClass() {
377     throw new UnsupportedOperationException();
378   }
379
380   public boolean isMemberClass() {
381     throw new UnsupportedOperationException();
382   }
383
384   public Class<?>[] getClasses() {
385     throw new UnsupportedOperationException();
386   }
387   
388   public Class<?>[] getDeclaredClasses() throws SecurityException {
389     throw new UnsupportedOperationException();
390   }
391   
392   public java.security.ProtectionDomain getProtectionDomain() {
393     throw new UnsupportedOperationException();
394   }
395
396   void setProtectionDomain0(java.security.ProtectionDomain pd) {
397     pd = null;  // Get rid of IDE warning 
398     throw new UnsupportedOperationException();
399   }
400
401   public boolean isEnum() {
402     throw new UnsupportedOperationException();
403   }
404   
405   @Override
406   public Annotation[] getDeclaredAnnotations() {
407     throw new UnsupportedOperationException();
408   }
409
410   public boolean isSynthetic (){
411     final int SYNTHETIC = 0x00001000;
412     return (getModifiers() & SYNTHETIC) != 0;
413   }
414 }