Skip to content

Commit 0082ab8

Browse files
committed
fix: allow to deserialize multi-resource json documents (#855)
Signed-off-by: Andre Dietisheim <[email protected]>
1 parent 1493d29 commit 0082ab8

File tree

2 files changed

+64
-30
lines changed

2 files changed

+64
-30
lines changed

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/editor/EditorResourceSerialization.kt

+51-20
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
******************************************************************************/
1111
package com.redhat.devtools.intellij.kubernetes.editor
1212

13+
import com.fasterxml.jackson.databind.ObjectMapper
14+
import com.fasterxml.jackson.databind.node.ArrayNode
1315
import com.intellij.json.JsonFileType
1416
import com.intellij.openapi.fileTypes.FileType
1517
import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
@@ -22,7 +24,6 @@ import org.jetbrains.yaml.YAMLFileType
2224
object EditorResourceSerialization {
2325

2426
const val RESOURCE_SEPARATOR_YAML = "\n---"
25-
private const val RESOURCE_SEPARATOR_JSON = ",\n"
2627

2728
/**
2829
* Returns a list of [HasMetadata] for a given yaml or json string.
@@ -41,32 +42,62 @@ object EditorResourceSerialization {
4142
* @see JsonFileType.INSTANCE
4243
*/
4344
fun deserialize(jsonYaml: String?, fileType: FileType?, currentNamespace: String?): List<HasMetadata> {
44-
return if (jsonYaml == null
45-
|| !isSupported(fileType)) {
46-
emptyList()
47-
} else {
48-
val resources = jsonYaml
49-
.split(RESOURCE_SEPARATOR_YAML)
50-
.filter { jsonYaml -> jsonYaml.isNotBlank() }
51-
if (resources.size > 1
52-
&& YAMLFileType.YML != fileType) {
53-
throw ResourceException(
54-
"${fileType?.name ?: "File type"} is not supported for multi-resource documents. Only ${YAMLFileType.YML.name} is.")
45+
return try {
46+
when {
47+
jsonYaml == null ->
48+
emptyList()
49+
50+
YAMLFileType.YML == fileType ->
51+
yaml2Resources(jsonYaml, currentNamespace)
52+
53+
JsonFileType.INSTANCE == fileType ->
54+
json2Resources(jsonYaml, currentNamespace)
55+
56+
else ->
57+
emptyList()
58+
}
59+
} catch (e: RuntimeException) {
60+
throw ResourceException("Invalid kubernetes yaml/json", e.cause ?: e)
61+
}
62+
}
63+
64+
private fun yaml2Resources(yaml: String, currentNamespace: String?): List<HasMetadata> {
65+
val resources = yaml
66+
.split(RESOURCE_SEPARATOR_YAML)
67+
.filter { yaml ->
68+
yaml.isNotBlank()
69+
}
70+
return resources
71+
.map { yaml ->
72+
setMissingNamespace(currentNamespace, createResource<GenericKubernetesResource>(yaml))
5573
}
56-
try {
57-
resources
58-
.map { jsonYaml ->
59-
setMissingNamespace(currentNamespace, createResource<GenericKubernetesResource>(jsonYaml))
74+
.toList()
75+
}
76+
77+
private fun json2Resources(json: String?, currentNamespace: String?): List<HasMetadata> {
78+
val mapper = ObjectMapper()
79+
val rootNode = mapper.readTree(json)
80+
return when {
81+
rootNode.isArray ->
82+
(rootNode as ArrayNode)
83+
.mapNotNull { node ->
84+
setMissingNamespace(currentNamespace, mapper.treeToValue(node, GenericKubernetesResource::class.java))
6085
}
6186
.toList()
62-
} catch (e: RuntimeException) {
63-
throw ResourceException("Invalid kubernetes yaml/json", e.cause ?: e)
64-
}
87+
rootNode.isObject ->
88+
listOf(
89+
setMissingNamespace(currentNamespace,
90+
mapper.treeToValue(rootNode, GenericKubernetesResource::class.java)
91+
)
92+
)
93+
else ->
94+
emptyList()
6595
}
6696
}
6797

6898
private fun setMissingNamespace(namespace: String?, resource: HasMetadata): HasMetadata {
69-
if (resource.metadata.namespace.isNullOrEmpty()
99+
if (resource.metadata != null
100+
&& resource.metadata.namespace.isNullOrEmpty()
70101
&& namespace != null) {
71102
resource.metadata.namespace = namespace
72103
}

src/test/kotlin/com/redhat/devtools/intellij/kubernetes/editor/EditorResourceSerializationTest.kt

+13-10
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ import com.intellij.json.JsonFileType
1414
import com.intellij.openapi.fileTypes.PlainTextFileType
1515
import com.redhat.devtools.intellij.kubernetes.model.mocks.ClientMocks.resource
1616
import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
17+
import io.fabric8.kubernetes.api.model.HasMetadata
1718
import io.fabric8.kubernetes.api.model.Pod
1819
import io.fabric8.kubernetes.client.utils.Serialization
1920
import org.assertj.core.api.Assertions.assertThat
2021
import org.assertj.core.api.Assertions.assertThatThrownBy
22+
import org.assertj.core.api.Assertions.tuple
2123
import org.jetbrains.yaml.YAMLFileType
2224
import org.junit.Test
2325

@@ -57,19 +59,20 @@ class EditorResourceSerializationTest {
5759
}
5860

5961
@Test
60-
fun `#deserialize throws if given multiple json resources`() {
62+
fun `#deserialize returns list of resources if given multiple JSON resources`() {
6163
// given
6264
val json = """
63-
{"apiVersion": "v1", "kind": "Pod"}
64-
---
65-
{"apiVersion": "v1", "kind": "Service"}
65+
[
66+
{"apiVersion": "v1", "kind": "Pod"},
67+
{"apiVersion": "v1", "kind": "Service"}
68+
]
6669
""".trimIndent()
67-
68-
assertThatThrownBy {
69-
// when
70-
EditorResourceSerialization.deserialize(json, JsonFileType.INSTANCE, null)
71-
// then
72-
}.isInstanceOf(ResourceException::class.java)
70+
val deserialized = EditorResourceSerialization.deserialize(json, JsonFileType.INSTANCE, null)
71+
assertThat(deserialized)
72+
.extracting(HasMetadata::getKind, HasMetadata::getApiVersion)
73+
.containsExactlyInAnyOrder(
74+
tuple("Pod", "v1"),
75+
tuple("Service", "v1"))
7376
}
7477

7578
@Test

0 commit comments

Comments
 (0)