I am using Fabric8 to perform CRUD operations on various K8S custom resources. When reading a resource and attempting to retrieve its spec
, I am experiencing a ClassCastException
between RawExtension
and my POJO which defines the resource spec MyCRDSpec
java.lang.ClassCastException: class io.fabric8.kubernetes.api.model.runtime.RawExtension cannot be cast to class my.package.MyCRDSpec
The custom resource class
@Group("my.group")
@Version("v1alpha1")
public class MyCRD extends CustomResource<MyCRDSpec, MyCRDStatus> implements
Namespaced {
}
Spec POJO
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MyCRDSpec implements KubernetesResource {
private String id;
private String name;
...
}
Status POJO
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyCRDStatus implements KubernetesResource {
private String msg;
}
And this is how I'm reading the resource and attempting to retrieve the spec
try (final KubernetesClient client = new KubernetesClientBuilder().build()) {
final MixedOperation<MyCRD, KubernetesResourceList<MyCRD>, Resource<MyCRD>> crdClient =
client.resources(MyCRD.class);
final MyCRD crd= crdClient.inNamespace("ns").withName("my-existing-custom-resource-name").get();
return crd.getSpec().getName();
}
The reason for retrieving the spec is I want to be able to map to a domain object using the properties contained in the custom resource. However, I encounter this ClassCastException
each time. Logging the full result of getSpec()
shows that it appears to be bound to RawExtension
rather than MyCRDSpec
as expected
spec=RawExtension(super=AnyType(value={...}))
I've been following this and this as guides so far. I have also tried changing my client configuration but nothing has yielded any results.
I haven't included the CRD yaml definition or how I'm creating the custom resources because that functionality is working as expected, but it's very similar to my code above and in those guides. I am able to view both the CRD and my created resources in cluster without issue.
I am using spring-cloud-kubernetes-fabric8-all
version 3.1.0
and JDK 21.
EDIT
The ClassCastException
also contains an error about the class loader
io.fabric8.kubernetes.api.model.runtime.RawExtension and my.package.MyCRDSpec are in unnamed module of loader org.springframework.boot.loader.launch.LaunchedClassLoader
Having checked some of the answers in this question, I tried replacing Lombok annotations with manual getters/setters but this made no difference.
EDIT 2
Progress. Annotating MyCRDSpec
with @JsonDeserialize()
solves the problem. The question is, why do I need to do this? Is there something in the Fabric8 client setting a custom deserializer unexpectedly or incorrectly?
You don't need extend MyCRDSpec
and MyCRDStatus
with KubernetesResource
. Extending them with this class seems to register it with KubernetesDeserializer that tries to map it as an actual Kubernetes resource (like Deployment, Pod etc). The issue was getting fixed by adding @JsonDeserialize(using = com.fasterxml.jackson.databind.JsonDeserializer.None.class)
because this configured Jackson to not use KubernetesDeserializer.