Skip to content
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

Hcon: error while trying to decode MAP + sealed class #1581

Closed
SchweinchenFuntik opened this issue Jul 2, 2021 · 5 comments
Closed

Hcon: error while trying to decode MAP + sealed class #1581

SchweinchenFuntik opened this issue Jul 2, 2021 · 5 comments

Comments

@SchweinchenFuntik
Copy link

SchweinchenFuntik commented Jul 2, 2021

additions to #1046

package khocon

import com.typesafe.config.ConfigFactory
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.hocon.Hocon
import kotlinx.serialization.hocon.decodeFromConfig

@Serializable
sealed class Node

@Serializable
data class Root(val name: String): Node()

@Serializable
data class Simple(val a: String)


private val configSimpleClass = """
    key1 {
       a = "simple"
    }
    
    key2 {
       a = "simple"
    }
    """

private val configSealedClass = """
    key1 {
       type = "khocon.Root"
       name = "seale"
    }
    
    key2 {
       type = "khocon.Root"
       name = "sealed"
    }
    """

private val configSealedClassSimple = """
    {
   type = "khocon.Root"
   name = "sealed"
   }
    """

@OptIn(ExperimentalSerializationApi::class)
fun main() {
    val simpleClassConfig = ConfigFactory.parseString(configSimpleClass)
    val sealedClassConfigSimple = ConfigFactory.parseString(configSealedClassSimple)
    val sealedClassConfig = ConfigFactory.parseString(configSealedClass)
    val hocon = Hocon {
      // useArrayPolymorphism = true // error val sealedSimple = hocon.decodeFromConfig<Node>(sealedClassConfigSimple)
    }
    val simple = hocon.decodeFromConfig<Map<String, Simple>>(simpleClassConfig) // Work
    println(simple)
    val sealedSimple = hocon.decodeFromConfig<Node>(sealedClassConfigSimple)
    println(sealedSimple)
    val sealed = hocon.decodeFromConfig<Map<String, Node>>(sealedClassConfig)
    println(sealed)
}

output

Exception in thread "main" java.lang.ClassCastException: class com.typesafe.config.impl.SimpleConfigObject cannot be cast to class com.typesafe.config.ConfigList (com.typesafe.config.impl.SimpleConfigObject and com.typesafe.config.ConfigList are in unnamed module of loader 'app')
	at kotlinx.serialization.hocon.Hocon$MapConfigReader.beginStructure(Hocon.kt:200)
	at kotlinx.serialization.internal.AbstractPolymorphicSerializer.deserialize(AbstractPolymorphicSerializer.kt:130)
	at kotlinx.serialization.encoding.Decoder$DefaultImpls.decodeSerializableValue(Decoding.kt:260)
	at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableValue(Tagged.kt:177)
	at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableValue(Tagged.kt:206)
	at kotlinx.serialization.internal.TaggedDecoder$decodeSerializableElement$1.invoke(Tagged.kt:279)
	at kotlinx.serialization.internal.TaggedDecoder.tagBlock(Tagged.kt:296)
	at kotlinx.serialization.internal.TaggedDecoder.decodeSerializableElement(Tagged.kt:279)
	at kotlinx.serialization.encoding.CompositeDecoder$DefaultImpls.decodeSerializableElement$default(Decoding.kt:535)
	at kotlinx.serialization.internal.MapLikeSerializer.readElement(CollectionSerializers.kt:111)
	at kotlinx.serialization.internal.MapLikeSerializer.readElement(CollectionSerializers.kt:84)
	at kotlinx.serialization.internal.AbstractCollectionSerializer.readElement$default(CollectionSerializers.kt:51)
	at kotlinx.serialization.internal.AbstractCollectionSerializer.merge(CollectionSerializers.kt:36)
	at kotlinx.serialization.internal.AbstractCollectionSerializer.deserialize(CollectionSerializers.kt:43)
	at kotlinx.serialization.hocon.Hocon$ConfigReader.decodeSerializableValue(Hocon.kt:126)
	at kotlinx.serialization.hocon.Hocon.decodeFromConfig(Hocon.kt:36)
	at khocon.MainKt.main(main.kt:69)
	at khocon.MainKt.main(main.kt)

Process finished with exit code 1

output: useArrayPolymorphism = true

{key2=Simple(a=simple), key1=Simple(a=simple)}
Exception in thread "main" java.util.NoSuchElementException: List is empty.
	at kotlin.collections.CollectionsKt___CollectionsKt.last(_Collections.kt:416)
	at kotlinx.serialization.internal.TaggedDecoder.getCurrentTag(Tagged.kt:306)
	at kotlinx.serialization.hocon.Hocon$ConfigReader.beginStructure(Hocon.kt:154)
	at kotlinx.serialization.internal.AbstractPolymorphicSerializer.deserialize(AbstractPolymorphicSerializer.kt:130)
	at kotlinx.serialization.hocon.Hocon$ConfigReader.decodeSerializableValue(Hocon.kt:126)
	at kotlinx.serialization.hocon.Hocon.decodeFromConfig(Hocon.kt:36)
	at khocon.MainKt.main(main.kt:66)
	at khocon.MainKt.main(main.kt)

Environment

  • Kotlin version: 1.5.10
  • kotlinx-serialization-hocon: 1.2.1
  • Kotlin platforms: JVM
  • Gradle version: 6.8.1
  • IDE version IntellijIDEA 2021.1,
@sandwwraith
Copy link
Member

Seems like that polymorphism is not implemented in HOCON correctly

@LichtHund
Copy link
Contributor

Any updates on this?

@martypitt
Copy link

martypitt commented Jul 4, 2023

I just hit a variation of this issue, which is that a List<T> (where T is a sealed class) doesn't deserialize correctly.

Usng the OP's strutruces:

@Serializable
sealed class Node

@Serializable
data class Root(val name: String): Node()

@Serializable
data class Simple(val a: String)

data class Wrapper(nodes: List<Node>)

val wrapper = Wrapper( ... )
val hocon = Hocon.encodeToConfig(wrapper)
val deserialized = Hocon.decodeFromConfig<Wrapper>(hocon)

Results in this exception:

java.lang.ClassCastException: class com.typesafe.config.impl.SimpleConfigObject cannot be cast to class com.typesafe.config.ConfigList (com.typesafe.config.impl.SimpleConfigObject and com.typesafe.config.ConfigList are in unnamed module of loader 'app')

	at kotlinx.serialization.hocon.Hocon$ListConfigReader.beginStructure(Hocon.kt:219)
	at kotlinx.serialization.internal.AbstractPolymorphicSerializer.deserialize(AbstractPolymorphicSerializer.kt:121)
	at kotlinx.serialization.encoding.Decoder$DefaultImpls.decodeSerializableValue(Decoding.kt:257)
	...

Tested using kotlinx-serialization-hocon-1.5.1.jar

@H4kt
Copy link

H4kt commented Nov 17, 2023

+1
Was trying to decode a List of sealed interface and got the same exception.
Had to fall back to YAML because of this.
Any chance of this being fixed?

@sandwwraith

@LichtHund
Copy link
Contributor

I have updated my PR with a fix for this. Ended up forgetting it was still marked as draft.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants