8103671: More objective stream classes

Reviewed-by: rriggs, igerasim
This commit is contained in:
Chris Hegarty 2015-06-29 11:44:53 +01:00
parent d9f0f86bf4
commit 6279b4ab74

@ -189,6 +189,9 @@ public class ObjectStreamClass implements Serializable {
/** superclass descriptor appearing in stream */ /** superclass descriptor appearing in stream */
private ObjectStreamClass superDesc; private ObjectStreamClass superDesc;
/** true if, and only if, the object has been correctly initialized */
private boolean initialized;
/** /**
* Initializes native code. * Initializes native code.
*/ */
@ -266,6 +269,7 @@ public class ObjectStreamClass implements Serializable {
if (cl == null) { if (cl == null) {
return null; return null;
} }
requireInitialized();
if (System.getSecurityManager() != null) { if (System.getSecurityManager() != null) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) { if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) {
@ -533,6 +537,7 @@ public class ObjectStreamClass implements Serializable {
name, "unmatched serializable field(s) declared"); name, "unmatched serializable field(s) declared");
} }
} }
initialized = true;
} }
/** /**
@ -550,6 +555,14 @@ public class ObjectStreamClass implements Serializable {
ObjectStreamClass superDesc) ObjectStreamClass superDesc)
throws InvalidClassException throws InvalidClassException
{ {
ObjectStreamClass osc = null;
if (cl != null) {
osc = lookup(cl, true);
if (!osc.isProxy) {
throw new InvalidClassException(
"cannot bind proxy descriptor to a non-proxy class");
}
}
this.cl = cl; this.cl = cl;
this.resolveEx = resolveEx; this.resolveEx = resolveEx;
this.superDesc = superDesc; this.superDesc = superDesc;
@ -557,21 +570,17 @@ public class ObjectStreamClass implements Serializable {
serializable = true; serializable = true;
suid = Long.valueOf(0); suid = Long.valueOf(0);
fields = NO_FIELDS; fields = NO_FIELDS;
if (osc != null) {
if (cl != null) { localDesc = osc;
localDesc = lookup(cl, true);
if (!localDesc.isProxy) {
throw new InvalidClassException(
"cannot bind proxy descriptor to a non-proxy class");
}
name = localDesc.name; name = localDesc.name;
externalizable = localDesc.externalizable; externalizable = localDesc.externalizable;
cons = localDesc.cons;
writeReplaceMethod = localDesc.writeReplaceMethod; writeReplaceMethod = localDesc.writeReplaceMethod;
readResolveMethod = localDesc.readResolveMethod; readResolveMethod = localDesc.readResolveMethod;
deserializeEx = localDesc.deserializeEx; deserializeEx = localDesc.deserializeEx;
cons = localDesc.cons;
} }
fieldRefl = getReflector(fields, localDesc); fieldRefl = getReflector(fields, localDesc);
initialized = true;
} }
/** /**
@ -583,11 +592,57 @@ public class ObjectStreamClass implements Serializable {
ObjectStreamClass superDesc) ObjectStreamClass superDesc)
throws InvalidClassException throws InvalidClassException
{ {
long suid = Long.valueOf(model.getSerialVersionUID());
ObjectStreamClass osc = null;
if (cl != null) {
osc = lookup(cl, true);
if (osc.isProxy) {
throw new InvalidClassException(
"cannot bind non-proxy descriptor to a proxy class");
}
if (model.isEnum != osc.isEnum) {
throw new InvalidClassException(model.isEnum ?
"cannot bind enum descriptor to a non-enum class" :
"cannot bind non-enum descriptor to an enum class");
}
if (model.serializable == osc.serializable &&
!cl.isArray() &&
suid != osc.getSerialVersionUID()) {
throw new InvalidClassException(osc.name,
"local class incompatible: " +
"stream classdesc serialVersionUID = " + suid +
", local class serialVersionUID = " +
osc.getSerialVersionUID());
}
if (!classNamesEqual(model.name, osc.name)) {
throw new InvalidClassException(osc.name,
"local class name incompatible with stream class " +
"name \"" + model.name + "\"");
}
if (!model.isEnum) {
if ((model.serializable == osc.serializable) &&
(model.externalizable != osc.externalizable)) {
throw new InvalidClassException(osc.name,
"Serializable incompatible with Externalizable");
}
if ((model.serializable != osc.serializable) ||
(model.externalizable != osc.externalizable) ||
!(model.serializable || model.externalizable)) {
deserializeEx = new ExceptionInfo(
osc.name, "class invalid for deserialization");
}
}
}
this.cl = cl; this.cl = cl;
this.resolveEx = resolveEx; this.resolveEx = resolveEx;
this.superDesc = superDesc; this.superDesc = superDesc;
name = model.name; name = model.name;
suid = Long.valueOf(model.getSerialVersionUID()); this.suid = suid;
isProxy = false; isProxy = false;
isEnum = model.isEnum; isEnum = model.isEnum;
serializable = model.serializable; serializable = model.serializable;
@ -598,53 +653,8 @@ public class ObjectStreamClass implements Serializable {
primDataSize = model.primDataSize; primDataSize = model.primDataSize;
numObjFields = model.numObjFields; numObjFields = model.numObjFields;
if (cl != null) { if (osc != null) {
localDesc = lookup(cl, true); localDesc = osc;
if (localDesc.isProxy) {
throw new InvalidClassException(
"cannot bind non-proxy descriptor to a proxy class");
}
if (isEnum != localDesc.isEnum) {
throw new InvalidClassException(isEnum ?
"cannot bind enum descriptor to a non-enum class" :
"cannot bind non-enum descriptor to an enum class");
}
if (serializable == localDesc.serializable &&
!cl.isArray() &&
suid.longValue() != localDesc.getSerialVersionUID())
{
throw new InvalidClassException(localDesc.name,
"local class incompatible: " +
"stream classdesc serialVersionUID = " + suid +
", local class serialVersionUID = " +
localDesc.getSerialVersionUID());
}
if (!classNamesEqual(name, localDesc.name)) {
throw new InvalidClassException(localDesc.name,
"local class name incompatible with stream class " +
"name \"" + name + "\"");
}
if (!isEnum) {
if ((serializable == localDesc.serializable) &&
(externalizable != localDesc.externalizable))
{
throw new InvalidClassException(localDesc.name,
"Serializable incompatible with Externalizable");
}
if ((serializable != localDesc.serializable) ||
(externalizable != localDesc.externalizable) ||
!(serializable || externalizable))
{
deserializeEx = new ExceptionInfo(
localDesc.name, "class invalid for deserialization");
}
}
cons = localDesc.cons;
writeObjectMethod = localDesc.writeObjectMethod; writeObjectMethod = localDesc.writeObjectMethod;
readObjectMethod = localDesc.readObjectMethod; readObjectMethod = localDesc.readObjectMethod;
readObjectNoDataMethod = localDesc.readObjectNoDataMethod; readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
@ -653,10 +663,13 @@ public class ObjectStreamClass implements Serializable {
if (deserializeEx == null) { if (deserializeEx == null) {
deserializeEx = localDesc.deserializeEx; deserializeEx = localDesc.deserializeEx;
} }
cons = localDesc.cons;
} }
fieldRefl = getReflector(fields, localDesc); fieldRefl = getReflector(fields, localDesc);
// reassign to matched fields so as to reflect local unshared settings // reassign to matched fields so as to reflect local unshared settings
fields = fieldRefl.getFields(); fields = fieldRefl.getFields();
initialized = true;
} }
/** /**
@ -758,12 +771,21 @@ public class ObjectStreamClass implements Serializable {
return resolveEx; return resolveEx;
} }
/**
* Throws InternalError if not initialized.
*/
private final void requireInitialized() {
if (!initialized)
throw new InternalError("Unexpected call when not initialized");
}
/** /**
* Throws an InvalidClassException if object instances referencing this * Throws an InvalidClassException if object instances referencing this
* class descriptor should not be allowed to deserialize. This method does * class descriptor should not be allowed to deserialize. This method does
* not apply to deserialization of enum constants. * not apply to deserialization of enum constants.
*/ */
void checkDeserialize() throws InvalidClassException { void checkDeserialize() throws InvalidClassException {
requireInitialized();
if (deserializeEx != null) { if (deserializeEx != null) {
throw deserializeEx.newInvalidClassException(); throw deserializeEx.newInvalidClassException();
} }
@ -775,6 +797,7 @@ public class ObjectStreamClass implements Serializable {
* not apply to serialization of enum constants. * not apply to serialization of enum constants.
*/ */
void checkSerialize() throws InvalidClassException { void checkSerialize() throws InvalidClassException {
requireInitialized();
if (serializeEx != null) { if (serializeEx != null) {
throw serializeEx.newInvalidClassException(); throw serializeEx.newInvalidClassException();
} }
@ -788,6 +811,7 @@ public class ObjectStreamClass implements Serializable {
* does not apply to deserialization of enum constants. * does not apply to deserialization of enum constants.
*/ */
void checkDefaultSerialize() throws InvalidClassException { void checkDefaultSerialize() throws InvalidClassException {
requireInitialized();
if (defaultSerializeEx != null) { if (defaultSerializeEx != null) {
throw defaultSerializeEx.newInvalidClassException(); throw defaultSerializeEx.newInvalidClassException();
} }
@ -799,6 +823,7 @@ public class ObjectStreamClass implements Serializable {
* of the subclass descriptor's bound class. * of the subclass descriptor's bound class.
*/ */
ObjectStreamClass getSuperDesc() { ObjectStreamClass getSuperDesc() {
requireInitialized();
return superDesc; return superDesc;
} }
@ -809,6 +834,7 @@ public class ObjectStreamClass implements Serializable {
* associated with this descriptor. * associated with this descriptor.
*/ */
ObjectStreamClass getLocalDesc() { ObjectStreamClass getLocalDesc() {
requireInitialized();
return localDesc; return localDesc;
} }
@ -819,6 +845,7 @@ public class ObjectStreamClass implements Serializable {
* returned. * returned.
*/ */
ObjectStreamField[] getFields(boolean copy) { ObjectStreamField[] getFields(boolean copy) {
requireInitialized();
return copy ? fields.clone() : fields; return copy ? fields.clone() : fields;
} }
@ -829,6 +856,7 @@ public class ObjectStreamClass implements Serializable {
* types only. Returns matching field, or null if no match found. * types only. Returns matching field, or null if no match found.
*/ */
ObjectStreamField getField(String name, Class<?> type) { ObjectStreamField getField(String name, Class<?> type) {
requireInitialized();
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i]; ObjectStreamField f = fields[i];
if (f.getName().equals(name)) { if (f.getName().equals(name)) {
@ -851,6 +879,7 @@ public class ObjectStreamClass implements Serializable {
* otherwise. * otherwise.
*/ */
boolean isProxy() { boolean isProxy() {
requireInitialized();
return isProxy; return isProxy;
} }
@ -859,6 +888,7 @@ public class ObjectStreamClass implements Serializable {
* otherwise. * otherwise.
*/ */
boolean isEnum() { boolean isEnum() {
requireInitialized();
return isEnum; return isEnum;
} }
@ -867,6 +897,7 @@ public class ObjectStreamClass implements Serializable {
* otherwise. * otherwise.
*/ */
boolean isExternalizable() { boolean isExternalizable() {
requireInitialized();
return externalizable; return externalizable;
} }
@ -875,6 +906,7 @@ public class ObjectStreamClass implements Serializable {
* otherwise. * otherwise.
*/ */
boolean isSerializable() { boolean isSerializable() {
requireInitialized();
return serializable; return serializable;
} }
@ -883,6 +915,7 @@ public class ObjectStreamClass implements Serializable {
* has written its data in 1.2 (block data) format, false otherwise. * has written its data in 1.2 (block data) format, false otherwise.
*/ */
boolean hasBlockExternalData() { boolean hasBlockExternalData() {
requireInitialized();
return hasBlockExternalData; return hasBlockExternalData;
} }
@ -892,6 +925,7 @@ public class ObjectStreamClass implements Serializable {
* writeObject() method, false otherwise. * writeObject() method, false otherwise.
*/ */
boolean hasWriteObjectData() { boolean hasWriteObjectData() {
requireInitialized();
return hasWriteObjectData; return hasWriteObjectData;
} }
@ -903,6 +937,7 @@ public class ObjectStreamClass implements Serializable {
* accessible no-arg constructor. Otherwise, returns false. * accessible no-arg constructor. Otherwise, returns false.
*/ */
boolean isInstantiable() { boolean isInstantiable() {
requireInitialized();
return (cons != null); return (cons != null);
} }
@ -912,6 +947,7 @@ public class ObjectStreamClass implements Serializable {
* returns false. * returns false.
*/ */
boolean hasWriteObjectMethod() { boolean hasWriteObjectMethod() {
requireInitialized();
return (writeObjectMethod != null); return (writeObjectMethod != null);
} }
@ -921,6 +957,7 @@ public class ObjectStreamClass implements Serializable {
* returns false. * returns false.
*/ */
boolean hasReadObjectMethod() { boolean hasReadObjectMethod() {
requireInitialized();
return (readObjectMethod != null); return (readObjectMethod != null);
} }
@ -930,6 +967,7 @@ public class ObjectStreamClass implements Serializable {
* Otherwise, returns false. * Otherwise, returns false.
*/ */
boolean hasReadObjectNoDataMethod() { boolean hasReadObjectNoDataMethod() {
requireInitialized();
return (readObjectNoDataMethod != null); return (readObjectNoDataMethod != null);
} }
@ -938,6 +976,7 @@ public class ObjectStreamClass implements Serializable {
* defines a conformant writeReplace method. Otherwise, returns false. * defines a conformant writeReplace method. Otherwise, returns false.
*/ */
boolean hasWriteReplaceMethod() { boolean hasWriteReplaceMethod() {
requireInitialized();
return (writeReplaceMethod != null); return (writeReplaceMethod != null);
} }
@ -946,6 +985,7 @@ public class ObjectStreamClass implements Serializable {
* defines a conformant readResolve method. Otherwise, returns false. * defines a conformant readResolve method. Otherwise, returns false.
*/ */
boolean hasReadResolveMethod() { boolean hasReadResolveMethod() {
requireInitialized();
return (readResolveMethod != null); return (readResolveMethod != null);
} }
@ -962,6 +1002,7 @@ public class ObjectStreamClass implements Serializable {
throws InstantiationException, InvocationTargetException, throws InstantiationException, InvocationTargetException,
UnsupportedOperationException UnsupportedOperationException
{ {
requireInitialized();
if (cons != null) { if (cons != null) {
try { try {
return cons.newInstance(); return cons.newInstance();
@ -983,6 +1024,7 @@ public class ObjectStreamClass implements Serializable {
void invokeWriteObject(Object obj, ObjectOutputStream out) void invokeWriteObject(Object obj, ObjectOutputStream out)
throws IOException, UnsupportedOperationException throws IOException, UnsupportedOperationException
{ {
requireInitialized();
if (writeObjectMethod != null) { if (writeObjectMethod != null) {
try { try {
writeObjectMethod.invoke(obj, new Object[]{ out }); writeObjectMethod.invoke(obj, new Object[]{ out });
@ -1012,6 +1054,7 @@ public class ObjectStreamClass implements Serializable {
throws ClassNotFoundException, IOException, throws ClassNotFoundException, IOException,
UnsupportedOperationException UnsupportedOperationException
{ {
requireInitialized();
if (readObjectMethod != null) { if (readObjectMethod != null) {
try { try {
readObjectMethod.invoke(obj, new Object[]{ in }); readObjectMethod.invoke(obj, new Object[]{ in });
@ -1042,6 +1085,7 @@ public class ObjectStreamClass implements Serializable {
void invokeReadObjectNoData(Object obj) void invokeReadObjectNoData(Object obj)
throws IOException, UnsupportedOperationException throws IOException, UnsupportedOperationException
{ {
requireInitialized();
if (readObjectNoDataMethod != null) { if (readObjectNoDataMethod != null) {
try { try {
readObjectNoDataMethod.invoke(obj, (Object[]) null); readObjectNoDataMethod.invoke(obj, (Object[]) null);
@ -1070,6 +1114,7 @@ public class ObjectStreamClass implements Serializable {
Object invokeWriteReplace(Object obj) Object invokeWriteReplace(Object obj)
throws IOException, UnsupportedOperationException throws IOException, UnsupportedOperationException
{ {
requireInitialized();
if (writeReplaceMethod != null) { if (writeReplaceMethod != null) {
try { try {
return writeReplaceMethod.invoke(obj, (Object[]) null); return writeReplaceMethod.invoke(obj, (Object[]) null);
@ -1099,6 +1144,7 @@ public class ObjectStreamClass implements Serializable {
Object invokeReadResolve(Object obj) Object invokeReadResolve(Object obj)
throws IOException, UnsupportedOperationException throws IOException, UnsupportedOperationException
{ {
requireInitialized();
if (readResolveMethod != null) { if (readResolveMethod != null) {
try { try {
return readResolveMethod.invoke(obj, (Object[]) null); return readResolveMethod.invoke(obj, (Object[]) null);