Skip to content

UnmatchedFieldTypeModule prevents certain jackson features from working #6342

@fxshlein

Description

@fxshlein

Describe the bug

I'm using the jackson-module-kotlin, registered in KubernetesSerialization. When deserializing a kotlin object, the SettableBeanPropertyDelegate that is added here does not properly delegate some functions from jackson (in this case, getCreatorIndex()). These are implemented with a default value by jackson, but they can be overridden by special properties, like kotlin constructor properties.

Fabric8 Kubernetes Client version

6.13.3

Steps to reproduce

  1. Have a CRD represented by a kotlin data class
  2. Try to serialize/deserialize that resource using the KubernetesSerialization

Expected behavior

I think this is a simple oversight, and the delegate is probably supposed implement and delegate all the functions.

Runtime

other (please specify in additional context)

Kubernetes API Server version

other (please specify in additional context)

Environment

other (please specify in additional context)

Fabric8 Kubernetes Client Logs

io.fabric8.kubernetes.client.KubernetesClientException: An error has occurred.
	at io.fabric8.kubernetes.client.KubernetesClientException.launderThrowable(KubernetesClientException.java:129)
	at io.fabric8.kubernetes.client.KubernetesClientException.launderThrowable(KubernetesClientException.java:122)
	at io.fabric8.kubernetes.client.utils.KubernetesSerialization.unmarshal(KubernetesSerialization.java:261)
	at io.fabric8.kubernetes.client.dsl.internal.OperationSupport.lambda$handleResponse$0(OperationSupport.java:551)
	at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:646)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
	at io.fabric8.kubernetes.client.http.StandardHttpClient.lambda$completeOrCancel$10(StandardHttpClient.java:142)
	at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
	at io.fabric8.kubernetes.client.http.ByteArrayBodyHandler.onBodyDone(ByteArrayBodyHandler.java:51)
	at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
	at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
	at io.fabric8.kubernetes.client.okhttp.OkHttpClientImpl$OkHttpAsyncBody.doConsume(OkHttpClientImpl.java:136)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Internal error: no creator index for property 'enabled' (of type io.fabric8.kubernetes.model.jackson.SettableBeanPropertyDelegate) (through reference chain: ...)
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:402)
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:361)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1964)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:580)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:447)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1497)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:348)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185)
	at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
	at io.fabric8.kubernetes.model.jackson.SettableBeanPropertyDelegate.deserializeAndSet(SettableBeanPropertyDelegate.java:134)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:310)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
	at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342)
	at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:2125)
	at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1501)
	at io.fabric8.kubernetes.client.utils.KubernetesSerialization.unmarshal(KubernetesSerialization.java:257)
	... 18 more
Caused by: java.lang.IllegalStateException: Internal error: no creator index for property 'enabled' (of type io.fabric8.kubernetes.model.jackson.SettableBeanPropertyDelegate)
	at com.fasterxml.jackson.databind.deser.SettableBeanProperty.getCreatorIndex(SettableBeanProperty.java:450)
	at com.fasterxml.jackson.databind.deser.impl.PropertyValueBuffer.assignParameter(PropertyValueBuffer.java:327)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:449)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1497)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:348)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185)
	at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:543)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:578)
	... 30 more

Additional context

This is happening anywhere and is not really platform-dependent.

Jackson provides SettableBeanProperty.Delegating for reliably delegating all properties, and using it as a supertype I fixed the issue (although registering this was a bit hacky). The delegate I'm using instead of SettableBeanPropertyDelegate looks like this:

open class JacksonSettableBeanPropertyDelegate(
    delegate: SettableBeanProperty,
    private val anySetter: SettableAnyProperty?,
    private val useAnySetter: BooleanSupplier,
) : SettableBeanProperty.Delegating(delegate) {
    override fun withDelegate(d: SettableBeanProperty): SettableBeanProperty {
        return JacksonSettableBeanPropertyDelegate(d, anySetter, useAnySetter)
    }

    @Throws(IOException::class)
    override fun deserializeAndSet(p: JsonParser, ctxt: DeserializationContext?, instance: Any?) {
        try {
            delegate.deserializeAndSet(p, ctxt, instance)
        } catch (ex: MismatchedInputException) {
            if (shouldUseAnySetter()) {
                anySetter!![instance, delegate.name] = p.text
            } else {
                throw ex
            }
        }
    }

    @Throws(IOException::class)
    override fun deserializeSetAndReturn(p: JsonParser?, ctxt: DeserializationContext?, instance: Any?): Any? {
        try {
            return delegate.deserializeSetAndReturn(p, ctxt, instance)
        } catch (ex: MismatchedInputException) {
            deserializeAndSet(p!!, ctxt, instance)
        }
        return null
    }

    private fun shouldUseAnySetter(): Boolean {
        if (anySetter == null) {
            return false
        }
        return useAnySetter.asBoolean
    }
}

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions