-
Notifications
You must be signed in to change notification settings - Fork 826
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ArrayIndexOutOfBoundsException when serializing generic lambda written in Kotlin #864
Comments
@holgerbrandl: Thanks for the report and the reproducer. Any chance you can reproduce this issue in plain Java? This would make it much easier for me to look into this. As a workaround you can disable generics optimization:
This will typically improve serialization speed at the cost of some extra payload bytes. |
Thanks. I could try, but since I'm consuming this rather complex library https://github.com/InsertKoinIO/koin, I may struggle here. Both because I do not know the internals of koin well enough, and also because I'm not sure if all kotlin constructs can be easily translated to java (although they all compile into jvm bytecode). I'll will try to use the workaround as well, and will report my results in here. This may take some time, because I need to work around all the missing zero-arg constructors in |
Quick update: I managed to de/serialize the I don't know about the implications of Note: I've also started kyrotizing |
The only negative implication is that Kryo doesn't try to use generics information to reduce the serialized payload size. If you use Kryo primarily for speed, then this shouldn't be a problem. In my main project, generics optimization is disabled as well.
Can't you use Objenesis to deal with zero-arg constructors? (https://github.com/EsotericSoftware/kryo#instantiatorstrategy)
|
Thanks. Using this compound-strategy I could successfully serialize the mentioned |
A simpler way to reproduce this: class LambdaTest {
private class Example(private val p: (Long) -> String) {
constructor() : this({ it.toString() })
}
@Test
fun testLambda() {
val kryo = Kryo().apply {
isRegistrationRequired = false
}
val example = Example()
val bytes = Output(1024).use { output ->
kryo.writeClassAndObject(output, example)
output.toBytes()
}
val deserialized = Input(bytes).use { input ->
kryo.readClassAndObject(input)
}
println(deserialized)
}
} What seems to be happening is that the |
@chrisr3: Thanks a lot for the reproducer! Do you know how we could add Kotlin support to our test? I'd really like to have a unit test when I fix this issue. |
Well, that unit test only uses Kryo, Kotlin and JUnit 5, so it shouldn't be too difficult. You'd need to add the Kotlin standard library to your tests: <dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
</dependencies> and presumably include the Kotlin Maven plugin to compile it too. I think JetBrains provides more details. Something like this, perhaps? |
Here's a "sledge-hammer" fix 😉 diff --git a/src/com/esotericsoftware/kryo/util/DefaultGenerics.java b/src/com/esotericsoftware/kryo/util/DefaultGenerics.java
index eeb2273..953215e 100644
--- a/src/com/esotericsoftware/kryo/util/DefaultGenerics.java
+++ b/src/com/esotericsoftware/kryo/util/DefaultGenerics.java
@@ -94,7 +94,9 @@ public final class DefaultGenerics implements Generics {
@Override
public int pushTypeVariables (GenericsHierarchy hierarchy, GenericType[] args) {
// Do not store type variables if hierarchy is empty or we do not have arguments for all root parameters.
- if (hierarchy.total == 0 || hierarchy.rootTotal > args.length) return 0;
+ if (hierarchy.total == 0 || hierarchy.rootTotal > args.length || args.length > hierarchy.counts.length) {
+ return 0;
+ }
int startSize = this.argumentsSize;
|
Your sledge-hammer fix looks good to me. It's not worse than the other two "fixes" I applied to various generics corner cases. ;) I will merge it after my PR that adds support for Kotlin tests. |
You might want to replace println(deserialized) with some actual assertions first though 😉. I made a similar change to my own PR. |
Merged. Thanks again @chrisr3! |
Describe the bug
When serializing an object in Kotlin it fails with an ArrayIndexOutOfBoundsException
To Reproduce
I've created a minimal example in https://github.com/holgerbrandl/kryo-koin. The respective class to reproduce the stacktrace from above is
KryoBeanDefinitionKt#main
Environment:
Analysis
It seems to be a mismatch between the array sizes of
args
andhierarchy
inkryo/src/com/esotericsoftware/kryo/util/DefaultGenerics.java
Line 116 in 76c5e5d
I've tried, but did not manage to narrow down the problem any further.
The text was updated successfully, but these errors were encountered: