This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Patch: Serialization merge from GNU Classpath
- From: Bryce McKinlay <mckinlay at redhat dot com>
- To: java-patches at gcc dot gnu dot org
- Date: Mon, 21 Feb 2005 16:48:15 -0500
- Subject: Patch: Serialization merge from GNU Classpath
This patch merges the latest serialization code from GNU Classpath into
libgcj. Although there are a few things I'm not entirely happy with in
the current classpath implementation, the benefits of merging the two
codebases outweigh those concerns, and it will be better to fix these
things in general rather than making fixes that are only in libgcj. Once
I check in a much smaller patch to Classpath, we'll have a 100% merged
serialization implementation for the first time!
As a side-effect, this also fixes a long-standing bug where final fields
in libgcj could be set via reflection (we couldn't fix this bug because
it would break the old serialization code).
We have several new mauve PASSes with this patch:
--- batch_run.clean.out 2005-02-21 12:17:58.000000000 -0500
+++ batch_run.patched.out 2005-02-21 11:43:52.000000000 -0500
@@ -5497,10 +5497,10 @@
PASS: gnu.testlet.java.io.ObjectInputOutput.OutputTest: Unserializable:
gnu.testlet.java.io.ObjectInputOutput.Test$BadField (x = 0, y = 0, o =
null) (number 1)
PASS: gnu.testlet.java.io.ObjectInputOutput.SerTest (number 1)
PASS: gnu.testlet.java.io.ObjectInputOutput.SerTest (number 2)
-FAIL: gnu.testlet.java.io.ObjectInputOutput.Deserializable: Wrong
exception (number 1)
+PASS: gnu.testlet.java.io.ObjectInputOutput.Deserializable: Deserialize
gnu.testlet.java.io.ObjectInputOutput.Deserializable$Serialized1 (number 1)
FAIL: gnu.testlet.java.io.ObjectInputOutput.Deserializable: Was
expecting an InvalidClassException (number 1)
PASS: gnu.testlet.java.io.ObjectInputOutput.ExtTest (number 1)
-FAIL: gnu.testlet.java.io.ObjectInputOutput.ExtTest (number 2)
+PASS: gnu.testlet.java.io.ObjectInputOutput.ExtTest (number 2)
PASS: gnu.testlet.java.io.ObjectStreamClass.ProxyTest: zero
serialVersionUID (number 1)
PASS: gnu.testlet.java.io.ObjectStreamClass.ProxyTest: zero
ObjectStreamFields (number 1)
PASS: gnu.testlet.java.io.ObjectStreamClass.ProxyTest: getField(any)
returns null (number 1)
@@ -6367,10 +6367,10 @@
PASS: gnu.testlet.java.lang.Class.init (number 13)
FAIL: gnu.testlet.java.lang.Class.init (number 14)
PASS: gnu.testlet.java.lang.Class.init (number 15)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface
java.lang.Cloneable (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface
java.lang.Comparable (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface
java.io.Serializable (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface
java.io.Externalizable (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface
java.lang.Cloneable (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface
java.lang.Comparable (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface
java.io.Serializable (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface
java.io.Externalizable (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.String
(number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.Number
(number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class
java.lang.Boolean (number 1)
@@ -6382,33 +6382,33 @@
PASS: gnu.testlet.java.lang.Class.serialization: class
java.text.DateFormat (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.awt.Point
(number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class
java.awt.Rectangle (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class
java.awt.geom.Rectangle2D (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class
java.awt.geom.Rectangle2D$Double (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class
java.awt.geom.Line2D (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class
java.awt.geom.Arc2D (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class
java.awt.geom.RoundRectangle2D (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class
java.awt.Graphics2D (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class
java.awt.geom.Rectangle2D (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class
java.awt.geom.Rectangle2D$Double (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class
java.awt.geom.Line2D (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class
java.awt.geom.Arc2D (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class
java.awt.geom.RoundRectangle2D (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class
java.awt.Graphics2D (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class
javax.swing.table.DefaultTableModel (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface
java.awt.LayoutManager (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class
java.lang.reflect.Array (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.lang.Object
(number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface
java.awt.LayoutManager (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class
java.lang.reflect.Array (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.Object
(number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.Class
(number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class
java.lang.Throwable (number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class
java.io.IOException (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: class java.lang.Void
(number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: class java.lang.Void
(number 1)
PASS: gnu.testlet.java.lang.Class.serialization: class
java.io.ObjectStreamClass (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface
java.util.Collection (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface
java.util.Set (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: interface
java.util.SortedSet (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: boolean (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: byte (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: short (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: char (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: int (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: long (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: float (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: double (number 1)
-FAIL: gnu.testlet.java.lang.Class.serialization: void (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface
java.util.Collection (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface
java.util.Set (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: interface
java.util.SortedSet (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: boolean (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: byte (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: short (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: char (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: int (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: long (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: float (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: double (number 1)
+PASS: gnu.testlet.java.lang.Class.serialization: void (number 1)
PASS: gnu.testlet.java.lang.Double.DoubleTest: Error: test_Basics
failed - 2 (number 1)
PASS: gnu.testlet.java.lang.Double.DoubleTest: Error: test_Basics
failed - 3 (number 1)
PASS: gnu.testlet.java.lang.Double.DoubleTest: Error: test_Basics
failed - 4 (number 1)
Bryce
2005-02-21 Bryce McKinlay <mckinlay@redhat.com>
Merge serialization from GNU Classpath.
* gcj/method.h: Add missing #includes.
* java/io/ObjectInputStream.java (readClassDescriptor): Check for
primitive class IDs on the stream here...
(resolveClass): ...not here.
* java/io/ObjectStreamField.java: Use VMObjectStream class calls to set
fields.
* java/io/VMObjectStreamClass.java (setDoubleNative, setFloatNative,
setLongNative, setIntNative, setShortNative, setCharNative,
setByteNative, setBooleanNative, setObjectNative): New native methods.
* java/io/natObjectInputStream.cc (allocateObject): Add new parameters
from Classpath's version. Use _Jv_FromReflectedConstructor(). Call
the constructor here.
(callConstructor): Removed.
(getCallersClassLoader): Removed.
* java/lang/reflect/Field.java (setByte, setShort, setInt, setLong,
setFloat, setDouble, setChar, setBoolean): Add 'checkFinal' parameter
to control whether setting final field values is permitted. Call
getAddr() with checkFinal parameter instead of setAddr().
* java/lang/reflect/natField.cc (getType): Lookup and resolve field
only if not done already.
(getAddr): Add checkFinal parameter. Do the final field check only if
checkFinal is set.
(setAddr): Removed.
2005-02-21 Mark Wielaard <mark@klomp.org>
# Fixes bug #11957
* java/io/ObjectInputStream.java (resolveClass): Don't check "void"
twice.
2005-02-21 Mark Wielaard <mark@klomp.org>
Fixes bug #11618.
* java/io/ObjectInputStream.java (readClassDescriptor): Handle classes
without a super class and us ObjectStreamClass.lookupForClassObject().
(resolveClass): Check for primitive types.
(lookupClass): Return null when argument is null.
2005-02-21 Jeroen Frijters <jeroen@frijters.net>
* java/io/ObjectInputStream.java
(readObject): Fix to consume TC_ENDBLOCKDATA after readExternal.
2005-02-21 Jeroen Frijters <jeroen@frijters.net>
* java/io/ObjectOutputStream.java
(writeObject, callWriteMethod): Replaced reflection with accessing
cached info in ObjectStreamClass.
(getMethod): Removed.
* java/io/ObjectStreamClass.java
(findMethod): Added check to make sure the method found has the
right modifiers.
(cacheMethods): Added writeReplace and writeObject methods.
(setFlags): Look at new writeObjectMethod field instead of doing
reflection again.
(writeReplaceMethod): New field.
(writeObjectMethod): New field.
2005-02-21 Guilhem Lavaux <guilhem@kaffe.org>
Jeroen Frijters <jeroen@frijters.net>
* java/io/ObjectInputStream.java
(newObject): Changed prototype. Get a constructor reflect object
directly.
(callConstructor): Removed.
(allocateObject): Changed prototype.
(readClassDescriptor): Build the constructor reflection directly.
(readObject): Invoke newObject using the new prototype.
* java/io/ObjectStreamClass.java
(firstNonSerializableParent): Removed.
(firstNonSerializableParentConstructor): Added.
Index: gcj/method.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/method.h,v
retrieving revision 1.6
diff -u -r1.6 method.h
--- gcj/method.h 7 Mar 2000 19:55:24 -0000 1.6
+++ gcj/method.h 21 Feb 2005 20:48:07 -0000
@@ -12,6 +12,8 @@
#define __GCJ_METHOD_H__
#include <java/lang/Class.h>
+#include <java/lang/reflect/Constructor.h>
+#include <java/lang/reflect/Method.h>
extern inline jmethodID
_Jv_FromReflectedMethod (java::lang::reflect::Method *method)
Index: java/io/ObjectInputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectInputStream.java,v
retrieving revision 1.40
diff -u -r1.40 ObjectInputStream.java
--- java/io/ObjectInputStream.java 20 Feb 2005 21:18:30 -0000 1.40
+++ java/io/ObjectInputStream.java 21 Feb 2005 20:48:07 -0000
@@ -43,6 +43,7 @@
import gnu.java.io.ObjectIdentityWrapper;
import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -122,15 +123,6 @@
*/
public final Object readObject() throws ClassNotFoundException, IOException
{
- if (callersClassLoader == null)
- {
- callersClassLoader = getCallersClassLoader ();
- if (Configuration.DEBUG && dump)
- {
- dumpElementln ("CallersClassLoader = " + callersClassLoader);
- }
- }
-
if (this.useSubclassMethod)
return readObjectOverride();
@@ -272,7 +264,7 @@
readArrayElements(array, componentType);
if(dump)
for (int i = 0, len = Array.getLength(array); i < len; i++)
- dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i));
+ dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i));
ret_val = processResolution(null, array, handle);
break;
}
@@ -302,13 +294,18 @@
obj.readExternal(this);
if (read_from_blocks)
- setBlockDataMode(oldmode);
+ {
+ setBlockDataMode(oldmode);
+ if (!oldmode)
+ if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
+ throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
+ }
ret_val = processResolution(osc, obj, handle);
break;
} // end if (osc.realClassIsExternalizable)
- Object obj = newObject(clazz, osc.firstNonSerializableParent);
+ Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
int handle = assignNewHandle(obj);
Object prevObject = this.currentObject;
@@ -399,8 +396,6 @@
setBlockDataMode(old_mode);
this.isDeserializing = was_deserializing;
-
- depth -= 2;
depth -= 2;
@@ -506,7 +501,8 @@
flags, fields);
assignNewHandle(osc);
- ClassLoader currentLoader = currentLoader();
+ if (callersClassLoader == null)
+ callersClassLoader = currentLoader();
for (int i = 0; i < field_count; i++)
{
@@ -527,12 +523,40 @@
class_name = String.valueOf(type_code);
fields[i] =
- new ObjectStreamField(field_name, class_name, currentLoader);
+ new ObjectStreamField(field_name, class_name, callersClassLoader);
}
/* Now that fields have been read we may resolve the class
* (and read annotation if needed). */
- Class clazz = resolveClass(osc);
+ Class clazz;
+ try
+ {
+ clazz = resolveClass(osc);
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ // Maybe it was an primitive class?
+ if (name.equals("void"))
+ clazz = Void.TYPE;
+ else if (name.equals("boolean"))
+ clazz = Boolean.TYPE;
+ else if (name.equals("byte"))
+ clazz = Byte.TYPE;
+ else if (name.equals("short"))
+ clazz = Short.TYPE;
+ else if (name.equals("char"))
+ clazz = Character.TYPE;
+ else if (name.equals("int"))
+ clazz = Integer.TYPE;
+ else if (name.equals("long"))
+ clazz = Long.TYPE;
+ else if (name.equals("float"))
+ clazz = Float.TYPE;
+ else if (name.equals("double"))
+ clazz = Double.TYPE;
+ else
+ throw cnfe;
+ }
boolean oldmode = setBlockDataMode(true);
osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
@@ -542,16 +566,45 @@
// find the first non-serializable, non-abstract
// class in clazz's inheritance hierarchy
Class first_nonserial = clazz.getSuperclass();
- while (Serializable.class.isAssignableFrom(first_nonserial)
- || Modifier.isAbstract(first_nonserial.getModifiers()))
+ // Maybe it is a primitive class, those don't have a super class,
+ // or Object itself. Otherwise we can keep getting the superclass
+ // till we hit the Object class, or some other non-serializable class.
+
+ if (first_nonserial == null)
+ first_nonserial = clazz;
+ else
+ while (Serializable.class.isAssignableFrom(first_nonserial)
+ || Modifier.isAbstract(first_nonserial.getModifiers()))
first_nonserial = first_nonserial.getSuperclass();
- osc.firstNonSerializableParent = first_nonserial;
+ final Class local_constructor_class = first_nonserial;
+
+ osc.firstNonSerializableParentConstructor =
+ (Constructor)AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ try
+ {
+ Constructor c = local_constructor_class.
+ getDeclaredConstructor(new Class[0]);
+ if (Modifier.isPrivate(c.getModifiers()))
+ return null;
+ return c;
+ }
+ catch (NoSuchMethodException e)
+ {
+ // error will be reported later, in newObject()
+ return null;
+ }
+ }
+ });
+
osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
ObjectStreamField[] stream_fields = osc.fields;
- ObjectStreamField[] real_fields = ObjectStreamClass.lookup(clazz).fields;
+ ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
int stream_idx = 0;
@@ -717,6 +770,15 @@
protected Class resolveClass(ObjectStreamClass osc)
throws ClassNotFoundException, IOException
{
+ if (callersClassLoader == null)
+ {
+ callersClassLoader = currentLoader ();
+ if (Configuration.DEBUG && dump)
+ {
+ dumpElementln ("CallersClassLoader = " + callersClassLoader);
+ }
+ }
+
return Class.forName(osc.getName(), true, callersClassLoader);
}
@@ -750,8 +812,10 @@
*/
private ObjectStreamClass lookupClass(Class clazz)
{
- ObjectStreamClass oclazz;
+ if (clazz == null)
+ return null;
+ ObjectStreamClass oclazz;
oclazz = (ObjectStreamClass)classLookupTable.get(clazz);
if (oclazz == null)
return ObjectStreamClass.lookup(clazz);
@@ -1767,14 +1831,14 @@
// returns a new instance of REAL_CLASS that has been constructed
// only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
- private Object newObject (Class real_class, Class constructor_class)
- throws ClassNotFoundException
+ private Object newObject (Class real_class, Constructor constructor)
+ throws ClassNotFoundException, IOException
{
+ if (constructor == null)
+ throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
try
{
- Object obj = allocateObject (real_class);
- callConstructor (constructor_class, obj);
- return obj;
+ return allocateObject(real_class, constructor.getDeclaringClass(), constructor);
}
catch (InstantiationException e)
{
@@ -1810,8 +1874,6 @@
* @return The current class loader in the calling stack.
*/
private static native ClassLoader currentClassLoader (SecurityManager sm);
-
- private native ClassLoader getCallersClassLoader();
private void callReadMethod (Method readObject, Class klass, Object obj)
throws ClassNotFoundException, IOException
@@ -1844,11 +1906,9 @@
prereadFields = null;
}
- private native Object allocateObject (Class clazz)
+ private native Object allocateObject(Class clazz, Class constr_clazz, Constructor constructor)
throws InstantiationException;
- private native void callConstructor (Class clazz, Object obj);
-
private static final int BUFFER_SIZE = 1024;
private DataInputStream realInputStream;
@@ -1870,9 +1930,8 @@
private Hashtable classLookupTable;
private GetField prereadFields;
- private static boolean dump = false && Configuration.DEBUG;
-
private ClassLoader callersClassLoader;
+ private static boolean dump;
// The nesting depth for debugging output
private int depth = 0;
Index: java/io/ObjectOutputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectOutputStream.java,v
retrieving revision 1.31
diff -u -r1.31 ObjectOutputStream.java
--- java/io/ObjectOutputStream.java 25 Nov 2004 03:47:02 -0000 1.31
+++ java/io/ObjectOutputStream.java 21 Feb 2005 20:48:07 -0000
@@ -250,6 +250,11 @@
break;
}
+ Class clazz = obj.getClass();
+ ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
+ if (osc == null)
+ throw new NotSerializableException(clazz.getName());
+
if ((replacementEnabled || obj instanceof Serializable)
&& ! replaceDone)
{
@@ -257,19 +262,11 @@
if (obj instanceof Serializable)
{
- Method m = null;
try
{
- Class classArgs[] = {};
- m = getMethod(obj.getClass(), "writeReplace",
- classArgs);
- // m can't be null by definition since an
- // exception would have been thrown so a check
- // for null is not needed.
- obj = m.invoke(obj, new Object[] {});
- }
- catch (NoSuchMethodException ignore)
- {
+ Method m = osc.writeReplaceMethod;
+ if (m != null)
+ obj = m.invoke(obj, new Object[0]);
}
catch (IllegalAccessException ignore)
{
@@ -294,11 +291,6 @@
break;
}
- Class clazz = obj.getClass();
- ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
- if (osc == null)
- throw new NotSerializableException(clazz.getName());
-
if (clazz.isArray ())
{
realOutput.writeByte(TC_ARRAY);
@@ -347,8 +339,8 @@
fieldsAlreadyWritten = false;
if (currentObjectStreamClass.hasWriteMethod())
{
- if (dump)
- dumpElementln ("WRITE METHOD CALLED FOR: " + obj);
+ if (dump)
+ dumpElementln ("WRITE METHOD CALLED FOR: " + obj);
setBlockDataMode(true);
callWriteMethod(obj, currentObjectStreamClass);
setBlockDataMode(false);
@@ -358,10 +350,10 @@
}
else
{
- if (dump)
- dumpElementln ("WRITE FIELDS CALLED FOR: " + obj);
- writeFields(obj, currentObjectStreamClass);
- }
+ if (dump)
+ dumpElementln ("WRITE FIELDS CALLED FOR: " + obj);
+ writeFields(obj, currentObjectStreamClass);
+ }
}
this.currentObject = prevObject;
@@ -1261,18 +1253,11 @@
private void callWriteMethod(Object obj, ObjectStreamClass osc)
throws IOException
{
- Class klass = osc.forClass();
currentPutField = null;
try
{
- Class classArgs[] = {ObjectOutputStream.class};
- Method m = getMethod(klass, "writeObject", classArgs);
- Object args[] = {this};
- m.invoke(obj, args);
- }
- catch (NoSuchMethodException nsme)
- {
- // Nothing.
+ Object args[] = {this};
+ osc.writeObjectMethod.invoke(obj, args);
}
catch (InvocationTargetException x)
{
@@ -1285,7 +1270,8 @@
IOException ioe
= new IOException("Exception thrown from writeObject() on " +
- klass + ": " + exception.getClass().getName());
+ osc.forClass().getName() + ": " +
+ exception.getClass().getName());
ioe.initCause(exception);
throw ioe;
}
@@ -1293,7 +1279,8 @@
{
IOException ioe
= new IOException("Failure invoking writeObject() on " +
- klass + ": " + x.getClass().getName());
+ osc.forClass().getName() + ": " +
+ x.getClass().getName());
ioe.initCause(x);
throw ioe;
}
@@ -1535,15 +1522,6 @@
}
}
- private Method getMethod (Class klass, String name, Class[] args)
- throws java.lang.NoSuchMethodException
- {
- final Method m = klass.getDeclaredMethod(name, args);
- setAccessible.setMember(m);
- AccessController.doPrivileged(setAccessible);
- return m;
- }
-
private void dumpElementln (String msg)
{
for (int i = 0; i < depth; i++)
Index: java/io/ObjectStreamClass.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectStreamClass.java,v
retrieving revision 1.24
diff -u -r1.24 ObjectStreamClass.java
--- java/io/ObjectStreamClass.java 9 Oct 2004 10:22:25 -0000 1.24
+++ java/io/ObjectStreamClass.java 21 Feb 2005 20:48:07 -0000
@@ -452,27 +452,33 @@
}
private Method findMethod(Method[] methods, String name, Class[] params,
- Class returnType)
+ Class returnType, boolean mustBePrivate)
{
outer:
- for(int i = 0; i < methods.length; i++)
+ for (int i = 0; i < methods.length; i++)
{
- if(methods[i].getName().equals(name) &&
- methods[i].getReturnType() == returnType)
+ final Method m = methods[i];
+ int mods = m.getModifiers();
+ if (Modifier.isStatic(mods)
+ || (mustBePrivate && !Modifier.isPrivate(mods)))
+ {
+ continue;
+ }
+
+ if (m.getName().equals(name)
+ && m.getReturnType() == returnType)
{
- Class[] mp = methods[i].getParameterTypes();
- if(mp.length == params.length)
+ Class[] mp = m.getParameterTypes();
+ if (mp.length == params.length)
{
- for(int j = 0; j < mp.length; j++)
+ for (int j = 0; j < mp.length; j++)
{
- if(mp[j] != params[j])
+ if (mp[j] != params[j])
{
continue outer;
}
}
- final Method m = methods[i];
- SetAccessibleAction setAccessible = new SetAccessibleAction(m);
- AccessController.doPrivileged(setAccessible);
+ AccessController.doPrivileged(new SetAccessibleAction(m));
return m;
}
}
@@ -485,9 +491,14 @@
Method[] methods = forClass().getDeclaredMethods();
readObjectMethod = findMethod(methods, "readObject",
new Class[] { ObjectInputStream.class },
- Void.TYPE);
+ Void.TYPE, true);
+ writeObjectMethod = findMethod(methods, "writeObject",
+ new Class[] { ObjectOutputStream.class },
+ Void.TYPE, true);
readResolveMethod = findMethod(methods, "readResolve",
- new Class[0], Object.class);
+ new Class[0], Object.class, false);
+ writeReplaceMethod = findMethod(methods, "writeReplace",
+ new Class[0], Object.class, false);
}
private ObjectStreamClass(Class cl)
@@ -517,20 +528,8 @@
// only set this bit if CL is NOT Externalizable
flags |= ObjectStreamConstants.SC_SERIALIZABLE;
- try
- {
- Method writeMethod = cl.getDeclaredMethod("writeObject",
- writeMethodArgTypes);
- int modifiers = writeMethod.getModifiers();
-
- if (writeMethod.getReturnType() == Void.TYPE
- && Modifier.isPrivate(modifiers)
- && !Modifier.isStatic(modifiers))
- flags |= ObjectStreamConstants.SC_WRITE_METHOD;
- }
- catch(NoSuchMethodException oh_well)
- {
- }
+ if (writeObjectMethod != null)
+ flags |= ObjectStreamConstants.SC_WRITE_METHOD;
}
@@ -851,11 +850,11 @@
{
return (Externalizable)constructor.newInstance(null);
}
- catch(Throwable t)
+ catch(Exception x)
{
throw (InvalidClassException)
new InvalidClassException(clazz.getName(),
- "Unable to instantiate").initCause(t);
+ "Unable to instantiate").initCause(x);
}
}
@@ -884,10 +883,12 @@
Method readObjectMethod;
Method readResolveMethod;
+ Method writeReplaceMethod;
+ Method writeObjectMethod;
boolean realClassIsSerializable;
boolean realClassIsExternalizable;
ObjectStreamField[] fieldMapping;
- Class firstNonSerializableParent;
+ Constructor firstNonSerializableParentConstructor;
private Constructor constructor; // default constructor for Externalizable
boolean isProxyClass = false;
@@ -896,34 +897,33 @@
// but it will avoid showing up as a discrepancy when comparing SUIDs.
private static final long serialVersionUID = -6120832682080437368L;
-}
-
-// interfaces are compared only by name
-class InterfaceComparator implements Comparator
-{
- public int compare(Object o1, Object o2)
+ // interfaces are compared only by name
+ private static final class InterfaceComparator implements Comparator
{
- return ((Class) o1).getName().compareTo(((Class) o2).getName());
+ public int compare(Object o1, Object o2)
+ {
+ return ((Class) o1).getName().compareTo(((Class) o2).getName());
+ }
}
-}
-// Members (Methods and Constructors) are compared first by name,
-// conflicts are resolved by comparing type signatures
-class MemberComparator implements Comparator
-{
- public int compare(Object o1, Object o2)
+ // Members (Methods and Constructors) are compared first by name,
+ // conflicts are resolved by comparing type signatures
+ private static final class MemberComparator implements Comparator
{
- Member m1 = (Member) o1;
- Member m2 = (Member) o2;
+ public int compare(Object o1, Object o2)
+ {
+ Member m1 = (Member) o1;
+ Member m2 = (Member) o2;
- int comp = m1.getName().compareTo(m2.getName());
+ int comp = m1.getName().compareTo(m2.getName());
- if (comp == 0)
- return TypeSignature.getEncodingOfMember(m1).
- compareTo(TypeSignature.getEncodingOfMember(m2));
- else
- return comp;
+ if (comp == 0)
+ return TypeSignature.getEncodingOfMember(m1).
+ compareTo(TypeSignature.getEncodingOfMember(m2));
+ else
+ return comp;
+ }
}
}
Index: java/io/ObjectStreamField.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/ObjectStreamField.java,v
retrieving revision 1.12
diff -u -r1.12 ObjectStreamField.java
--- java/io/ObjectStreamField.java 25 Sep 2004 09:47:45 -0000 1.12
+++ java/io/ObjectStreamField.java 21 Feb 2005 20:48:10 -0000
@@ -367,109 +367,46 @@
final void setBooleanField(Object obj, boolean val)
{
- try
- {
- field.setBoolean(obj, val);
- }
- catch(IllegalAccessException x)
- {
- throw new InternalError(x.getMessage());
- }
+ VMObjectStreamClass.setBooleanNative(field, obj, val);
}
final void setByteField(Object obj, byte val)
{
- try
- {
- field.setByte(obj, val);
- }
- catch(IllegalAccessException x)
- {
- throw new InternalError(x.getMessage());
- }
+ VMObjectStreamClass.setByteNative(field, obj, val);
}
final void setCharField(Object obj, char val)
{
- try
- {
- field.setChar(obj, val);
- }
- catch(IllegalAccessException x)
- {
- throw new InternalError(x.getMessage());
- }
+ VMObjectStreamClass.setCharNative(field, obj, val);
}
final void setShortField(Object obj, short val)
{
- try
- {
- field.setShort(obj, val);
- }
- catch(IllegalAccessException x)
- {
- throw new InternalError(x.getMessage());
- }
+ VMObjectStreamClass.setShortNative(field, obj, val);
}
final void setIntField(Object obj, int val)
{
- try
- {
- field.setInt(obj, val);
- }
- catch(IllegalAccessException x)
- {
- throw new InternalError(x.getMessage());
- }
+ VMObjectStreamClass.setIntNative(field, obj, val);
}
final void setLongField(Object obj, long val)
{
- try
- {
- field.setLong(obj, val);
- }
- catch(IllegalAccessException x)
- {
- throw new InternalError(x.getMessage());
- }
+ VMObjectStreamClass.setLongNative(field, obj, val);
}
final void setFloatField(Object obj, float val)
{
- try
- {
- field.setFloat(obj, val);
- }
- catch(IllegalAccessException x)
- {
- throw new InternalError(x.getMessage());
- }
+ VMObjectStreamClass.setFloatNative(field, obj, val);
}
final void setDoubleField(Object obj, double val)
{
- try
- {
- field.setDouble(obj, val);
- }
- catch(IllegalAccessException x)
- {
- throw new InternalError(x.getMessage());
- }
+ VMObjectStreamClass.setDoubleNative(field, obj, val);
}
final void setObjectField(Object obj, Object val)
{
- try
- {
- field.set(obj, val);
- }
- catch(IllegalAccessException x)
- {
- throw new InternalError(x.getMessage());
- }
+ VMObjectStreamClass.setObjectNative(field, obj, val);
}
}
Index: java/io/VMObjectStreamClass.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/VMObjectStreamClass.java,v
retrieving revision 1.1
diff -u -r1.1 VMObjectStreamClass.java
--- java/io/VMObjectStreamClass.java 20 Jan 2003 06:46:28 -0000 1.1
+++ java/io/VMObjectStreamClass.java 21 Feb 2005 20:48:10 -0000
@@ -38,7 +38,7 @@
package java.io;
-import java.lang.reflect.Method;
+import java.lang.reflect.Field;
final class VMObjectStreamClass
{
@@ -47,4 +47,94 @@
* (a.k.a. <clinit>).
*/
static native boolean hasClassInitializer (Class clazz);
+
+ /**
+ * Sets the value of the specified "double" field, allowing final values
+ * to be assigned.
+ *
+ * @param field Field to set the value.
+ * @param obj Instance which will have its field set.
+ * @param val Value to put in the field.
+ */
+ static native void setDoubleNative(Field field, Object obj, double val);
+
+ /**
+ * Sets the value of the specified "float" field, allowing final values
+ * to be assigned.
+ *
+ * @param field Field to set the value.
+ * @param obj Instance which will have its field set.
+ * @param val Value to put in the field.
+ */
+ static native void setFloatNative(Field field, Object obj, float val);
+
+ /**
+ * Sets the value of the specified "long" field, allowing final values
+ * to be assigned.
+ *
+ * @param field Field to set the value.
+ * @param obj Instance which will have its field set.
+ * @param val Value to put in the field.
+ */
+ static native void setLongNative(Field field, Object obj, long val);
+
+ /**
+ * Sets the value of the specified "int" field, allowing final values
+ * to be assigned.
+ *
+ * @param field Field to set the value.
+ * @param obj Instance which will have its field set.
+ * @param val Value to put in the field.
+ */
+ static native void setIntNative(Field field, Object obj, int val);
+
+ /**
+ * Sets the value of the specified "short" field, allowing final values
+ * to be assigned.
+ *
+ * @param field Field to set the value.
+ * @param obj Instance which will have its field set.
+ * @param val Value to put in the field.
+ */
+ static native void setShortNative(Field field, Object obj, short val);
+
+ /**
+ * Sets the value of the specified "char" field, allowing final values
+ * to be assigned.
+ *
+ * @param field Field to set the value.
+ * @param obj Instance which will have its field set.
+ * @param val Value to put in the field.
+ */
+ static native void setCharNative(Field field, Object obj, char val);
+
+ /**
+ * Sets the value of the specified "byte" field, allowing final values
+ * to be assigned.
+ *
+ * @param field Field to set the value.
+ * @param obj Instance which will have its field set.
+ * @param val Value to put in the field.
+ */
+ static native void setByteNative(Field field, Object obj, byte val);
+
+ /**
+ * Sets the value of the specified "boolean" field, allowing final values
+ * to be assigned.
+ *
+ * @param field Field to set the value.
+ * @param obj Instance which will have its field set.
+ * @param val Value to put in the field.
+ */
+ static native void setBooleanNative(Field field, Object obj, boolean val);
+
+ /**
+ * Sets the value of the specified object field, allowing final values
+ * to be assigned.
+ *
+ * @param field Field to set the value.
+ * @param obj Instance which will have its field set.
+ * @param val Value to put in the field.
+ */
+ static native void setObjectNative(Field field, Object obj, Object val);
}
Index: java/io/natObjectInputStream.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/natObjectInputStream.cc,v
retrieving revision 1.8
diff -u -r1.8 natObjectInputStream.cc
--- java/io/natObjectInputStream.cc 21 Jun 2004 16:52:14 -0000 1.8
+++ java/io/natObjectInputStream.cc 21 Feb 2005 20:48:10 -0000
@@ -12,6 +12,7 @@
#include <gcj/cni.h>
#include <jvm.h>
+#include <gcj/method.h>
#include <java/io/ObjectInputStream$GetField.h>
#include <java/io/ObjectInputStream.h>
@@ -21,6 +22,8 @@
#include <java/lang/reflect/Method.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/SecurityManager.h>
+#include <java/lang/reflect/Constructor.h>
+#include <java/lang/reflect/Method.h>
#ifdef DEBUG
#include <java/lang/System.h>
@@ -28,7 +31,8 @@
#endif
jobject
-java::io::ObjectInputStream::allocateObject (jclass klass)
+java::io::ObjectInputStream::allocateObject (jclass klass, jclass,
+ ::java::lang::reflect::Constructor *ctr)
{
jobject obj = NULL;
using namespace java::lang::reflect;
@@ -41,21 +45,15 @@
else
{
obj = _Jv_AllocObject (klass);
- }
+ }
}
catch (jthrowable t)
{
return NULL;
}
- return obj;
-}
-
+ jmethodID meth = _Jv_FromReflectedConstructor (ctr);
-void
-java::io::ObjectInputStream::callConstructor (jclass klass, jobject obj)
-{
- jstring init_name = JvNewStringLatin1 ("<init>");
// This is a bit inefficient, and a bit of a hack, since we don't
// actually use the Method and since what is returned isn't
// technically a Method. We can't use Method.invoke as it looks up
@@ -63,36 +61,12 @@
JArray<jclass> *arg_types
= (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
NULL);
- java::lang::reflect::Method *m = klass->getPrivateMethod (init_name,
- arg_types);
+
// We lie about this being a constructor. If we put `true' here
// then _Jv_CallAnyMethodA would try to allocate the object for us.
- jmethodID meth = (jmethodID) ((char *) (klass->methods)
- + m->offset);
_Jv_CallAnyMethodA (obj, JvPrimClass (void), meth, false, arg_types, NULL);
-}
-java::lang::ClassLoader*
-java::io::ObjectInputStream::getCallersClassLoader ()
-{
- java::lang::ClassLoader *loader = NULL;
- gnu::gcj::runtime::StackTrace *t
- = new gnu::gcj::runtime::StackTrace(4);
- java::lang::Class *klass = NULL;
- try
- {
- for (int i = 2; !klass; i++)
- {
- klass = t->classAt (i);
- }
- loader = klass->getClassLoaderInternal();
- }
- catch (::java::lang::ArrayIndexOutOfBoundsException *e)
- {
- // FIXME: RuntimeError
- }
-
- return loader;
+ return obj;
}
java::lang::ClassLoader*
Index: java/io/natVMObjectStreamClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/io/natVMObjectStreamClass.cc,v
retrieving revision 1.1
diff -u -r1.1 natVMObjectStreamClass.cc
--- java/io/natVMObjectStreamClass.cc 20 Jan 2003 06:46:28 -0000 1.1
+++ java/io/natVMObjectStreamClass.cc 21 Feb 2005 20:48:10 -0000
@@ -13,11 +13,75 @@
#include <java/io/VMObjectStreamClass.h>
#include <java/lang/Class.h>
+#include <java/lang/reflect/Field.h>
+
+using namespace java::lang::reflect;
jboolean
java::io::VMObjectStreamClass::hasClassInitializer (jclass klass)
{
+ if (klass->isPrimitive())
+ return false;
_Jv_Method *meth = _Jv_GetMethodLocal(klass, gcj::clinit_name,
gcj::void_signature);
return (meth != NULL);
}
+
+void
+java::io::VMObjectStreamClass::setDoubleNative (Field *f, jobject obj,
+ jdouble val)
+{
+ f->setDouble (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setFloatNative (Field *f, jobject obj,
+ jfloat val)
+{
+ f->setFloat (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setLongNative (Field *f, jobject obj, jlong val)
+{
+ f->setLong (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setIntNative (Field *f, jobject obj, jint val)
+{
+ f->setInt (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setShortNative (Field *f, jobject obj,
+ jshort val)
+{
+ f->setShort (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setCharNative (Field *f, jobject obj, jchar val)
+{
+ f->setChar (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setByteNative (Field *f, jobject obj, jbyte val)
+{
+ f->setByte (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setBooleanNative (Field *f, jobject obj,
+ jboolean val)
+{
+ f->setBoolean (NULL, obj, val, false);
+}
+
+void
+java::io::VMObjectStreamClass::setObjectNative (Field *f, jobject obj,
+ jobject val)
+{
+ f->set (NULL, obj, val, f->getType(), false);
+}
Index: java/lang/reflect/Field.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/Field.java,v
retrieving revision 1.9
diff -u -r1.9 Field.java
--- java/lang/reflect/Field.java 21 Jul 2003 01:54:06 -0000 1.9
+++ java/lang/reflect/Field.java 21 Feb 2005 20:48:10 -0000
@@ -23,6 +23,9 @@
// Offset in bytes from the start of declaringClass's fields array.
private int offset;
+ // The Class (or primitive TYPE) of this field.
+ private Class type;
+
// This is instantiated by Class sometimes, but it uses C++ and
// avoids the Java protection check.
Field ()
@@ -136,76 +139,79 @@
public void setByte (Object obj, byte b)
throws IllegalArgumentException, IllegalAccessException
{
- setByte(null, obj, b);
+ setByte(null, obj, b, true);
}
public void setShort (Object obj, short s)
throws IllegalArgumentException, IllegalAccessException
{
- setShort(null, obj, s);
+ setShort(null, obj, s, true);
}
public void setInt (Object obj, int i)
throws IllegalArgumentException, IllegalAccessException
{
- setInt(null, obj, i);
+ setInt(null, obj, i, true);
}
public void setLong (Object obj, long l)
throws IllegalArgumentException, IllegalAccessException
{
- setLong(null, obj, l);
+ setLong(null, obj, l, true);
}
public void setFloat (Object obj, float f)
throws IllegalArgumentException, IllegalAccessException
{
- setFloat(null, obj, f);
+ setFloat(null, obj, f, true);
}
public void setDouble (Object obj, double d)
throws IllegalArgumentException, IllegalAccessException
{
- setDouble(null, obj, d);
+ setDouble(null, obj, d, true);
}
public void setChar (Object obj, char c)
throws IllegalArgumentException, IllegalAccessException
{
- setChar(null, obj, c);
+ setChar(null, obj, c, true);
}
public void setBoolean (Object obj, boolean b)
throws IllegalArgumentException, IllegalAccessException
{
- setBoolean(null, obj, b);
+ setBoolean(null, obj, b, true);
}
- private native void setByte (Class caller, Object obj, byte b)
+ native void setByte (Class caller, Object obj, byte b, boolean checkFinal)
throws IllegalArgumentException, IllegalAccessException;
- private native void setShort (Class caller, Object obj, short s)
+ native void setShort (Class caller, Object obj, short s, boolean checkFinal)
throws IllegalArgumentException, IllegalAccessException;
- private native void setInt (Class caller, Object obj, int i)
+ native void setInt (Class caller, Object obj, int i, boolean checkFinal)
throws IllegalArgumentException, IllegalAccessException;
- private native void setLong (Class caller, Object obj, long l)
+ native void setLong (Class caller, Object obj, long l, boolean checkFinal)
throws IllegalArgumentException, IllegalAccessException;
- private native void setFloat (Class caller, Object obj, float f)
+ native void setFloat (Class caller, Object obj, float f, boolean checkFinal)
throws IllegalArgumentException, IllegalAccessException;
- private native void setDouble (Class caller, Object obj, double d)
+ native void setDouble (Class caller, Object obj, double d,
+ boolean checkFinal)
throws IllegalArgumentException, IllegalAccessException;
- private native void setChar (Class caller, Object obj, char c)
+ native void setChar (Class caller, Object obj, char c, boolean checkFinal)
throws IllegalArgumentException, IllegalAccessException;
- private native void setBoolean (Class caller, Object obj, boolean b)
+ native void setBoolean (Class caller, Object obj, boolean b,
+ boolean checkFinal)
throws IllegalArgumentException, IllegalAccessException;
- private native void set (Class caller, Object obj, Object val, Class type)
+ native void set (Class caller, Object obj, Object val, Class type,
+ boolean checkFinal)
throws IllegalArgumentException, IllegalAccessException;
public void set (Object object, Object value)
@@ -219,23 +225,23 @@
{
Class type = getType();
if (! type.isPrimitive())
- set(caller, object, value, type);
+ set(caller, object, value, type, true);
else if (value instanceof Byte)
- setByte(caller, object, ((Byte) value).byteValue());
+ setByte(caller, object, ((Byte) value).byteValue(), true);
else if (value instanceof Short)
- setShort (caller, object, ((Short) value).shortValue());
+ setShort (caller, object, ((Short) value).shortValue(), true);
else if (value instanceof Integer)
- setInt(caller, object, ((Integer) value).intValue());
+ setInt(caller, object, ((Integer) value).intValue(), true);
else if (value instanceof Long)
- setLong(caller, object, ((Long) value).longValue());
+ setLong(caller, object, ((Long) value).longValue(), true);
else if (value instanceof Float)
- setFloat(caller, object, ((Float) value).floatValue());
+ setFloat(caller, object, ((Float) value).floatValue(), true);
else if (value instanceof Double)
- setDouble(caller, object, ((Double) value).doubleValue());
+ setDouble(caller, object, ((Double) value).doubleValue(), true);
else if (value instanceof Character)
- setChar(caller, object, ((Character) value).charValue());
+ setChar(caller, object, ((Character) value).charValue(), true);
else if (value instanceof Boolean)
- setBoolean(caller, object, ((Boolean) value).booleanValue());
+ setBoolean(caller, object, ((Boolean) value).booleanValue(), true);
else
throw new IllegalArgumentException();
}
Index: java/lang/reflect/natField.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/reflect/natField.cc,v
retrieving revision 1.16
diff -u -r1.16 natField.cc
--- java/lang/reflect/natField.cc 25 Nov 2004 03:47:05 -0000 1.16
+++ java/lang/reflect/natField.cc 21 Feb 2005 20:48:10 -0000
@@ -45,14 +45,19 @@
jclass
java::lang::reflect::Field::getType ()
{
- jfieldID fld = _Jv_FromReflectedField (this);
- JvSynchronize sync (declaringClass);
- _Jv_Linker::resolve_field (fld, declaringClass->getClassLoaderInternal ());
- return fld->type;
+ if (type == NULL)
+ {
+ jfieldID fld = _Jv_FromReflectedField (this);
+ JvSynchronize sync (declaringClass);
+ _Jv_Linker::resolve_field (fld, declaringClass->getClassLoaderInternal ());
+ type = fld->type;
+ }
+ return type;
}
static void*
-getAddr (java::lang::reflect::Field* field, jclass caller, jobject obj)
+getAddr (java::lang::reflect::Field* field, jclass caller, jobject obj,
+ jboolean checkFinal)
{
// FIXME: we know CALLER is NULL here. At one point we planned to
// have the compiler insert the caller as a hidden argument in some
@@ -63,6 +68,12 @@
jfieldID fld = _Jv_FromReflectedField (field);
_Jv_ushort flags = fld->getModifiers();
+
+ // Setting a final field is usually not allowed.
+ if (checkFinal
+ && field->getModifiers() & java::lang::reflect::Modifier::FINAL)
+ throw new java::lang::IllegalAccessException(JvNewStringUTF
+ ("Field is final"));
// Check accessibility, if required.
if (! (Modifier::isPublic (flags) || field->isAccessible()))
@@ -180,56 +191,56 @@
jboolean
java::lang::reflect::Field::getBoolean (jclass caller, jobject obj)
{
- return ::getBoolean (this->getType(), getAddr (this, caller, obj));
+ return ::getBoolean (this->getType(), getAddr (this, caller, obj, false));
}
jchar
java::lang::reflect::Field::getChar (jclass caller, jobject obj)
{
- return ::getChar (this->getType(), getAddr (this, caller, obj));
+ return ::getChar (this->getType(), getAddr (this, caller, obj, false));
}
jbyte
java::lang::reflect::Field::getByte (jclass caller, jobject obj)
{
- return ::getByte (this->getType(), getAddr (this, caller, obj));
+ return ::getByte (this->getType(), getAddr (this, caller, obj, false));
}
jshort
java::lang::reflect::Field::getShort (jclass caller, jobject obj)
{
- return ::getShort (this->getType(), getAddr (this, caller, obj));
+ return ::getShort (this->getType(), getAddr (this, caller, obj, false));
}
jint
java::lang::reflect::Field::getInt (jclass caller, jobject obj)
{
- return ::getInt (this->getType(), getAddr (this, caller, obj));
+ return ::getInt (this->getType(), getAddr (this, caller, obj, false));
}
jlong
java::lang::reflect::Field::getLong (jclass caller, jobject obj)
{
- return ::getLong (this->getType(), getAddr (this, caller, obj));
+ return ::getLong (this->getType(), getAddr (this, caller, obj, false));
}
jfloat
java::lang::reflect::Field::getFloat (jclass caller, jobject obj)
{
- return ::getFloat (this->getType(), getAddr (this, caller, obj));
+ return ::getFloat (this->getType(), getAddr (this, caller, obj, false));
}
jdouble
java::lang::reflect::Field::getDouble (jclass caller, jobject obj)
{
- return ::getDouble (this->getType(), getAddr (this, caller, obj));
+ return ::getDouble (this->getType(), getAddr (this, caller, obj, false));
}
jobject
java::lang::reflect::Field::get (jclass caller, jobject obj)
{
jclass type = this->getType();
- void* addr = getAddr (this, caller, obj);
+ void* addr = getAddr (this, caller, obj, false);
if (! type->isPrimitive ())
return * (jobject*) addr;
if (type == JvPrimClass (double))
@@ -257,16 +268,6 @@
throw new java::lang::IllegalArgumentException;
}
-static void*
-setAddr (java::lang::reflect::Field* field, jclass caller, jobject obj)
-{
- void *addr = getAddr(field, caller, obj);
- if (!field->isAccessible()
- && field->getModifiers() & java::lang::reflect::Modifier::FINAL)
- throw new java::lang::IllegalAccessException();
- return addr;
-}
-
static void
setBoolean (jclass type, void *addr, jboolean value)
{
@@ -378,57 +379,66 @@
}
void
-java::lang::reflect::Field::setBoolean (jclass caller, jobject obj, jboolean b)
+java::lang::reflect::Field::setBoolean (jclass caller, jobject obj, jboolean b,
+ jboolean checkFinal)
{
- ::setBoolean (this->getType(), setAddr (this, caller, obj), b);
+ ::setBoolean (this->getType(), getAddr (this, caller, obj, checkFinal), b);
}
void
-java::lang::reflect::Field::setChar (jclass caller, jobject obj, jchar c)
+java::lang::reflect::Field::setChar (jclass caller, jobject obj, jchar c,
+ jboolean checkFinal)
{
- ::setChar (this->getType(), setAddr (this, caller, obj), c);
+ ::setChar (this->getType(), getAddr (this, caller, obj, checkFinal), c);
}
void
-java::lang::reflect::Field::setByte (jclass caller, jobject obj, jbyte b)
+java::lang::reflect::Field::setByte (jclass caller, jobject obj, jbyte b,
+ jboolean checkFinal)
{
- ::setByte (this->getType(), setAddr (this, caller, obj), b);
+ ::setByte (this->getType(), getAddr (this, caller, obj, checkFinal), b);
}
void
-java::lang::reflect::Field::setShort (jclass caller, jobject obj, jshort s)
+java::lang::reflect::Field::setShort (jclass caller, jobject obj, jshort s,
+ jboolean checkFinal)
{
- ::setShort (this->getType(), setAddr (this, caller, obj), s);
+ ::setShort (this->getType(), getAddr (this, caller, obj, checkFinal), s);
}
void
-java::lang::reflect::Field::setInt (jclass caller, jobject obj, jint i)
+java::lang::reflect::Field::setInt (jclass caller, jobject obj, jint i,
+ jboolean checkFinal)
{
- ::setInt (this->getType(), setAddr (this, caller, obj), i);
+ ::setInt (this->getType(), getAddr (this, caller, obj, checkFinal), i);
}
void
-java::lang::reflect::Field::setLong (jclass caller, jobject obj, jlong l)
+java::lang::reflect::Field::setLong (jclass caller, jobject obj, jlong l,
+ jboolean checkFinal)
{
- ::setLong (this->getType(), setAddr (this, caller, obj), l);
+ ::setLong (this->getType(), getAddr (this, caller, obj, checkFinal), l);
}
+
void
-java::lang::reflect::Field::setFloat (jclass caller, jobject obj, jfloat f)
+java::lang::reflect::Field::setFloat (jclass caller, jobject obj, jfloat f,
+ jboolean checkFinal)
{
- ::setFloat (this->getType(), setAddr (this, caller, obj), f);
+ ::setFloat (this->getType(), getAddr (this, caller, obj, checkFinal), f);
}
void
-java::lang::reflect::Field::setDouble (jclass caller, jobject obj, jdouble d)
+java::lang::reflect::Field::setDouble (jclass caller, jobject obj, jdouble d,
+ jboolean checkFinal)
{
- ::setDouble (this->getType(), setAddr (this, caller, obj), d);
+ ::setDouble (this->getType(), getAddr (this, caller, obj, checkFinal), d);
}
void
java::lang::reflect::Field::set (jclass caller, jobject object, jobject value,
- jclass type)
+ jclass type, jboolean checkFinal)
{
- void* addr = setAddr (this, caller, object);
+ void* addr = getAddr (this, caller, object, checkFinal);
if (value != NULL && ! _Jv_IsInstanceOf (value, type))
throw new java::lang::IllegalArgumentException;
* (jobject*) addr = value;