summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Keiser <shalom@gnu.org>1998-10-17 20:33:59 +0000
committerJohn Keiser <shalom@gnu.org>1998-10-17 20:33:59 +0000
commitdf30658b9df671a678a9a0d76d1078b7d72a110c (patch)
tree9bed325d5607d19ab504cceb3b029983139eb636
parent8cf3c66259e5edd396ae48a98bc29ae71f4d864f (diff)
downloadclasspath-df30658b9df671a678a9a0d76d1078b7d72a110c.tar.gz
Moved some files that are VM-specific over from the main tree.
Fixed a few typos too.
-rw-r--r--vm/reference/gnu/vm/stack/StackFrame.java62
-rw-r--r--vm/reference/gnu/vm/stack/StackTrace.java65
-rw-r--r--vm/reference/java/lang/Thread.java556
-rw-r--r--vm/reference/java/lang/VMSecurityManager.java2
-rw-r--r--vm/reference/java/lang/reflect/Constructor.java199
-rw-r--r--vm/reference/java/lang/reflect/Field.java356
-rw-r--r--vm/reference/java/lang/reflect/Method.java222
7 files changed, 1461 insertions, 1 deletions
diff --git a/vm/reference/gnu/vm/stack/StackFrame.java b/vm/reference/gnu/vm/stack/StackFrame.java
new file mode 100644
index 000000000..9339a63ba
--- /dev/null
+++ b/vm/reference/gnu/vm/stack/StackFrame.java
@@ -0,0 +1,62 @@
+/*
+ * gnu.java.lang.StackFrame: part of the Java Class Libraries project.
+ * Copyright (C) 1998 John Keiser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package gnu.vm.stack;
+
+import java.lang.reflect.*;
+
+/**
+ ** StackFrame represents a single frame of the Java
+ ** execution stack, frozen in time.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, Aug 11 1998
+ **/
+public class StackFrame {
+ StackFrame caller;
+ Object obj;
+ Method method;
+ int lineNum;
+ String filename;
+
+ private StackFrame(Object obj, Method method, int lineNum, String filename) {
+ this.caller = caller;
+ this.obj = obj;
+ this.method = method;
+ this.lineNum = lineNum;
+ this.filename = filename;
+ }
+
+ public String getSourceFilename() {
+ return filename;
+ }
+
+ public Object getCalledObject() {
+ return obj;
+ }
+
+ public Method getCalledMethod() {
+ return method;
+ }
+
+ public int getSourceLineNumber() {
+ return lineNum;
+ }
+}
diff --git a/vm/reference/gnu/vm/stack/StackTrace.java b/vm/reference/gnu/vm/stack/StackTrace.java
new file mode 100644
index 000000000..2bab71363
--- /dev/null
+++ b/vm/reference/gnu/vm/stack/StackTrace.java
@@ -0,0 +1,65 @@
+/*
+ * gnu.java.lang.ExecutionStack: part of the Java Class Libraries project.
+ * Copyright (C) 1998 John Keiser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package gnu.vm.stack;
+
+import java.lang.reflect.*;
+
+/**
+ ** StackTrace represents a Java system execution
+ ** stack and allows you to get information off of it.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, Aug 11 1998
+ **/
+public class StackTrace {
+ StackFrame[] frames;
+ int len;
+
+ public static StackTrace copyCurrentStackTrace() {
+ return new StackTrace(new StackFrame[0]);
+ }
+
+ public static StackTrace copyStackTrace(Thread t) {
+ return new StackTrace(new StackFrame[0]);
+ }
+
+ StackTrace(StackFrame[] frames) {
+ this.frames = frames;
+ len = frames.length;
+ }
+
+ public synchronized StackFrame pop() {
+ if(len == 0)
+ throw new ArrayIndexOutOfBoundsException("stack trace empty.");
+ len--;
+ return frames[len];
+ }
+
+ public synchronized StackFrame frameAt(int i) {
+ if(i > len)
+ throw new ArrayIndexOutOfBoundsException(i + " > " + len);
+ return frames[i];
+ }
+
+ public synchronized int numFrames() {
+ return len;
+ }
+}
diff --git a/vm/reference/java/lang/Thread.java b/vm/reference/java/lang/Thread.java
new file mode 100644
index 000000000..7cbef65d4
--- /dev/null
+++ b/vm/reference/java/lang/Thread.java
@@ -0,0 +1,556 @@
+/*
+ * java.lang.Thread: part of the Java Class Libraries project.
+ * Copyright (C) 1998 John Keiser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package java.lang;
+
+/**
+ ** Thread represents a single thread of execution in the VM.
+ ** When an application VM starts up, it creates a new Thread
+ ** which calls the main() method of a particular class. There
+ ** may be other Threads running, such as the garbage collection
+ ** thread.<P>
+ **
+ ** Threads have names to identify them. These names are not
+ ** necessarily unique.<P>
+ **
+ ** Every Thread has a priority, as well, which tells the VM
+ ** which Threads get more running time.<P>
+ **
+ ** There are two methods of creating a Thread: you may
+ ** subclass Thread and implement the <CODE>run()</CODE> method, at which
+ ** point you may start the Thread by calling its <CODE>start()</CODE>
+ ** method, or you may implement <CODE>Runnable</CODE> in the class you
+ ** want to use and then call new <CODE>Thread(your_obj).start()</CODE>.
+ **
+ ** @specnote it is unclear at what point a Thread should be added to a
+ ** ThreadGroup, and at what point it should be removed.
+ ** Should it be inserted when it starts, or when it is
+ ** created? Should it be removed when it is suspended or
+ ** interrupted? The only thing that is clear is that the
+ ** Thread should be removed when it is stopped.
+ ** @author John Keiser
+ ** @version 1.1.0, Aug 6 1998
+ ** @since JDK1.0
+ **/
+
+public class Thread {
+ static final byte INITIALIZED = 0;
+ static final byte RUNNING = 1;
+ static final byte SUSPENDED = 2;
+ static final byte INTERRUPTED = 3;
+ static final byte STOPPED = 4;
+ static final byte SLEEPING= 5;
+ static final byte WAITING_FOR_LOCK = 6;
+ static final byte STOPPED_BEFORE_START = 7;
+
+ ThreadGroup group;
+ Runnable toRun;
+ String name;
+ boolean daemon;
+ byte state = INITIALIZED;
+
+ /** The maximum priority for a Thread.
+ ** @XXX find out the value for this.
+ **/
+ public static final int MAX_PRIORITY;
+
+ /** The priority a Thread gets by default.
+ ** @XXX find out the value for this.
+ **/
+ public static final int NORM_PRIORITY;
+
+ /** The minimum priority for a Thread.
+ ** @XXX find out the value for this.
+ **/
+ public static final int MIN_PRIORITY;
+
+ static int numThreadsCreated = 0;
+
+ int priority;
+
+ /** Allocate a new Thread object, with the same ThreadGroup
+ ** as the calling thread, with an automatic name, and using
+ ** Thread's <CODE>run()</CODE> method to execute.<P>
+ **
+ ** The new Thread will inherit its creator's priority and
+ ** will be marked as a daemon if its creator is a daemon.<P>
+ **
+ ** This method is identical to calling
+ ** <CODE>Thread(null,null,<I>fake name</I>)</CODE>, where the
+ ** fake name in this case is automatically generated with the
+ ** name "Thread-" + <I>arbitrary integer</I>.
+ **/
+ public Thread() {
+ this(null,null,null);
+ }
+
+ /** Allocate a new Thread object, with the same ThreadGroup
+ ** as the calling thread, with an automatic name, and using
+ ** the specified Runnable object's <CODE>run()</CODE> method
+ ** to execute. If the Runnable object is null, Thread's
+ ** <CODE>run()</CODE> will be called instead.<P>
+ **
+ ** The new Thread will inherit its creator's priority and
+ ** will be marked as a daemon if its creator is a daemon.<P>
+ **
+ ** This method is identical to calling
+ ** <CODE>Thread(null,target,<I>fake name</I>)</CODE>, where the
+ ** fake name in this case is automatically generated with the
+ ** name "Thread-" + <I>arbitrary integer</I>.
+ **
+ ** @param toRun the Runnable object to execute.
+ **/
+ public Thread(Runnable toRun) {
+ this(null,toRun);
+ }
+
+ /** Allocate a new Thread object, with the specified ThreadGroup,
+ ** with an automatic name, and using the specified Runnable
+ ** object's <CODE>run()</CODE> method to execute. If the
+ ** Runnable object is null, Thread's <CPDE>run()</CODE> will be
+ ** called instead. If the ThreadGroup object is null, the Thread
+ ** will get the same ThreadGroup as the creating Thread.<P>
+ **
+ ** The new Thread will inherit its creator's priority and
+ ** will be marked as a daemon if its creator is a daemon.<P>
+ **
+ ** This method is identical to calling
+ ** <CODE>Thread(null,target,<I>fake name</I>)</CODE>, where the
+ ** fake name in this case is automatically generated with the
+ ** name "Thread-" + <I>arbitrary integer</I>.
+ **
+ ** @param group the group to put the Thread into.
+ ** @param target the Runnable object to execute.
+ **
+ ** @exception SecurityException if this thread cannot access the
+ ** specified ThreadGroup.
+ **/
+ public Thread(ThreadGroup group, Runnable toRun) {
+ this(group,toRun,"Thread-" + (++numThreadsCreated));
+ }
+
+ /** Allocate a new Thread object, with the same ThreadGroup
+ ** as the calling thread, with the specified name, and using
+ ** Thread's <CODE>run()</CODE> method to execute.<P>
+ **
+ ** The new Thread will inherit its creator's priority and
+ ** will be marked as a daemon if its creator is a daemon.<P>
+ **
+ ** This method is identical to calling
+ ** <CODE>Thread(null,null,name)</CODE>.
+ **
+ ** @param name the name for the Thread.
+ **/
+ public Thread(String name) {
+ this(null,null,name);
+ }
+
+ /** Allocate a new Thread object, with the same ThreadGroup
+ ** as the calling thread, with the specified name, and using
+ ** the specified Runnable object's <CODE>run()</CODE> method
+ ** to execute. If the Runnable object is null, Thread's
+ ** <CPDE>run()</CODE> will be called instead.<P>
+ **
+ ** The new Thread will inherit its creator's priority and
+ ** will be marked as a daemon if its creator is a daemon.<P>
+ **
+ ** This method is identical to calling
+ ** <CODE>Thread(null,target,name)</CODE>.
+ **
+ ** @param toRun the Runnable object to execute.
+ ** @param name the name for the Thread.
+ **/
+ public Thread(Runnable toRun, String name) {
+ this(null,toRun,name);
+ }
+
+ /** Allocate a new Thread object, with the specified ThreadGroup,
+ ** with the specified name, and using the specified Runnable
+ ** object's <CODE>run()</CODE> method to execute. If the
+ ** Runnable object is null, Thread's <CPDE>run()</CODE> will be
+ ** called instead. If the ThreadGroup object is null, the Thread
+ ** will get the same ThreadGroup as the creating Thread.<P>
+ **
+ ** The new Thread will inherit its creator's priority and
+ ** will be marked as a daemon if its creator is a daemon.
+ **
+ ** @param group the group to put the Thread into.
+ ** @param target the Runnable object to execute.
+ ** @param name the name for the Thread.
+ **
+ ** @exception SecurityException if this thread cannot access the
+ ** specified ThreadGroup.
+ **/
+ public Thread(ThreadGroup group, Runnable toRun, String name) {
+ if(group != null) {
+ this.group = group;
+ group.checkAccess();
+ } else {
+ this.group = currentThread().getThreadGroup();
+ }
+ this.toRun = toRun;
+ this.name = name;
+ priority = currentThread().getPriority();
+ daemon = currentThread().isDaemon();
+ nativeInit();
+
+ this.group.addThread(this);
+ }
+
+ /** Get the currently executing Thread.
+ ** @return the currently executing Thread.
+ **/
+ public static native Thread currentThread();
+
+ /** Suspend the current Thread's execution for the specified
+ ** amount of time. The Thread will not lose any locks it has
+ ** during this time.
+ **
+ ** @param ms the number of milliseconds to sleep.
+ ** @exception InterruptedException if the Thread is interrupted
+ ** by another Thread.
+ ** @exception SecurityException if you cannot modify this Thread.
+ **/
+ public static void sleep(long ms) throws InterruptedException {
+ sleep(ms,0);
+ }
+
+ /** Suspend the current Thread's execution for the specified
+ ** amount of time. The Thread will not lose any locks it has
+ ** during this time.
+ **
+ ** @param ms the number of milliseconds to sleep.
+ ** @param ns the number of extra nanoseconds to sleep (0-999999).
+ ** @exception InterruptedException if the Thread is interrupted
+ ** by another Thread.
+ **/
+ public static void sleep(long ms, int ns) throws InterruptedException {
+ synchronized(currentThread()) {
+ if(currentThread().state != RUNNING && currentThread().state != INTERRUPTED) {
+ return;
+ }
+ try {
+ currentThread().state = SLEEPING;
+ currentThread().nativeSleep(ms,ns);
+ } catch(InterruptedException e) {
+ currentThread().state = INTERRUPTED;
+ throw e;
+ }
+ currentThread().state = RUNNING;
+ }
+ }
+
+ /** Start this Thread, calling the run() method of the Runnable
+ ** this Thread was created with or else the run() method of the
+ ** Thread itself.
+ **/
+ public synchronized void start() {
+ if(state == INITIALIZED) {
+ nativeStart();
+ state = RUNNING;
+ }
+ }
+
+ /** The method of Thread that will be run if there is no Runnable
+ ** object associated with the Thread.<P>
+ **
+ ** Thread's implementation does nothing at all.
+ **/
+ public void run() {
+ }
+
+ /** Cause this Thread to stop abnormally and throw a ThreadDeath
+ ** exception.<P>
+ **
+ ** If you stop a Thread that has not yet started, it will stop
+ ** immediately when it is actually started.<P>
+ **
+ ** @exception SecurityException if you cannot modify this Thread.
+ ** @XXX it doesn't yet implement that second requirement.
+ **/
+ public final void stop() {
+ stop(new ThreadDeath());
+ }
+
+ /** Cause this Thread to stop abnormally and throw the specified
+ ** exception.<P>
+ **
+ ** If you stop a Thread that has not yet started, it will stop
+ ** immediately when it is actually started.<P>
+ **
+ ** @param t the Throwable to throw when the Thread dies.
+ ** @exception SecurityException if you cannot modify this Thread.
+ ** @XXX it doesn't yet implement that second requirement.
+ **/
+ public final synchronized void stop(Throwable t) {
+ checkAccess();
+ group.removeThread(this);
+ nativeStop(t);
+ state = STOPPED;
+ }
+
+ /** Interrupt this Thread.
+ ** It is not clear whether locks this Thread has should be released.
+ ** This operation will only take place if the Thread is suspended
+ ** or is sleeping.
+ ** @exception SecurityException if you cannot modify this Thread.
+ **/
+ public synchronized void interrupt() {
+ checkAccess();
+ if(state == SUSPENDED || state == SLEEPING) {
+ nativeInterrupt();
+ state = INTERRUPTED;
+ }
+ }
+
+ /** Destroy this thread. Don't even bother to clean up locks.
+ ** @exception SecurityException if you cannot modify this Thread.
+ **/
+ public synchronized void destroy() {
+ checkAccess();
+ group.removeThread(this);
+ state = STOPPED;
+ nativeDestroy();
+ }
+
+ /** Suspend this Thread. It will not come back, ever, unless
+ ** it is resumed. It is not clear whether locks should be
+ ** released until resumption, but it is likely.
+ ** @exception SecurityException if you cannot modify this Thread.
+ **/
+ public final synchronized void suspend() {
+ checkAccess();
+ if(state == RUNNING || state == INTERRUPTED) {
+ nativeSuspend();
+ state = SUSPENDED;
+ }
+ }
+
+ /** Resume this Thread. If the thread is not suspended, this
+ ** method does nothing.
+ ** @exception SecurityException if you cannot modify this Thread.
+ **/
+ public final synchronized void resume() {
+ checkAccess();
+ if(state != SUSPENDED) {
+ nativeResume();
+ state = RUNNING;
+ }
+ }
+
+ /** Wait forever for the Thread in question to die.
+ ** @exception InterruptedException if this Thread is interrupted
+ ** while waiting.
+ **/
+ public final void join() throws InterruptedException {
+ join(0,0);
+ }
+
+ /** Wait the specified amount of time for the Thread in question to
+ ** die.
+ ** @param ms the number of milliseconds to wait, or 0 for forever.
+ ** @exception InterruptedException if this Thread is interrupted
+ ** while waiting.
+ **/
+ public final void join(long ms) throws InterruptedException {
+ join(ms,0);
+ }
+
+ /** Wait the specified amount of time for the Thread in question to
+ ** die.
+ ** @param ms the number of milliseconds to wait, or 0 for forever.
+ ** @param ns the number of nanoseconds (0-999999) to wait, or 0 for
+ ** forever.
+ ** @exception InterruptedException if this Thread is interrupted
+ ** while waiting.
+ ** @XXX a ThreadListener would be nice. Then perhaps this could be
+ ** made efficient.
+ **/
+ public final void join(long ms, int ns) throws InterruptedException {
+ if(ms == 0 && ns == 0) {
+ while(!isAlive())
+ currentThread().sleep(1);
+ } else {
+ for(long i=0;i<ms;i++) {
+ if(isAlive())
+ return;
+ currentThread().sleep(1);
+ }
+ currentThread().sleep(0,ns);
+ }
+ }
+
+ /** Print a stack trace of the current thread to stderr using
+ ** the same format as Throwable's printStackTrace() method.
+ **/
+ public static void dumpStack() {
+ new Throwable().printStackTrace();
+ }
+
+
+ /** Set this Thread's priority.
+ ** @param priority the new priority for this Thread.
+ ** @exception SecurityException if you cannot modify this Thread.
+ **/
+ public final void setPriority(int priority) {
+ checkAccess();
+ if(priority < MIN_PRIORITY
+ || priority > MAX_PRIORITY
+ || priority > group.getMaxPriority())
+ throw new IllegalArgumentException("Invalid thread priority value " + priority + ".");
+ this.priority = priority;
+ }
+
+ /** Get this Thread's priority.
+ ** @return the Thread's priority.
+ **/
+ public final int getPriority() {
+ return priority;
+ }
+
+ /** Set this Thread's name.
+ ** @param name the new name for this Thread.
+ ** @exception SecurityException if you cannot modify this Thread.
+ **/
+ public final void setName(String name) {
+ checkAccess();
+ this.name = name;
+ }
+
+ /** Get this Thread's name.
+ ** @return this Thread's name.
+ **/
+ public final String getName() {
+ return name;
+ }
+
+ /** Get the ThreadGroup this Thread belongs to.
+ ** @return this Thread's ThreadGroup.
+ **/
+ public final ThreadGroup getThreadGroup() {
+ return group;
+ }
+
+ /** Set the daemon status of this Thread. If this is a
+ ** daemon Thread, then the VM may exit even if it is still
+ ** running. This may only be called when the Thread is not
+ ** running.
+ **
+ ** @specnote It is possible that this should only be called
+ ** if the Thread has not been started. This
+ ** interpretation was easier to implement, though,
+ ** so it's the one I chose :)
+ ** @param daemon whether this should be a daemon thread or not.
+ ** @exception SecurityException if you cannot modify this Thread.
+ ** @exception IllegalThreadStateException if the Thread is active.
+ **/
+ public final void setDaemon(boolean daemon) {
+ this.daemon = daemon;
+ }
+
+ /** Tell whether this is a daemon Thread or not.
+ ** @return whether this is a daemon Thread or not.
+ **/
+ public final boolean isDaemon() {
+ return daemon;
+ }
+
+
+ /** Get the number of active threads in the current Thread's
+ ** ThreadGroup. This implementation calls
+ ** <CODE>currentThread().getThreadGroup().activeCount()</CODE>.
+ ** @return the number of active threads in the current Thread's
+ ** ThreadGroup.
+ **/
+ public static int activeCount() {
+ return currentThread().group.activeCount();
+ }
+
+ /** Copy every active thread in the current Thread's ThreadGroup
+ ** into the array. This implementation calls
+ ** <CODE>getThreadGroup().enumerate(array)</CODE>
+ ** @param array the array to place the Threads into.
+ ** @return the number of Threads placed into the array.
+ **/
+ public static int enumerate(Thread[] array) {
+ return currentThread().group.enumerate(array);
+ }
+
+ /** Count the number of stack frames in this Thread. The Thread
+ ** in question must be suspended when this occurs.
+ **
+ ** @return the number of stack frames in this Thread.
+ ** @exception IllegalThreadStateException if this Thread is
+ ** not suspended.
+ **/
+ public native int countStackFrames();
+
+
+ /** Determine whether the current Thread has been interrupted.
+ ** @return whether the current Thread has been interrupted.
+ **/
+ public static boolean interrupted() {
+ return currentThread().isInterrupted();
+ }
+
+ /** Determine whether this Thread has been interrupted.
+ ** @return whether this Thread has been interrupted.
+ **/
+ public boolean isInterrupted() {
+ return state == INTERRUPTED;
+ }
+
+ /** Determine whether this Thread is alive.
+ ** @return whether this Thread is alive.
+ **/
+ public final boolean isAlive() {
+ return state != STOPPED && state != INITIALIZED;
+ }
+
+
+ /** Check whether the current Thread is allowed to
+ ** modify this Thread.
+ ** @exception SecurityException if the current Thread cannot
+ ** modify this Thread.
+ **/
+ public void checkAccess() {
+ SecurityManager sm = System.getSecurityManager();
+ if(sm != null) {
+ sm.checkAccess(this);
+ }
+ }
+
+ /** Return a human-readable String representing this Thread.
+ ** @return a human-readable String representing this Thread.
+ ** @XXX determine the exact format of this String.
+ **/
+ public String toString() {
+ return "";
+ }
+
+ final native void nativeInit();
+ final native void nativeStop(Throwable t);
+ final native void nativeStart();
+ final native void nativeInterrupt();
+ final native void nativeDestroy();
+ final native void nativeSuspend();
+ final native void nativeResume();
+ final native void nativeSleep(long ms, int ns) throws InterruptedException;
+}
diff --git a/vm/reference/java/lang/VMSecurityManager.java b/vm/reference/java/lang/VMSecurityManager.java
index 938784a13..74ab587b8 100644
--- a/vm/reference/java/lang/VMSecurityManager.java
+++ b/vm/reference/java/lang/VMSecurityManager.java
@@ -48,5 +48,5 @@ class VMSecurityManager {
** top of the stack.
** @return the current ClassLoader.
**/
- static native Class currentClassLoader();
+ static native ClassLoader currentClassLoader();
}
diff --git a/vm/reference/java/lang/reflect/Constructor.java b/vm/reference/java/lang/reflect/Constructor.java
new file mode 100644
index 000000000..e9d0720d2
--- /dev/null
+++ b/vm/reference/java/lang/reflect/Constructor.java
@@ -0,0 +1,199 @@
+/*
+ * java.lang.reflect.Constructor: part of the Java Class Libraries project.
+ * Copyright (C) 1998 John Keiser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package java.lang.reflect;
+
+/**
+ ** Constructor represents a constructor of a class.
+ ** It will allow you to create a new instance of the class or get generic
+ ** information about the constructor.<P>
+ **
+ ** <B>Note:</B> This class returns and accepts types as Classes, even
+ ** primitive types; there are Class types defined that represent each
+ ** different primitive type. They are <code>java.lang.Boolean.TYPE,
+ ** java.lang.Byte.TYPE, </code>etc. These are not to be confused with
+ ** the classes <code>java.lang.Boolean, java.lang.Byte</code>, etc.,
+ ** which are real classes.<P>
+ **
+ ** <STRONG>Serialization:</STROMG>Note that this is not a serializable
+ ** class. It is entirely feasible to make it serializable, but this
+ ** is on Sun, not me.<P>
+ **
+ ** <STRONG>Access and Security:</STRONG> Once this Constructor is created
+ ** by java.lang.Class (which does its own security check), any object may
+ ** query it for information like parameter types, exception types, etc.
+ ** However, the Constructor may only be invoked using standard Java
+ ** language access controls. The JLS says that reflective access to all
+ ** private, public and protected reflective members is granted to any
+ ** class which can be linked against the reflected member. Link-level
+ ** enforcement is the enforcement of public, private, protected and
+ ** default access rules, based on the caller's relationship to the class
+ ** (same package, subclass, or unrelated). Thus, if you couldn't
+ ** normally invoke this constructor from the calling class, you can't do
+ ** it using a Constructor object either.<P>
+ **
+ ** The relevant section of the VM spec on link-security is <A
+ ** HREF='http://java.sun.com/docs/books/vmspec/html/Concepts.doc.html#22574'>2.16.3</A>, under Resolution.
+ ** A summary of the appropriate rules follows.<P>
+ **
+ ** <STRONG>Summary of access rules</STRONG><BR>
+ ** Two checks are done, and they are the same checks--on both the member's class and the member itself:
+ ** <UL>
+ ** <LI>If the caller is the same class as the member's class, then it can access the member no matter
+ ** what.</LI>
+ ** <LI>If the caller is in the same package as the member's class, then the member's class and the member
+ ** itself must both be public, protected or default access.</LI>
+ ** <LI>If the caller is a subclass of the member's class, then the member's class and the member itself must
+ ** both be public or protected access.</LI>
+ ** <LI>If the caller is unrelated member's class, then the member's class and the member must
+ ** be public access.</LI>
+ ** </UL>
+ ** <P>
+ **
+ ** As far as I can tell from the fairly confusing <A
+ ** HREF='http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html'>Inner
+ ** Classes Specification</A>, there should be no change to these rules from the addition of inner
+ ** classes in 1.1.<P>
+ **
+ ** <STRONG>Version note:</STRONG> In 1.2, the security checks can be disabled in the AccessibleObject
+ ** interface. But this ain't 1.2. :)<P>
+ **
+ ** <STRONG>BUGS:</STRONG> The maximum size of a signature right now is 4096 characters because I'm using
+ ** a static buffer when I calculate them. While fine for most purposes, it is for pathological cases that
+ ** specs are built. I'm not sure how I'll handle this yet.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 31 May 1998
+ ** @see Member
+ ** @see java.lang.Class#getConstructor(Object[])
+ ** @see java.lang.Class#getDeclaredConstructor(Object[])
+ ** @see java.lang.Class#getConstructors()
+ ** @see java.lang.Class#getDeclaredConstructors()
+ **/
+
+public final class Constructor implements Member {
+ private Class declaringClass;
+ private int slot;
+
+ /* This class is uninstantiable except from native code. */
+ private Constructor(Class declaringClass,int slot) {
+ this.declaringClass = declaringClass;
+ this.slot = slot;
+ }
+
+ /** Gets the class that declared this constructor.
+ ** @specnote It is unclear whether this returns the class that
+ ** actually syntactically declared the member, or the
+ ** class where the Constructor object was gotten from.
+ ** @return the class that declared this member.
+ **/
+ public Class getDeclaringClass() {
+ return declaringClass;
+ }
+
+ /** Gets the modifiers this constructor uses. Use the <code>Modifier</code>
+ ** class to interpret the values.
+ ** A Constructor may only have the modifiers public, private and protected.
+ ** @see Modifier
+ ** @return an integer representing the modifiers to this Member.
+ **/
+ public native int getModifiers();
+
+ /** Gets the name of this constructor (the non-qualified name of the class it was declared in).
+ ** @return the name of this constructor.
+ **/
+ public String getName() {
+ return getDeclaringClass().getName();
+ }
+
+ /** Get the parameter list for this constructor.
+ ** @return a list of classes representing the names of the constructor's parameters.
+ **/
+ public native Class[] getParameterTypes();
+
+ /** Get the exception types this constructor says it throws.
+ ** @return a list of classes representing the exception types.
+ **/
+ public native Class[] getExceptionTypes();
+
+ /** Compare two objects to see if they are semantically equivalent.
+ ** Two Constructors are semantically equivalent if they have the same declaring class and the
+ ** same parameter list. <B>Though I really don't see how two different Constructor objects with
+ ** identical parameters could be created.</B>
+ ** @param o the object to compare to.
+ ** @return <code>true<code> if they are equal; <code>false</code> if not.
+ **/
+ public boolean equals(Object o) {
+ return this == o;
+ }
+
+ /** Get the hash code for the Constructor.
+ ** Constructor hash code is the hash code of the declaring class's name.
+ ** @return the hash code for the object.
+ **/
+ public int hashCode() {
+ return getDeclaringClass().getName().hashCode();
+ }
+
+ /** Get a String representation of the Constructor.
+ ** A Constructor's String representation is &lt;modifiers&gt; &lt;classname&gt;(&lt;paramtypes&gt;).
+ ** Example: <code>public java.lang.Thread(java.lang.Runnable,int)</code>
+ ** @return the String representation of the Constructor.
+ **/
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(Modifier.toString(getModifiers()));
+ sb.append(' ');
+ sb.append(getDeclaringClass().getName());
+ sb.append('(');
+ Class[] c = getParameterTypes();
+ if(c.length > 0) {
+ sb.append(c[0].getName());
+ for(int i = 1; i < c.length; i++) {
+ sb.append(',');
+ sb.append(c[i].getName());
+ }
+ }
+ return sb.toString();
+ }
+
+ /** Create a new instance of the object the constructor can construct.
+ ** The constructor will permit widening argument conversions, but not narrowing conversions.
+ ** @param args the arguments to the constructor.
+ ** @return the newly created object.
+ ** @exception InstantiationException if the class is abstract. <B>Never mind that there
+ ** should be no constructors in an abstract class.</B>
+ ** @exception IllegalAccessException if the constructor could not normally be called
+ ** by the Java code (i.e. it is not public).
+ ** @exception IllegalArgumentException if the number of arguments is incorrect, or if the
+ ** arguments cannot be converted to the actual argument
+ ** types, even with a widening conversion.
+ ** @exception InvocationTargetException if the constructor throws an exception.
+ **/
+ public Object newInstance(Object args[])
+ throws InstantiationException,
+ IllegalAccessException,
+ IllegalArgumentException,
+ InvocationTargetException {
+ return constructNative(args, declaringClass, slot);
+ }
+
+ private native Object constructNative(Object[] args, Class declaringClass, int slot);
+}
diff --git a/vm/reference/java/lang/reflect/Field.java b/vm/reference/java/lang/reflect/Field.java
new file mode 100644
index 000000000..c17a83563
--- /dev/null
+++ b/vm/reference/java/lang/reflect/Field.java
@@ -0,0 +1,356 @@
+/*
+ * java.lang.reflect.Field: part of the Java Class Libraries project.
+ * Copyright (C) 1998 John Keiser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package java.lang.reflect;
+
+/**
+ ** The Field class represents a member variable of a class.
+ ** It allows you to read and manipulate that variable.<P>
+ **
+ ** <B>Note:</B> This class returns and accepts types as Classes, even primitive types; there are Class
+ ** types defined that represent each different primitive type. They are <code>java.lang.Boolean.TYPE,
+ ** java.lang.Byte.TYPE, </code>etc. These are not to be confused with the classes
+ ** <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are real classes.<P>
+ **
+ ** Also note that this is not a serializable class. It is entirely feasible to make it serializable
+ ** using the Externalizable interface, but this is on Sun, not me.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 31 May 1998
+ ** @see Member
+ ** @see java.lang.Class#getField(String)
+ ** @see java.lang.Class#getDeclaredField(String)
+ ** @see java.lang.Class#getFields()
+ ** @see java.lang.Class#getDeclaredFields()
+ **/
+public final class Field implements Member {
+ private Class declaringClass;
+ private String name;
+ private int slot;
+
+ /* This class is uninstantiable except natively. */
+ private Field(Class declaringClass, String name, int slot) {
+ this.declaringClass = declaringClass;
+ this.name = name;
+ this.slot = slot;
+ }
+
+ /** Gets the class that declared this field.
+ ** <B>It is unclear whether this returns the class that actually syntactically declared
+ ** the member, or the class where the Field object was gotten from.</B>
+ ** @return the class that declared this member.
+ **/
+ public Class getDeclaringClass() {
+ return declaringClass;
+ }
+
+ /** Gets the modifiers this field uses. Use the <code>Modifier</code>
+ ** class to interpret the values. A field can only have the following
+ ** modifiers: public, private, protected, static, final, transient, and volatile.
+ ** @see Modifier
+ ** @return an integer representing the modifiers to this Member.
+ **/
+ public native int getModifiers();
+
+ /** Gets the name of this field.
+ ** @return the name of this field.
+ **/
+ public String getName() {
+ return name;
+ }
+
+ /** Gets the type of this field.
+ ** @return the type of this field.
+ **/
+ public native Class getType();
+
+ /** Compare two objects to see if they are semantically equivalent.
+ ** Two Fields are semantically equivalent if they have the same declaring class and the
+ ** same name.
+ ** @param o the object to compare to.
+ ** @return <code>true<code> if they are equal; <code>false</code> if not.
+ **/
+ public boolean equals(Object o) {
+ return this == o;
+ }
+
+ /** Get the hash code for the Field.
+ ** The Field hash code is the hash code of its name XOR'd with the hash code of its class name.
+ ** @return the hash code for the object.
+ **/
+ public int hashCode() {
+ return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
+ }
+
+ /** Get a String representation of the Field.
+ ** A Field's String representation is &lt;modifiers&gt; &lt;type&gt; &lt;class&gt;.&lt;fieldname&gt;.
+ ** Example: <code>public transient boolean gnu.parse.Parser.parseComplete</code>
+ ** @return the String representation of the Constructor.
+ **/
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(Modifier.toString(getModifiers()));
+ sb.append(' ');
+ sb.append(getType().getName());
+ sb.append(' ');
+ sb.append(getDeclaringClass().getName());
+ sb.append('.');
+ sb.append(getName());
+ return sb.toString();
+ }
+
+ /** Get the value of this Field. If it is primitive, it will be wrapped in the
+ ** appropriate wrapper type (boolean = java.lang.Boolean)
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to get the value of this Field from.
+ ** @return the value of the Field.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this field is not a field of <code>o</code>.
+ **/
+ public Object get(Object o)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Get the value of this boolean Field.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to get the value of this Field from.
+ ** @return the value of the Field.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this is not a boolean field of <code>o</code>.
+ **/
+ public native boolean getBoolean(Object o)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Get the value of this byte Field.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to get the value of this Field from.
+ ** @return the value of the Field.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this is not a byte field of <code>o</code>.
+ **/
+ public native byte getByte(Object o)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Get the value of this Field as a short.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to get the value of this Field from.
+ ** @return the value of the Field.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is
+ ** a field of <code>o</code> but cannot be converted
+ ** via a widening conversion to a short.
+ **/
+ public native short getShort(Object o)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Get the value of this Field as a char.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to get the value of this Field from.
+ ** @return the value of the Field.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is
+ ** a field of <code>o</code> but cannot be converted
+ ** via a widening conversion to a char.
+ **/
+ public native char getChar(Object o)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Get the value of this Field as an int.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to get the value of this Field from.
+ ** @return the value of the Field.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is
+ ** a field of <code>o</code> but cannot be converted
+ ** via a widening conversion to an int.
+ **/
+ public native int getInt(Object o)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Get the value of this Field as a long.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to get the value of this Field from.
+ ** @return the value of the Field.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is
+ ** a field of <code>o</code> but cannot be converted
+ ** via a widening conversion to a long.
+ **/
+ public native long getLong(Object o)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Get the value of this Field as a float.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to get the value of this Field from.
+ ** @return the value of the Field.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is
+ ** a field of <code>o</code> but cannot be converted
+ ** via a widening conversion to a float.
+ **/
+ public float getFloat(Object o)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Get the value of this Field as a double.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to get the value of this Field from.
+ ** @return the value of the Field.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this is not a field of <code>o</code> or is
+ ** a field of <code>o</code> but cannot be converted
+ ** via a widening conversion to a double.
+ **/
+ public double getDouble(Object o)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Set this Field. If it is a primitive field, the value passed must be wrapped in
+ ** the appropriate wrapped type (boolean = java.lang.Boolean)
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to set this Field on.
+ ** @param value the value to set this Field to.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if <code>value</code> cannot be converted by a
+ ** widening conversion to the underlying type of
+ ** the Field.
+ **/
+ public void set(Object o, Object value)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Set this boolean Field.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to set this Field on.
+ ** @param value the value to set this Field to.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this field is not a primitive boolean field.
+ **/
+ public void setBoolean(Object o, boolean value)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Set this byte Field.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to set this Field on.
+ ** @param value the value to set this Field to.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if a byte cannot be converted via a widening
+ ** conversion to the type of this field.
+ **/
+ public void setByte(Object o, byte value)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Set this short Field.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to set this Field on.
+ ** @param value the value to set this Field to.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if a byte cannot be converted via a widening
+ ** conversion to the type of this field.
+ **/
+ public void setShort(Object o, short value)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Set this char Field.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to set this Field on.
+ ** @param value the value to set this Field to.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if a char cannot be converted via a widening
+ ** conversion to the type of this field.
+ **/
+ public void setChar(Object o, char value)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Set this int Field.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to set this Field on.
+ ** @param value the value to set this Field to.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if an int cannot be converted via a widening
+ ** conversion to the type of this field.
+ **/
+ public void setInt(Object o, int value)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Set this long Field.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to set this Field on.
+ ** @param value the value to set this Field to.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if a long cannot be converted via a widening
+ ** conversion to the type of this field.
+ **/
+ public void setLong(Object o, long value)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Set this float Field.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to set this Field on.
+ ** @param value the value to set this Field to.
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if a float cannot be converted via a widening
+ ** conversion to the type of this field.
+ **/
+ public void setFloat(Object o, float value)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+
+ /** Set this double Field.
+ ** If the field is static, <code>o</code> will be ignored.
+ ** @param o the object to set this Field on.
+ ** @param value the value to set this Field to
+ ** @exception IllegalAccessException if you could not normally access this field
+ ** (i.e. it is not public).
+ ** @exception IllegalArgumentException if this field is not a primitive double field.
+ **/
+ public void setDouble(Object o, double value)
+ throws IllegalAccessException,
+ IllegalArgumentException;
+}
diff --git a/vm/reference/java/lang/reflect/Method.java b/vm/reference/java/lang/reflect/Method.java
new file mode 100644
index 000000000..5f00bb307
--- /dev/null
+++ b/vm/reference/java/lang/reflect/Method.java
@@ -0,0 +1,222 @@
+/*
+ * java.lang.reflect.Method: part of the Java Class Libraries project.
+ * Copyright (C) 1998 John Keiser
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+package java.lang.reflect;
+
+/**
+ ** Method is a class which represents a method.
+ ** You may get information about it and make calls on it.<P>
+ **
+ ** <STRONG>Note:</STRONG> This class returns and accepts types as Classes, even primitive types; there are Class
+ ** types defined that represent each different primitive type. They are <code>java.lang.Boolean.TYPE,
+ ** java.lang.Byte.TYPE, </code>etc. These are not to be confused with the classes
+ ** <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are real classes.<P>
+ **
+ ** <STRONG>Serialization:</STROMG>Note that this is not a serializable class. It is entirely feasible to make it
+ ** serializable, but this is on Sun, not me.<P>
+ **
+ ** <STRONG>Access and Security:</STRONG> Once this Method is created by java.lang.Class (which does its own
+ ** security check), any object may query it for information like parameter types, exception types, etc.
+ ** However, the Method may only be invoked using standard Java language access controls. The JLS says that
+ ** reflective access to all private, public and protected reflective members is granted to any class which
+ ** can be linked against the reflected member. Link-level enforcement is the enforcement of public, private,
+ ** protected and default access rules, based on the caller's relationship to the class (same package,
+ ** subclass, or unrelated). Thus, if you couldn't normally invoke this method from the calling class, you
+ ** can't do it using a Method object either.<P>
+ **
+ ** The relevant section of the VM spec on link-security is <A
+ ** HREF='http://java.sun.com/docs/books/vmspec/html/Concepts.doc.html#22574'>2.16.3</A>, under Resolution.
+ ** A summary of the appropriate rules follows.<P>
+ **
+ ** <STRONG>Summary of access rules</STRONG><BR>
+ ** Two checks are done, and they are the same checks--on both the member's class and the member itself:
+ ** <UL>
+ ** <LI>If the caller is the same class as the member's class, then it can access the member no matter
+ ** what.</LI>
+ ** <LI>If the caller is in the same package as the member's class, then the member's class and the member
+ ** itself must both be public, protected or default access.</LI>
+ ** <LI>If the caller is a subclass of the member's class, then the member's class and the member itself must
+ ** both be public or protected access.</LI>
+ ** <LI>If the caller is in the same package as the member's class, then the member's class and the member must
+ ** be public access.</LI>
+ ** </UL>
+ ** <P>
+ **
+ ** As far as I can tell from the fairly confusing <A
+ ** HREF='http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc.html'>Inner
+ ** Classes Specification</A>, there should be no change to these rules from the addition of inner
+ ** classes in 1.1.<P>
+ **
+ ** <STRONG>Version note:</STRONG> In 1.2, the security checks can be disabled in the AccessibleObject
+ ** interface. But this ain't 1.2. :)<P>
+ **
+ ** <STRONG>BUGS:</STRONG> The maximum size of a signature right now is 4096 characters because I'm using
+ ** a static buffer when I calculate them. While fine for most purposes, it is for pathological cases that
+ ** specs are built. I'm not sure how I'll handle this yet.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 31 May 1998
+ ** @see Member
+ ** @see java.lang.Class#getMethod(String,Object[])
+ ** @see java.lang.Class#getDeclaredMethod(String,Object[])
+ ** @see java.lang.Class#getMethods()
+ ** @see java.lang.Class#getDeclaredMethods()
+ **/
+
+public final class Method implements Member {
+ Class declaringClass;
+ String name;
+ int slot;
+
+ /* This class is uninstantiable. */
+ private Method(Class declaringClass, String name, int slot) {
+ this.declaringClass = declaringClass;
+ this.name = name;
+ this.slot = slot;
+ }
+
+ /** Gets the class that declared this method.
+ ** <STRONG>It is unclear whether this returns the class that actually syntactically declared
+ ** the member, or the class where the Method object was gotten from.</STRONG>
+ ** @return the class that declared this member.
+ **/
+ public Class getDeclaringClass() {
+ return declaringClass;
+ }
+
+ /** Gets the modifiers this method uses. Use the <code>Modifier</code>
+ ** class to interpret the values.
+ ** A Method may only have the modifiers public, private, protected, abstract,
+ ** static, final, synchronized, and native.
+ ** @see Modifier
+ ** @return an integer representing the modifiers to this Member.
+ **/
+ public native int getModifiers();
+
+ /** Gets the name of this method.
+ ** @return the name of this method.
+ **/
+ public String getName() {
+ return name;
+ }
+
+ /** Gets the return type of this method.
+ ** @return the type of this method.
+ **/
+ public native Class getReturnType();
+
+ /** Get the parameter list for this method.
+ ** @return a list of classes representing the names of the method's parameters.
+ **/
+ public native Class[] getParameterTypes();
+
+ /** Get the exception types this method says it throws.
+ ** @return a list of classes representing the exception types.
+ **/
+ public native Class[] getExceptionTypes();
+
+ /** Compare two objects to see if they are semantically equivalent.
+ ** Two Methods are semantically equivalent if they have the same declaring class, name,
+ ** and parameter list. <STRONG>Though I really don't see how two different Method objects
+ ** with identical parameters could be created.</STRONG>
+ ** @param o the object to compare to.
+ ** @return <code>true<code> if they are equal; <code>false</code> if not.
+ **/
+ public boolean equals(Object o) {
+ return this == o;
+ }
+
+ /** Get the hash code for the Method.
+ ** Constructor hash code is the hash code of the declaring class's name XOR'd with the method name.
+ ** @return the hash code for the object.
+ **/
+ public int hashCode() {
+ return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
+ }
+
+ /** Get a String representation of the Constructor.
+ ** A Constructor's String representation is &lt;modifiers&gt; &lt;returntype&gt; &lt;methodname&gt;(&lt;paramtypes&gt;).
+ ** Example: <code>public static int run(java.lang.Runnable,int)</code>
+ ** @return the String representation of the Constructor.
+ **/
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(Modifier.toString(getModifiers()));
+ sb.append(' ');
+ sb.append(getReturnType());
+ sb.append(' ');
+ sb.append(getDeclaringClass().getName());
+ sb.append('.');
+ sb.append(getName());
+ sb.append('(');
+ Class[] c = getParameterTypes();
+ if(c.length > 0) {
+ sb.append(c[0].getName());
+ for(int i = 1; i < c.length; i++) {
+ sb.append(',');
+ sb.append(c[i].getName());
+ }
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+
+
+ /** Invoke the method.<P>
+ ** The method will permit widening argument conversions, but not narrowing conversions.<P>
+ ** For static methods, declaringClass is used for the Method lookup, not the class of the Object
+ ** being invoked on.<P>
+ ** For instance methods, the method in the class of the Object itself is invoked.<P>
+ **
+ ** The permissions and workings of this method are the same as if you had invoked the method in Java
+ ** using ((<declaringClass>)o).<methodName>(<args>). If your object had enough permissions to do
+ ** that, then this call will succeed.<P>
+ **
+ ** <STRONG>Robustness Note:</STRONG> if the method returns an Object of the wrong type somehow, then
+ ** that will not be checked by invoke(). Shouldn't happen anyway, but this information is included
+ ** for completeness.
+ **
+ ** @param o the object to invoke the method on.
+ ** @param args the arguments to the method.
+ ** @return the return value of the method, wrapped in the appropriate wrapper if it is primitive.
+ ** @exception IllegalAccessException if the method could not normally be called
+ ** by the Java code (see note at beginning of class
+ ** for more information).
+ ** @exception IllegalArgumentException if the number of arguments is incorrect; if the
+ ** arguments cannot be converted to the actual argument
+ ** types, even with a widening conversion; for instance
+ ** methods, if the Object invoked on is not of appropriate
+ ** type.
+ ** @exception InvocationTargetException if the method throws an exception.
+ **/
+ public Object invoke(Object o, Object[] args)
+ throws IllegalAccessException,
+ IllegalArgumentException,
+ InvocationTargetException {
+ return invokeNative(o, args, declaringClass, slot);
+ }
+
+ /*
+ * NATIVE HELPERS
+ */
+
+ private native Object invokeNative(Object o, Object[] args,
+ Class declaringClass, int slot);
+}