RFR 8169653: Restore ObjectInputStream::resolveClass call stack default search order

Chris Hegarty chris.hegarty at oracle.com
Tue Dec 6 11:27:19 UTC 2016


Mandy and I exchanged some mails off line, here is updated proposed wording.


> On 21 Nov 2016, at 09:41, Chris Hegarty <chris.hegarty at oracle.com> wrote:
> 
> JDK-8155977 updated ObjectInputStream::resolveClass, and
> resolveProxyClass, to work with the platform class loader, but
> inadvertently removed the text describing the order in which the
> call stack is searched, for the 'loader'.
> 
> The omission, from Java SE 8, is " ... closest such method to the
> currently executing frame". Similar text should be reinstated.

diff --git a/src/java.base/share/classes/java/io/ObjectInputStream.java b/src/java.base/share/classes/java/io/ObjectInputStream.java
--- a/src/java.base/share/classes/java/io/ObjectInputStream.java
+++ b/src/java.base/share/classes/java/io/ObjectInputStream.java
@@ -640,46 +640,45 @@
 
     /**
      * Load the local class equivalent of the specified stream class
      * description.  Subclasses may implement this method to allow classes to
      * be fetched from an alternate source.
      *
      * <p>The corresponding method in <code>ObjectOutputStream</code> is
      * <code>annotateClass</code>.  This method will be invoked only once for
      * each unique class in the stream.  This method can be implemented by
      * subclasses to use an alternate loading mechanism but must return a
      * <code>Class</code> object. Once returned, if the class is not an array
      * class, its serialVersionUID is compared to the serialVersionUID of the
      * serialized class, and if there is a mismatch, the deserialization fails
      * and an {@link InvalidClassException} is thrown.
      *
      * <p>The default implementation of this method in
      * <code>ObjectInputStream</code> returns the result of calling
      * <pre>
      *     Class.forName(desc.getName(), false, loader)
      * </pre>
-     * where <code>loader</code> is determined as follows: if there is a
-     * method on the current thread's stack whose declaring class is not a
-     * <a href="../lang/ClassLoader.html#builtinLoaders">
-     * <em>platform class</em></a>, then <code>loader</code> is
-     * the class loader of such class; otherwise, <code>loader</code>
-     * is the {@linkplain ClassLoader#getPlatformClassLoader()
+     * where <code>loader</code> is the first class loader on the current
+     * thread’s stack (starting from the currently executing method) that is
+     * neither the <a href="../lang/ClassLoader.html#builtinLoaders"><em>
+     * platform class loader</em></a> nor its ancestor; otherwise, <code>
+     * loaded</code> is the {@linkplain ClassLoader#getPlatformClassLoader()
      * platform class loader}.  If this call results in a
      * <code>ClassNotFoundException</code> and the name of the passed
      * <code>ObjectStreamClass</code> instance is the Java language keyword
      * for a primitive type or void, then the <code>Class</code> object
      * representing that primitive type or void will be returned
      * (e.g., an <code>ObjectStreamClass</code> with the name
      * <code>"int"</code> will be resolved to <code>Integer.TYPE</code>).
      * Otherwise, the <code>ClassNotFoundException</code> will be thrown to
      * the caller of this method.
      *
      * @param   desc an instance of class <code>ObjectStreamClass</code>
      * @return  a <code>Class</code> object corresponding to <code>desc</code>
      * @throws  IOException any of the usual Input/Output exceptions.
      * @throws  ClassNotFoundException if class of a serialized object cannot
      *          be found.
      */
     protected Class<?> resolveClass(ObjectStreamClass desc)
         throws IOException, ClassNotFoundException
     {
         String name = desc.getName();
@@ -704,46 +703,45 @@
      *
      * <p>This method is called exactly once for each unique proxy class
      * descriptor in the stream.
      *
      * <p>The corresponding method in <code>ObjectOutputStream</code> is
      * <code>annotateProxyClass</code>.  For a given subclass of
      * <code>ObjectInputStream</code> that overrides this method, the
      * <code>annotateProxyClass</code> method in the corresponding subclass of
      * <code>ObjectOutputStream</code> must write any data or objects read by
      * this method.
      *
      * <p>The default implementation of this method in
      * <code>ObjectInputStream</code> returns the result of calling
      * <code>Proxy.getProxyClass</code> with the list of <code>Class</code>
      * objects for the interfaces that are named in the <code>interfaces</code>
      * parameter.  The <code>Class</code> object for each interface name
      * <code>i</code> is the value returned by calling
      * <pre>
      *     Class.forName(i, false, loader)
      * </pre>
-     * where <code>loader</code> is determined as follows: if there is a
-     * method on the current thread's stack whose declaring class is not a
-     * <a href="../lang/ClassLoader.html#builtinLoaders">
-     * <em>platform class</em></a>, then <code>loader</code> is
-     * the class loader of such class; otherwise, <code>loader</code>
-     * is the {@linkplain ClassLoader#getPlatformClassLoader()
+     * where <code>loader</code> is the first class loader on the current 
+     * thread’s stack (starting from the currently executing method) that is
+     * neither the <a href="../lang/ClassLoader.html#builtinLoaders"><em>
+     * platform class loader</em></a> nor its ancestor; otherwise, <code>
+     * loaded</code> is the {@linkplain ClassLoader#getPlatformClassLoader()
      * platform class loader}.
      * Unless any of the resolved interfaces are non-public, this same value
      * of <code>loader</code> is also the class loader passed to
      * <code>Proxy.getProxyClass</code>; if non-public interfaces are present,
      * their class loader is passed instead (if more than one non-public
      * interface class loader is encountered, an
      * <code>IllegalAccessError</code> is thrown).
      * If <code>Proxy.getProxyClass</code> throws an
      * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code>
      * will throw a <code>ClassNotFoundException</code> containing the
      * <code>IllegalArgumentException</code>.
      *
      * @param interfaces the list of interface names that were
      *                deserialized in the proxy class descriptor
      * @return  a proxy class for the specified interfaces
      * @throws        IOException any exception thrown by the underlying
      *                <code>InputStream</code>
      * @throws        ClassNotFoundException if the proxy class or any of the
      *                named interfaces could not be found
      * @see ObjectOutputStream#annotateProxyClass(Class)


-Chris.

> [1] https://bugs.openjdk.java.net/browse/JDK-8155977



More information about the core-libs-dev mailing list