[
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)