From 6279b4ab7435030a1c240fa204d349f692925ce6 Mon Sep 17 00:00:00 2001 From: Chris Hegarty <chegar@openjdk.org> Date: Mon, 29 Jun 2015 11:44:53 +0100 Subject: [PATCH] 8103671: More objective stream classes Reviewed-by: rriggs, igerasim --- .../classes/java/io/ObjectStreamClass.java | 158 +++++++++++------- 1 file changed, 102 insertions(+), 56 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java b/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java index 5c3c707768b..77e638b50bd 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java @@ -189,6 +189,9 @@ public class ObjectStreamClass implements Serializable { /** 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 @@ public class ObjectStreamClass implements Serializable { 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 @@ public class ObjectStreamClass implements Serializable { name, "unmatched serializable field(s) declared"); } } + initialized = true; } /** @@ -550,6 +555,14 @@ public class ObjectStreamClass implements Serializable { 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 @@ public class ObjectStreamClass implements Serializable { 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 @@ public class ObjectStreamClass implements Serializable { 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 @@ public class ObjectStreamClass implements Serializable { 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 @@ public class ObjectStreamClass implements Serializable { 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; } /** @@ -758,12 +771,21 @@ public class ObjectStreamClass implements Serializable { 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 * 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 @@ public class ObjectStreamClass implements Serializable { * not apply to serialization of enum constants. */ void checkSerialize() throws InvalidClassException { + requireInitialized(); if (serializeEx != null) { throw serializeEx.newInvalidClassException(); } @@ -788,6 +811,7 @@ public class ObjectStreamClass implements Serializable { * does not apply to deserialization of enum constants. */ void checkDefaultSerialize() throws InvalidClassException { + requireInitialized(); if (defaultSerializeEx != null) { throw defaultSerializeEx.newInvalidClassException(); } @@ -799,6 +823,7 @@ public class ObjectStreamClass implements Serializable { * of the subclass descriptor's bound class. */ ObjectStreamClass getSuperDesc() { + requireInitialized(); return superDesc; } @@ -809,6 +834,7 @@ public class ObjectStreamClass implements Serializable { * associated with this descriptor. */ ObjectStreamClass getLocalDesc() { + requireInitialized(); return localDesc; } @@ -819,6 +845,7 @@ public class ObjectStreamClass implements Serializable { * returned. */ ObjectStreamField[] getFields(boolean copy) { + requireInitialized(); 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. */ 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 @@ public class ObjectStreamClass implements Serializable { * otherwise. */ boolean isProxy() { + requireInitialized(); return isProxy; } @@ -859,6 +888,7 @@ public class ObjectStreamClass implements Serializable { * otherwise. */ boolean isEnum() { + requireInitialized(); return isEnum; } @@ -867,6 +897,7 @@ public class ObjectStreamClass implements Serializable { * otherwise. */ boolean isExternalizable() { + requireInitialized(); return externalizable; } @@ -875,6 +906,7 @@ public class ObjectStreamClass implements Serializable { * otherwise. */ boolean isSerializable() { + requireInitialized(); return serializable; } @@ -883,6 +915,7 @@ public class ObjectStreamClass implements Serializable { * has written its data in 1.2 (block data) format, false otherwise. */ boolean hasBlockExternalData() { + requireInitialized(); return hasBlockExternalData; } @@ -892,6 +925,7 @@ public class ObjectStreamClass implements Serializable { * writeObject() method, false otherwise. */ boolean hasWriteObjectData() { + requireInitialized(); return hasWriteObjectData; } @@ -903,6 +937,7 @@ public class ObjectStreamClass implements Serializable { * accessible no-arg constructor. Otherwise, returns false. */ boolean isInstantiable() { + requireInitialized(); return (cons != null); } @@ -912,6 +947,7 @@ public class ObjectStreamClass implements Serializable { * returns false. */ boolean hasWriteObjectMethod() { + requireInitialized(); return (writeObjectMethod != null); } @@ -921,6 +957,7 @@ public class ObjectStreamClass implements Serializable { * returns false. */ boolean hasReadObjectMethod() { + requireInitialized(); return (readObjectMethod != null); } @@ -930,6 +967,7 @@ public class ObjectStreamClass implements Serializable { * Otherwise, returns false. */ boolean hasReadObjectNoDataMethod() { + requireInitialized(); return (readObjectNoDataMethod != null); } @@ -938,6 +976,7 @@ public class ObjectStreamClass implements Serializable { * defines a conformant writeReplace method. Otherwise, returns false. */ boolean hasWriteReplaceMethod() { + requireInitialized(); return (writeReplaceMethod != null); } @@ -946,6 +985,7 @@ public class ObjectStreamClass implements Serializable { * defines a conformant readResolve method. Otherwise, returns false. */ boolean hasReadResolveMethod() { + requireInitialized(); return (readResolveMethod != null); } @@ -962,6 +1002,7 @@ public class ObjectStreamClass implements Serializable { throws InstantiationException, InvocationTargetException, UnsupportedOperationException { + requireInitialized(); if (cons != null) { try { return cons.newInstance(); @@ -983,6 +1024,7 @@ public class ObjectStreamClass implements Serializable { void invokeWriteObject(Object obj, ObjectOutputStream out) throws IOException, UnsupportedOperationException { + requireInitialized(); if (writeObjectMethod != null) { try { writeObjectMethod.invoke(obj, new Object[]{ out }); @@ -1012,6 +1054,7 @@ public class ObjectStreamClass implements Serializable { throws ClassNotFoundException, IOException, UnsupportedOperationException { + requireInitialized(); if (readObjectMethod != null) { try { readObjectMethod.invoke(obj, new Object[]{ in }); @@ -1042,6 +1085,7 @@ public class ObjectStreamClass implements Serializable { void invokeReadObjectNoData(Object obj) throws IOException, UnsupportedOperationException { + requireInitialized(); if (readObjectNoDataMethod != null) { try { readObjectNoDataMethod.invoke(obj, (Object[]) null); @@ -1070,6 +1114,7 @@ public class ObjectStreamClass implements Serializable { Object invokeWriteReplace(Object obj) throws IOException, UnsupportedOperationException { + requireInitialized(); if (writeReplaceMethod != null) { try { return writeReplaceMethod.invoke(obj, (Object[]) null); @@ -1099,6 +1144,7 @@ public class ObjectStreamClass implements Serializable { Object invokeReadResolve(Object obj) throws IOException, UnsupportedOperationException { + requireInitialized(); if (readResolveMethod != null) { try { return readResolveMethod.invoke(obj, (Object[]) null);