From 030261885269717a9888c43779b7d9db7180f262 Mon Sep 17 00:00:00 2001 From: yue9944882 <291271447@qq.com> Date: Wed, 16 Dec 2020 15:27:21 +0800 Subject: [PATCH] fixes gson-syntax-exception upon deletion even if the deletion succeeds --- .../client/e2e/basic/CoreV1ApiTest.groovy | 41 ++++++++++++++ .../client/gson/V1StatusPreProcessor.java | 48 +++++++++++++++++ .../io/kubernetes/client/openapi/JSON.java | 7 ++- .../gson/V1StatusJsonDeserializerTest.java | 54 +++++++++++++++++++ 4 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 e2e/src/test/groovy/io/kubernetes/client/e2e/basic/CoreV1ApiTest.groovy create mode 100644 kubernetes/src/main/java/io/kubernetes/client/gson/V1StatusPreProcessor.java create mode 100644 kubernetes/src/test/java/io/kubernetes/client/gson/V1StatusJsonDeserializerTest.java diff --git a/e2e/src/test/groovy/io/kubernetes/client/e2e/basic/CoreV1ApiTest.groovy b/e2e/src/test/groovy/io/kubernetes/client/e2e/basic/CoreV1ApiTest.groovy new file mode 100644 index 0000000000..22b5ccdf5b --- /dev/null +++ b/e2e/src/test/groovy/io/kubernetes/client/e2e/basic/CoreV1ApiTest.groovy @@ -0,0 +1,41 @@ +/* +Copyright 2020 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package io.kubernetes.client.e2e.basic + +import io.kubernetes.client.openapi.Configuration +import io.kubernetes.client.openapi.apis.CoreV1Api +import io.kubernetes.client.openapi.models.V1Namespace +import io.kubernetes.client.openapi.models.V1ObjectMeta +import io.kubernetes.client.openapi.models.V1Status +import io.kubernetes.client.util.ClientBuilder +import spock.lang.Specification + +class CoreV1ApiTest extends Specification { + def "Create Namespace then Delete should work"() { + given: + def apiClient = ClientBuilder.defaultClient() + def corev1api = new CoreV1Api(apiClient) + Configuration.setDefaultApiClient(apiClient) + def namespaceFoo = new V1Namespace().metadata(new V1ObjectMeta().name("e2e-basic")) + when: + V1Namespace created = corev1api.createNamespace(namespaceFoo, null, null, null) + then: + created != null + when: + V1Status deleted = corev1api.deleteNamespace("e2e-basic", null, null, null, null, null, null) + then: + deleted != null + } + +} diff --git a/kubernetes/src/main/java/io/kubernetes/client/gson/V1StatusPreProcessor.java b/kubernetes/src/main/java/io/kubernetes/client/gson/V1StatusPreProcessor.java new file mode 100644 index 0000000000..c7fa1d22bb --- /dev/null +++ b/kubernetes/src/main/java/io/kubernetes/client/gson/V1StatusPreProcessor.java @@ -0,0 +1,48 @@ +/* +Copyright 2020 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package io.kubernetes.client.gson; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import io.gsonfire.PreProcessor; +import io.kubernetes.client.openapi.models.V1Status; + +/** Suppresses runtime exceptions due to https://github.com/kubernetes-client/java/issues/86. */ +public class V1StatusPreProcessor implements PreProcessor { + + @Override + public void preDeserialize(Class aClass, JsonElement jsonElement, Gson gson) { + if (isLegitKubernetesStatus(jsonElement)) { + return; + } + + JsonObject obj = jsonElement.getAsJsonObject(); + JsonElement statusField = obj.get("status"); + if (statusField != null && statusField.isJsonObject()) { + obj.addProperty("status", (String) null); + } + } + + private static boolean isLegitKubernetesStatus(JsonElement jsonElement) { + String apiVersion = + jsonElement.getAsJsonObject().get("apiVersion") != null + ? jsonElement.getAsJsonObject().get("apiVersion").getAsString() + : null; + String kind = + jsonElement.getAsJsonObject().get("kind") != null + ? jsonElement.getAsJsonObject().get("kind").getAsString() + : null; + return "v1".equals(apiVersion) && "Status".equals(kind); + } +} diff --git a/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java b/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java index 6fd80b1e35..0bb5bb5a33 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java +++ b/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java @@ -20,6 +20,8 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import io.gsonfire.GsonFireBuilder; +import io.kubernetes.client.gson.V1StatusPreProcessor; +import io.kubernetes.client.openapi.models.V1Status; import java.io.IOException; import java.io.StringReader; import java.lang.reflect.Type; @@ -46,7 +48,10 @@ public class JSON { public static GsonBuilder createGson() { GsonFireBuilder fireBuilder = new GsonFireBuilder(); - GsonBuilder builder = fireBuilder.createGsonBuilder(); + GsonBuilder builder = + fireBuilder + .registerPreProcessor(V1Status.class, new V1StatusPreProcessor()) + .createGsonBuilder(); return builder; } diff --git a/kubernetes/src/test/java/io/kubernetes/client/gson/V1StatusJsonDeserializerTest.java b/kubernetes/src/test/java/io/kubernetes/client/gson/V1StatusJsonDeserializerTest.java new file mode 100644 index 0000000000..b4f925d788 --- /dev/null +++ b/kubernetes/src/test/java/io/kubernetes/client/gson/V1StatusJsonDeserializerTest.java @@ -0,0 +1,54 @@ +/* +Copyright 2020 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package io.kubernetes.client.gson; + +import static org.junit.Assert.assertNotNull; + +import com.google.gson.Gson; +import io.gsonfire.GsonFireBuilder; +import io.kubernetes.client.openapi.models.V1Status; +import org.junit.Test; + +public class V1StatusJsonDeserializerTest { + + private final Gson gson = + new GsonFireBuilder() + .registerPreProcessor(V1Status.class, new V1StatusPreProcessor()) + .createGsonBuilder() + .create(); + + private static final String JSON_DEPLOYMENT = + "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"spec\":null,\"status\":{}}"; + private static final String JSON_STATUS = + "{\"apiVersion\":\"v1\",\"kind\":\"Status\",\"status\":\"True\"}"; + private static final String JSON_STATUS_NULL = + "{\"apiVersion\":\"v1\",\"kind\":\"Status\",\"status\":null}"; + + @Test + public void testDeserializeNormalStatusIntoStatus() { + V1Status status = gson.fromJson(JSON_STATUS, V1Status.class); + assertNotNull(status); + } + + @Test + public void testDeserializeNullStatusIntoStatus() { + V1Status status = gson.fromJson(JSON_STATUS_NULL, V1Status.class); + assertNotNull(status); + } + + @Test + public void testDeserializeDeploymentIntoStatus() { + V1Status status = gson.fromJson(JSON_DEPLOYMENT, V1Status.class); + assertNotNull(status); + } +}