kubernetes-client: JsonMappingException "No resource type found for: tekton.dev/v1alpha1#PipelineList" in intellij plugins

Hi guys,

When retrieving the list of pipelines I hit an exception when PipelineList is being deserialized in jackson:

client.pipelines().inNamespace(namespace).list().getItems()

results in:

com.fasterxml.jackson.databind.JsonMappingException: No resource type found for:tekton.dev/v1alpha1#PipelineList"

io.fabric8.kubernetes.client.KubernetesClientException.launderThrowable(KubernetesClientException.java:64) 
 io.fabric8.kubernetes.client.KubernetesClientException.launderThrowable(KubernetesClientException.java:53)
 io.fabric8.kubernetes.client.utils.Serialization.unmarshal(Serialization.java:248)
 io.fabric8.kubernetes.client.utils.Serialization.unmarshal(Serialization.java:199)
 io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:474)
 io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:430)
 io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:412)
 io.fabric8.kubernetes.client.dsl.base.BaseOperation.listRequestHelper(BaseOperation.java:151)
 io.fabric8.kubernetes.client.dsl.base.BaseOperation.list(BaseOperation.java:621)
 io.fabric8.kubernetes.client.dsl.base.BaseOperation.list(BaseOperation.java:70)

For the background: I’m writing an IntelliJ plugin to display, operate, etc. kubernetes resources in Intellij at https://github.com/redhat-developer/intellij-kubernetes

I’m trying to separate kubernetes- and tekton-pieces into 2 different plugins: kubernetes base plugin: https://github.com/redhat-developer/intellij-kubernetes/pull/26 tekton extension plugin: https://github.com/redhat-developer/intellij-tekton/pull/36

The kubernetes (base) plugin holds all kubernetes & jackson jars:

  • “io.fabric8:kubernetes-client:4.9.0”,
  • “io.fabric8:kubernetes-model:4.9.0”,
  • “io.fabric8:kubernetes-model-common:4.9.0”,
  • “io.fabric8:openshift-client:4.9.0”
  • “com.fasterxml.jackson.core:jackson-annotations”
  • “com.fasterxml.jackson.core:jackson-core”
  • “com.fasterxml.jackson.corejackson-databind”
  • “com.fasterxml.jackson.module:jackson-module-jaxb-annotations”

The tekton (extension) plugin holds the tekton jars:

  • “io.fabric8:tekton-client:4.9.0”
  • “io.fabric8:tekton-model:4.9.0”

IntelliJ plugins each have their own classloader. The kubernetes (base) plugin doesn’t “see” the classes in the tekton (extension) plugin. The tekton plugin on the other hand depends on the kubernetes plugin and can thus access all it’s classes

In the tekton (extension) plugin I manually register the custom type for the tekton pipeline since I found out that ServiceLoader wouldn’t find the TektonResourceMappingProvider (which would do this automatically in a non-segregated classpath:

KubernetesDeserializer.registerCustomKind("tekton.dev/v1alpha1", "Pipeline", Pipeline.class)

I’m obviously missing bits for this to work in intellij plugins (which have different classloaders for each plugin).

I’d highly appreciate some help here. Thanks in advance!

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 21 (21 by maintainers)

Commits related to this issue

Most upvoted comments

I finally found a solution in intellij and the only changes left for the kubernetes-client that would help me are:

  • lazy-loading of KubernetesResourceProviders
  • lookup for KubernetesResourceProviders via current Classloader & current Thread classloader

I’ll file a PR asap.

@adietish: I don’t 100% get the issue. Feel free to implement the solution and we can discuss the details on the PR.

@iocanel, @rohanKanojia: as far as I can see so far KubernetesDeserializer is not able to decode a KubernetesResource when it has further nested KubernetesResource(s). This ends up in the endless loop I reported above. This does not happen in a setup with a flat classpath bcs all types with nested resources (ex. TaskList, PipelineList, NamespaceList, WatchEvent etc.) are deserialized by BeanDeserializer. There’s therefore no recursive calling of the KubernetesDeserializer happening.

My suggestion where list types would get deserialized by KubernetesDeserializer thus causes these recursive calls. To fix this I’ll add support for this recursion. I’ll either implement the missing pieces or subclass BeanDeserializer.

Makes sense?

Turns out that the classloader segregation in intellij is causing this: The annotation in Task should override the annotation in KubernetesResource. The annotations collector in jackson-databind (AnnotationCollector#addOrOverride) is storing the @JsonDeserialize annotations in Task and its superclass KubernetesResource in a map and using the @JsonDeserialize annotation instance as key. In intellij the annotations are unfortunately loaded via different classloaders (a bug in intellij) and then causes the collector not to grock that the annotation in the subclass should override the annotation in the superclass.

@adietish: I don’t remember why we don’t add the List types. Most probably, because we didn’t need to.

How is this possible? For core types there is a safety net, so we wouldn’t really see the issue there.

So, I propose to also register the List types and try to fix the SO bug.

I traced things down and found out that list types TaskList, PipelineList etc. are created without mapping via classpath lookup in jackson’s TypeFactory. Given that IntelliJ doesn’t have a flat but a classpath that’s segregated across plugins makes this fail when separating the (base) kubernetes model from it’s tekton extension into 2 different plugins. I’ll try to figure out how to solve this in jackson.