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

Json Type no longer works for Kotlin sealed classes in Micronaut 4.0.0 #580

Open
tmalinakis-vng opened this issue Jul 21, 2023 · 4 comments

Comments

@tmalinakis-vng
Copy link

Expected Behavior

Fields annotated with DataType.JSON should continue to be serializable and deserializable. The following should work as it used to work in Micronaut 3.x:

@MappedEntity(value = "foo")
internal data class FooEntity(
    @field:Id @GeneratedValue
    val sequence: Long?,

    @field:TypeDef(type = DataType.JSON)
    val status: FooStatus
)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
sealed class FooStatus {

    @JsonTypeName("requested")
    object Requested : FooStatus()

    sealed class Processing : FooStatus() {

        @JsonTypeName("foo_status.updated")
        object Updated : Processing()

        @JsonTypeName("foo_status.no_changes")
        object NoChanges : Processing()
    }

    @JsonTypeName("errored")
    data class Errored(val reason: String?) : FooStatus()
}

Actual Behaviour

Getting a SerDe exception:

Caused by: io.micronaut.data.exceptions.DataAccessException: Failed setting JSON field parameter at index 3
	at io.micronaut.data.runtime.operations.internal.sql.AbstractSqlRepositoryOperations.getJsonValue(AbstractSqlRepositoryOperations.java:275)
Caused by: io.micronaut.data.exceptions.DataAccessException: Failed setting JSON field parameter at index 3

	at io.micronaut.data.runtime.operations.internal.sql.AbstractSqlRepositoryOperations.setStatementParameter(AbstractSqlRepositoryOperations.java:231)
	at io.micronaut.data.jdbc.operations.DefaultJdbcRepositoryOperations.access$1700(DefaultJdbcRepositoryOperations.java:136)
	at io.micronaut.data.jdbc.operations.DefaultJdbcRepositoryOperations$JdbcParameterBinder.bindOne(DefaultJdbcRepositoryOperations.java:1064)
	at io.micronaut.data.runtime.operations.internal.query.DefaultBindableParametersStoredQuery.bindParameter(DefaultBindableParametersStoredQuery.java:178)
	at io.micronaut.data.runtime.operations.internal.query.DefaultBindableParametersStoredQuery.bindParameters(DefaultBindableParametersStoredQuery.java:85)
	at io.micronaut.data.jdbc.operations.DefaultJdbcRepositoryOperations$JdbcEntityOperations.execute(DefaultJdbcRepositoryOperations.java:1135)
	at io.micronaut.data.runtime.operations.internal.BaseOperations.persist(BaseOperations.java:84)
	... 72 common frames omitted
Caused by: io.micronaut.serde.exceptions.SerdeException: No serializable introspection present for type Requested. Consider adding Serdeable. Serializable annotate to type Requested. Alternatively if you are not in control of the project's source code, you can use @SerdeImport(Requested.class) to enable serialization of this type.
	at io.micronaut.serde.support.serializers.ObjectSerializer$4.tryToFindSerializer(ObjectSerializer.java:218)
Caused by: io.micronaut.serde.exceptions.SerdeException: No serializable introspection present for type Requested. Consider adding Serdeable. Serializable annotate to type Requested. Alternatively if you are not in control of the project's source code, you can use @SerdeImport(Requested.class) to enable serialization of this type.

	at io.micronaut.serde.support.serializers.ObjectSerializer$RuntimeTypeSerializer.lambda$getSerializer$0(ObjectSerializer.java:280)
	at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
	at io.micronaut.serde.support.serializers.ObjectSerializer$RuntimeTypeSerializer.getSerializer(ObjectSerializer.java:278)
	at io.micronaut.serde.support.serializers.ObjectSerializer$RuntimeTypeSerializer.serialize(ObjectSerializer.java:245)
	at io.micronaut.serde.jackson.JacksonJsonMapper.writeValue(JacksonJsonMapper.java:114)
	at io.micronaut.serde.jackson.JacksonJsonMapper.writeValue0(JacksonJsonMapper.java:106)
	at io.micronaut.serde.jackson.JacksonJsonMapper.writeValue0(JacksonJsonMapper.java:100)
	at io.micronaut.serde.jackson.JacksonJsonMapper.writeValueAsBytes(JacksonJsonMapper.java:201)
	at io.micronaut.data.runtime.mapper.sql.SqlJsonValueMapper.mapValue(SqlJsonValueMapper.java:52)
	at io.micronaut.data.runtime.operations.internal.sql.AbstractSqlRepositoryOperations.getJsonValue(AbstractSqlRepositoryOperations.java:273)
	... 79 common frames omitted
Caused by: io.micronaut.core.beans.exceptions.IntrospectionException: No serializable introspection present for type Requested. Consider adding Serdeable. Serializable annotate to type Requested. Alternatively if you are not in control of the project's source code, you can use @SerdeImport(Requested.class) to enable serialization of this type.
Caused by: io.micronaut.core.beans.exceptions.IntrospectionException: No serializable introspection present for type Requested. Consider adding Serdeable. Serializable annotate to type Requested. Alternatively if you are not in control of the project's source code, you can use @SerdeImport(Requested.class) to enable serialization of this type.

	at io.micronaut.serde.support.DefaultSerdeIntrospections.getSerializableIntrospection(DefaultSerdeIntrospections.java:102)
	at io.micronaut.serde.support.serializers.SerBean.<init>(SerBean.java:107)
	at io.micronaut.serde.support.serializers.ObjectSerializer.create(ObjectSerializer.java:202)
	at io.micronaut.serde.support.serializers.ObjectSerializer.lambda$getSerBean$0(ObjectSerializer.java:193)
	at io.micronaut.core.util.SupplierUtil$2.get(SupplierUtil.java:79)
	at io.micronaut.serde.support.serializers.ObjectSerializer.getSerBean(ObjectSerializer.java:194)
	at io.micronaut.serde.support.serializers.ObjectSerializer.createSpecificInternal(ObjectSerializer.java:93)
	at io.micronaut.serde.support.serializers.ObjectSerializer.createSpecific(ObjectSerializer.java:86)
	at io.micronaut.serde.jackson.JacksonJsonMapper.writeValue(JacksonJsonMapper.java:112)
	... 84 common frames omitted

I've followed the instructions on adding the dependencies for updating to Micronaut 4.x. I've also tried annotating the Kotlin classes with @Serdeable but then I'm hitting a "No Default constructor exists" exception which seems to be a limitation of Micronaut Serialization.

Is there a way to opt out from Micronaut Serialization back to plain Jackson?

Thanks

Steps To Reproduce

No response

Environment Information

  • MacOS
  • JDK 17

Example Application

No response

Version

4.0.0

@tmalinakis-vng
Copy link
Author

Going through the code, providing the following bean seems to restore the previous behaviour:

@Singleton
class JacksonSqlJsonValueMapper(
    private val jacksonDatabindMapper: JacksonDatabindMapper
) : SqlJsonValueMapper {

    override fun getJsonMapper(): JsonMapper {
        return jacksonDatabindMapper
    }
}

Still not sure if it's wise to rely on classes marked as Internal though.

@radovanradic radovanradic self-assigned this Jul 21, 2023
@radovanradic
Copy link
Contributor

radovanradic commented Jul 24, 2023

There is another workaround, if that's ok with your project. Excluding micronaut serde jackson
If using gradle

configurations.all {
    exclude group: "io.micronaut.serde", module: "micronaut-serde-jackson"
}

and then make sure jackson databind is imported

runtime("io.micronaut:micronaut-jackson-databind")
// or implementation

then SqlJsonValueMapper and SqlJsonColumnReader will have JacksonDatabindMapper as default JsonMapper and adding this singleton is not needed.

@dstepanov
Copy link
Contributor

@graemerocher Do we support this case in Micronaut Serialization?

@radovanradic radovanradic removed their assignment Sep 25, 2023
@radovanradic radovanradic transferred this issue from micronaut-projects/micronaut-data Sep 25, 2023
@radovanradic
Copy link
Contributor

Documentation for configuring serde dependency in Micronaut 4: https://micronaut.io/2023/02/27/micronaut-framework-4-0-and-micronaut-jackson-databind-transitive-dependency/

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

No branches or pull requests

3 participants