Serialization Error When Loading Multi-Document YAML in fabric8 Kubernetes Client
fengyinqiao opened this issue · comments
Describe the bug
Encountering a deserialization error when attempting to use the Serialization.unmarshal method to handle a YAML string containing multiple Kubernetes resource definitions separated by ---, and trying to deserialize it as List.class.
Error Details:
java.lang.IllegalArgumentException: Cannot deserialize value of type `java.util.ArrayList<java.lang.Object>` from Object value (token `JsonToken.START_OBJECT`)
at [Source: UNKNOWN; line: -1, column: -1]
Fabric8 Kubernetes Client version
6.9.2
Steps to reproduce
- Prepare a YAML string containing multiple resource definitions separated by ---.
- Attempt to load and deserialize the YAML string using the following code:
InputStream is = new ByteArrayInputStream(ymlContent.getBytes(StandardCharsets.UTF_8));
List<HasMetadata> resources = Serialization.unmarshal(is, List.class);
Actual Behavior:
Throws a type mismatch exception when the YAML definitions contain only a single resource object instead of an array.
Expected behavior
The method should correctly parse the multi-document YAML string and deserialize each definition into a corresponding list of Kubernetes resource objects.
Runtime
Kubernetes (vanilla)
Kubernetes API Server version
1.23
Environment
macOS
Fabric8 Kubernetes Client Logs
No response
Additional context
Consider enhancing the Serialization.unmarshal method to more intelligently handle both single objects and arrays of objects, or clarify in the documentation how such cases should be handled.
@fengyinqiao : Hello, we have a test for verifying this multi-line document YAML deserialization. Could you please check if your YAML is similar to this?
kubernetes-client/kubernetes-client/src/test/resources/test-list.yml
Lines 17 to 20 in e97a19e
This yaml gets used in KubernetesClientImplTest
@fengyinqiao : Hello, we have a test for verifying this multi-line document YAML deserialization. Could you please check if your YAML is similar to this?
kubernetes-client/kubernetes-client/src/test/resources/test-list.yml
Lines 17 to 20 in e97a19e
This yaml gets used in KubernetesClientImplTest
@rohanKanojia Really thank's for your reply! my YAML is as below:
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
---
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
@fengyinqiao : When I copy paste your YAML and add this test, it seems to pass.
@Test
void multiline() {
// Given
// When
try (KubernetesClient kubernetesClient = new KubernetesClientBuilder().build()) {
List<HasMetadata> result = kubernetesClient.load(KubernetesClientImplTest.class.getResourceAsStream("/multi-line.yml")).items();
// Then
assertThat(result)
.hasSize(2)
.hasAtLeastOneElementOfType(GenericKubernetesResource.class)
.hasAtLeastOneElementOfType(GenericKubernetesResource.class);
}
}
@fengyinqiao : When I copy paste your YAML and add this test, it seems to pass.
@Test void multiline() { // Given // When try (KubernetesClient kubernetesClient = new KubernetesClientBuilder().build()) { List<HasMetadata> result = kubernetesClient.load(KubernetesClientImplTest.class.getResourceAsStream("/multi-line.yml")).items(); // Then assertThat(result) .hasSize(2) .hasAtLeastOneElementOfType(GenericKubernetesResource.class) .hasAtLeastOneElementOfType(GenericKubernetesResource.class); } }
@rohanKanojia Thanks for your code. It does work. And I find another way based on my code just now, it also works:
List<HasMetadata> resources = new ArrayList<>();
try (InputStream is = new ByteArrayInputStream(ymlContent.getBytes(StandardCharsets.UTF_8))) {
resources.addAll(Serialization.unmarshal(is));
assertThat(resources)
.hasSize(2)
.hasAtLeastOneElementOfType(GenericKubernetesResource.class)
.hasAtLeastOneElementOfType(GenericKubernetesResource.class);
}
so, why my original code is wrong?
so, why my original code is wrong?
Are you using java.util.List
in your initial method? Does it work if you use io.fabric8.kubernetes.api.model.KubernetesResourceList
?
Does it work if you use
io.fabric8.kubernetes.api.model.KubernetesResourceList
?
@rohanKanojia I get null , use below code:
try (InputStream is = new ByteArrayInputStream(ymlContent.getBytes(StandardCharsets.UTF_8))) {
KubernetesResourceList kubernetesResourceList = Serialization.unmarshal(is);
assertNull(kubernetesResourceList)
}