[ 
https://issues.apache.org/jira/browse/GROOVY-12676?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18137469#comment-18137469
 ] 

ASF GitHub Bot commented on GROOVY-12676:
-----------------------------------------

codeconsole opened a new pull request, #3197:
URL: https://github.com/apache/groovy/pull/3197

   `withObjectInputStream(ClassLoader)` and `newObjectInputStream(ClassLoader)` 
fail with `ClassNotFoundException: int` for any stream that holds a primitive 
`Class`. That includes `[int.class]` and a dehydrated closure such as `{ int x 
-> x }.dehydrate()`, whose `parameterTypes` holds `int.class`. The InputStream, 
File and Path variants all fail, and so does the `clone()` generated by 
`@AutoClone(style=SERIALIZATION)`. The same stream reads fine through 
`withObjectInputStream` without a class loader.
   
   ```groovy
   def bytes = new ByteArrayOutputStream()
   bytes.withObjectOutputStream { it.writeObject([int.class]) }
   new 
ByteArrayInputStream(bytes.toByteArray()).withObjectInputStream(getClass().classLoader)
 { it.readObject() }
   // java.lang.ClassNotFoundException: int
   ```
   
   Seen in 4.0.33, 5.0.8 and 6.0.0 too.
   
   `IOGroovyMethods.newObjectInputStream(InputStream, ClassLoader)` overrides 
`ObjectInputStream.resolveClass` with `Class.forName`, which cannot load 
primitive types. All the class-loader-aware variants go through this override. 
The JDK's `resolveClass` falls back to a table of primitive types (`boolean` 
through `double`, plus `void`) when `Class.forName` fails, and the override now 
does the same. The given class loader is still tried first; a class it cannot 
see still fails with `ClassNotFoundException`, since the override does not fall 
back to `super.resolveClass`, which would resolve through a different loader.
   
   ## Tests
   
   These fail without the change:
   - `BinaryStreamsTest`: 
`testWithObjectStreamAndClassLoaderReadsPrimitiveClasses`, 
`testWithObjectStreamAndClassLoaderReadsDehydratedClosureWithPrimitiveParameters`
 and `testWithObjectStreamAndClassLoaderStillResolvesClassesThroughThatLoader`.
   - `CanonicalComponentsTransformTest`: 
`testCloningWithSerializablePrimitiveClassField` and 
`testCloningWithSerializablePrimitiveClassFieldCompileStatic`.
   - 
`NioExtensionsTest.testWithObjectInputStreamAndClassLoaderReadsPrimitiveClasses`.
   
   `IOGroovyMethodsTest`, `BinaryStreamsTest`, 
`CanonicalComponentsTransformTest`, `AutoCloneTransformTest`, 
`StreamClassloaderInScriptTest`, `Groovy11272`, 
`ClosureSerializationCycleTest`, `SerializableCompatibilityTest`, 
`ClosureTest`, `RecordTest`, `NamedValueTest`, `IntRangeTest` and 
`org.apache.groovy.nio.*` pass. The Checkstyle and CodeNarc gates pass.
   




> withObjectInputStream(ClassLoader) fails with ClassNotFoundException for 
> serialized primitive classes such as int.class
> -----------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12676
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12676
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 4.0.33, 5.0.8, 7.0.0-alpha-1, 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> {code:groovy}
> def bytes = new ByteArrayOutputStream()
> bytes.withObjectOutputStream { it.writeObject([int.class, void.class]) }
> new 
> ByteArrayInputStream(bytes.toByteArray()).withObjectInputStream(getClass().classLoader)
>  { it.readObject() }
> // also: a dehydrated closure with a primitive parameter, whose 
> parameterTypes holds int.class
> bytes = new ByteArrayOutputStream()
> bytes.withObjectOutputStream { it.writeObject({ int x -> x + 1 }.dehydrate()) 
> }
> new 
> ByteArrayInputStream(bytes.toByteArray()).withObjectInputStream(getClass().classLoader)
>  { it.readObject() }
> {code}
> *Actual:* {{java.lang.ClassNotFoundException: int}}. The same applies to the 
> File and Path variants, and to the {{clone()}} generated by 
> {{@AutoClone(style=SERIALIZATION)}} for a class holding a primitive Class or 
> such a closure.
> *Expected:* {{[int, void]}} and a working closure, as with 
> {{withObjectInputStream}} without a class loader.
> Cause: {{IOGroovyMethods.newObjectInputStream(InputStream, ClassLoader)}} 
> overrides {{ObjectInputStream.resolveClass}} with {{Class.forName}}, which 
> cannot load primitive types. The JDK implementation falls back to a table of 
> primitive types when {{Class.forName}} fails; the override has no such 
> fallback.
> Verified on 4.0.33, 5.0.8, 6.0.0 and master.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to