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