Configurate
Configurate copied to clipboard
TypeToken interprets Kotlin type variance wrongly
Since Kotlin's type variance works different, there are some issues when using io.leangen.geantyref.TypeToken
:
In Java, this works as expected:
System.out.println(new TypeToken<Set<String>>() {}.getType()); // java.util.Set<java.lang.String>
In Kotlin, this interpreted wrongly:
println(object : TypeToken<Set<String>>() {}.type) // java.util.Set<? extends java.lang.String>
This can then lead to unexpected exceptions, as Configurate won't find serializes for type ? extends String
:
// import org.spongepowered.configurate.kotlin.extensions.get
println(root.node("list").get<Set<String>>())
Exception in thread "main" org.spongepowered.configurate.serialize.SerializationException: [list] of type ? extends java.lang.String: No applicable type serializer for type
at org.spongepowered.configurate.serialize.AbstractListChildSerializer.deserialize(AbstractListChildSerializer.java:50)
at org.spongepowered.configurate.AbstractConfigurationNode.get(AbstractConfigurationNode.java:151)
at org.spongepowered.configurate.ConfigurationNode.get(ConfigurationNode.java:458)
at org.example.ConfigurateTestKt.main(ConfigurateTest.kt:70)
at org.example.ConfigurateTestKt.main(ConfigurateTest.kt)
The reason for this is that Kotlin has declaration-site variance and the immutable kotlin.collections.Set
is covariant (public interface Set<out E> : Collection<E>
), which translates to java.util.Set<? extends java.lang.String>
at runtime.
The easiest way to fix this would be to use Kotlin's built-in typeOf
in Configurate's Kotlin extension functions. As an additional benefit, this also removes the overhead of tons of anonymous classes.
println(typeOf<Set<String>>().javaType) // java.util.Set<java.lang.String>