Skip to content

Commit

Permalink
fix #4998: removing the usage of the yaml mapper
Browse files Browse the repository at this point in the history
  • Loading branch information
shawkins authored and manusa committed Mar 29, 2023
1 parent d93ddc6 commit 3f08f6e
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 33 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
#### Improvements
* Fix #4477 exposing LeaderElector.release to force an elector to give up the lease
* Fix #4992: Optimize Quantity parsing to avoid regex overhead
* Fix #4998: removing the internal usage of the Serialization yaml mapper

#### Dependency Upgrade

#### New Features

#### _**Note**_: Breaking changes
* Fix #4998: Serialization.yamlMapper and Serialization.clearYamlMapper have been deprecated

### 6.5.1 (2023-03-20)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package io.fabric8.kubernetes.client.internal;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.kubernetes.api.model.AuthInfo;
import io.fabric8.kubernetes.api.model.Cluster;
import io.fabric8.kubernetes.api.model.Config;
Expand All @@ -26,6 +25,8 @@
import io.fabric8.kubernetes.client.utils.Serialization;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

Expand All @@ -39,13 +40,11 @@ private KubeConfigUtils() {
}

public static Config parseConfig(File file) throws IOException {
ObjectMapper mapper = Serialization.yamlMapper();
return mapper.readValue(file, Config.class);
return Serialization.unmarshal(new FileInputStream(file), Config.class);
}

public static Config parseConfigFromString(String contents) throws IOException {
ObjectMapper mapper = Serialization.yamlMapper();
return mapper.readValue(contents, Config.class);
public static Config parseConfigFromString(String contents) {
return Serialization.unmarshal(contents, Config.class);
}

/**
Expand Down Expand Up @@ -158,6 +157,8 @@ public static int getNamedUserIndexFromConfig(Config config, String userName) {
* @throws IOException in case of failure while writing to file
*/
public static void persistKubeConfigIntoFile(Config kubeConfig, String kubeConfigPath) throws IOException {
Serialization.yamlMapper().writeValue(new File(kubeConfigPath), kubeConfig);
try (FileWriter writer = new FileWriter(kubeConfigPath)) {
writer.write(Serialization.asYaml(kubeConfig));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,11 @@ public static boolean isJSONValid(String json) {
return true;
}

public static String convertYamlToJson(String yaml) throws IOException {
ObjectMapper yamlReader = Serialization.yamlMapper();
Object obj = yamlReader.readValue(yaml, Object.class);

ObjectMapper jsonWriter = Serialization.jsonMapper();
return jsonWriter.writeValueAsString(obj);
public static String convertYamlToJson(String yaml) {
return Serialization.asJson(Serialization.unmarshal(yaml, Object.class));
}

public static String convertToJson(String jsonOrYaml) throws IOException {
public static String convertToJson(String jsonOrYaml) {
if (isJSONValid(jsonOrYaml)) {
return jsonOrYaml;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,16 @@
import io.fabric8.kubernetes.api.model.runtime.RawExtension;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.model.jackson.UnmatchedFieldTypeModule;
import org.snakeyaml.engine.v2.api.Dump;
import org.snakeyaml.engine.v2.api.DumpSettings;
import org.snakeyaml.engine.v2.api.Load;
import org.snakeyaml.engine.v2.api.LoadSettings;
import org.snakeyaml.engine.v2.common.FlowStyle;
import org.snakeyaml.engine.v2.common.ScalarStyle;
import org.snakeyaml.engine.v2.nodes.NodeTuple;
import org.snakeyaml.engine.v2.nodes.ScalarNode;
import org.snakeyaml.engine.v2.nodes.Tag;
import org.snakeyaml.engine.v2.representer.StandardRepresenter;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
Expand Down Expand Up @@ -84,7 +92,10 @@ public static ObjectMapper jsonMapper() {
* n.b. the use of this module gives precedence to properties present in the additionalProperties Map present
* in most KubernetesResource instances. If a property is both defined in the Map and in the original field, the
* one from the additionalProperties Map will be serialized.
*
* @deprecated use {@link #asYaml(Object)} or one of the unmarshal methods
*/
@Deprecated
public static ObjectMapper yamlMapper() {
if (YAML_MAPPER == null) {
synchronized (Serialization.class) {
Expand All @@ -103,7 +114,10 @@ public static ObjectMapper yamlMapper() {
* This is useful because in a lot of cases the YAML mapper is only need at application startup
* when the client is created, so there is no reason to keep the very heavy (in terms of memory) mapper
* around indefinitely.
*
* @deprecated to be removed in later versions
*/
@Deprecated
public static void clearYamlMapper() {
YAML_MAPPER = null;
}
Expand Down Expand Up @@ -141,11 +155,38 @@ public static <T> String asJson(T object) {
* @return a String containing a JSON representation of the provided object.
*/
public static <T> String asYaml(T object) {
try {
return yamlMapper().writeValueAsString(object);
} catch (JsonProcessingException e) {
throw KubernetesClientException.launderThrowable(e);
}
DumpSettings settings = DumpSettings.builder()
.setExplicitStart(true).setDefaultFlowStyle(FlowStyle.BLOCK).build();
final Dump yaml = new Dump(settings, new StandardRepresenter(settings) {
private boolean quote = true;

@Override
protected NodeTuple representMappingEntry(java.util.Map.Entry<?, ?> entry) {
Object key = entry.getKey();
if (key instanceof String) {
// to match the previous format, don't quote keys
quote = false;
String str = (String) key;
// the abbreviations y/n are not part of the snakeyaml core schema
if (str.length() == 1) {
char start = str.charAt(0);
quote = (start == 'y' || start == 'Y' || start == 'n' || start == 'N');
}
}
org.snakeyaml.engine.v2.nodes.Node nodeKey = representData(key);
quote = true;
return new NodeTuple(nodeKey, representData(entry.getValue()));
}

@Override
protected org.snakeyaml.engine.v2.nodes.Node representScalar(Tag tag, String value, ScalarStyle style) {
if (style == ScalarStyle.PLAIN) {
style = quote && tag == Tag.STR ? ScalarStyle.DOUBLE_QUOTED : this.defaultScalarStyle;
}
return new ScalarNode(tag, value, style);
}
});
return yaml.dumpToString(JSON_MAPPER.convertValue(object, Object.class));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,20 @@ void unmarshal_configMapWithBoolAndDateData_shouldBeDeserializedAsString() {
.containsEntry("date", "2022-07-22");
}

@Test
void testArrayAsYaml() {
// Given
String[] value = new String[] { "x", "y" };

// When
String yaml = Serialization.asYaml(value);

// Then
assertThat(yaml).isEqualTo("---\n"
+ "- \"x\"\n"
+ "- \"y\"\n");
}

@Test
void testAnyTypeSerialization() {
// Given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,16 @@
*/
package io.fabric8.kubernetes.client.dsl.internal;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.utils.ResourceCompare;
import io.fabric8.kubernetes.client.utils.Serialization;
import io.fabric8.zjsonpatch.JsonDiff;

import java.util.Optional;
import java.util.function.Function;

public class PatchUtils {

Expand All @@ -48,12 +47,8 @@ private static class SingletonHolder {
}

public static String withoutRuntimeState(Object object, Format format, boolean omitStatus) {
ObjectMapper mapper = format == Format.JSON ? Serialization.jsonMapper() : Serialization.yamlMapper();
try {
return mapper.writeValueAsString(withoutRuntimeState(object, omitStatus));
} catch (JsonProcessingException e) {
throw KubernetesClientException.launderThrowable(e);
}
Function<Object, String> mapper = format == Format.JSON ? Serialization::asJson : Serialization::asYaml;
return mapper.apply(withoutRuntimeState(object, omitStatus));
}

/**
Expand All @@ -75,12 +70,8 @@ static JsonNode withoutRuntimeState(Object object, boolean omitStatus) {
}

public static String jsonDiff(Object current, Object updated, boolean omitStatus) {
try {
return Serialization.jsonMapper().writeValueAsString(
JsonDiff.asJson(withoutRuntimeState(current, omitStatus), withoutRuntimeState(updated, omitStatus)));
} catch (JsonProcessingException e) {
throw KubernetesClientException.launderThrowable(e);
}
return Serialization
.asJson(JsonDiff.asJson(withoutRuntimeState(current, omitStatus), withoutRuntimeState(updated, omitStatus)));
}

}

0 comments on commit 3f08f6e

Please sign in to comment.