Skip to content

Commit

Permalink
fix #5214: explicitly omitting nulls by default
Browse files Browse the repository at this point in the history
  • Loading branch information
shawkins committed Jun 8, 2023
1 parent aa822b7 commit 953c899
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### 6.8-SNAPSHOT

#### Bugs
* Fix #5214: null values are omitted by default, which means custom resources by in large won't need JsonIncludes annotations. The only time that is required is when null is to be preserved via @JsonInclude(value = Include.ALWAYS) on the relevant field.

#### Improvements

Expand Down
4 changes: 4 additions & 0 deletions doc/CHEATSHEET.md
Original file line number Diff line number Diff line change
Expand Up @@ -1859,6 +1859,10 @@ import io.fabric8.kubernetes.model.annotation.Version;
public class CronTab extends CustomResource<CronTabSpec, CronTabStatus> implements Namespaced {
}
```

**Note:** Null values in your custom resource will be omitted by default by the client or when directly using KubernetesSerialization, or the static Serialization methods. If you have a situation where a null value
must be present in the serialized form, then mark the field with @JsonInclude(value = Include.ALWAYS).

You can find other helper classes related to `CronTab` in our [tests](https://github.com/fabric8io/kubernetes-client/tree/master/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/crd). For now, we can proceed with it's common usage examples:

- Get Instance of client for our `CustomResource`:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package io.fabric8.kubernetes.client.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationConfig;
Expand Down Expand Up @@ -89,6 +91,8 @@ public KubernetesSerialization(ObjectMapper mapper, boolean searchClassloaders)
protected void configureMapper(ObjectMapper mapper) {
mapper.registerModules(new JavaTimeModule(), unmatchedFieldTypeModule);
mapper.disable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE);
// omit null fields, but keep null map values
mapper.setDefaultPropertyInclusion(JsonInclude.Value.construct(Include.NON_NULL, Include.ALWAYS));
HandlerInstantiator instanciator = mapper.getDeserializationConfig().getHandlerInstantiator();
mapper.setConfig(mapper.getDeserializationConfig().with(new HandlerInstantiator() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.fabric8.kubernetes.client.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
Expand Down Expand Up @@ -77,6 +78,27 @@

class SerializationTest {

static class WithNull {
@JsonInclude(value = Include.ALWAYS)
public Integer field;
}

static class WithoutNull {
public Integer field;
}

@Test
void testNullSerialization() throws Exception {
assertEquals("---\nfield: null\n", Serialization.asYaml(new WithNull()));
assertEquals("{\"field\":null}", Serialization.asJson(new WithNull()));
assertEquals("--- {}\n", Serialization.asYaml(new WithoutNull()));
assertEquals("{}", Serialization.asJson(new WithoutNull()));
// map null values should be preserved
Map<String, String> map = new HashMap<>();
map.put("key", null);
assertEquals("{\"key\":null}", Serialization.asJson(map));
}

@Test
void unmarshalCRDWithSchema() throws Exception {
// Given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,16 @@ void testDiff() {
PatchUtils.jsonDiff(rc1, rc2, false, new KubernetesSerialization()));
}

@Test
void testDiffRemove() {
ReplicationController rc1 = new ReplicationControllerBuilder().withNewStatus().withFullyLabeledReplicas(1).endStatus()
.withNewMetadata().withName("x").endMetadata().build();

ReplicationController rc2 = new ReplicationControllerBuilder(rc1).withStatus(null).build();

assertEquals(
"[{\"op\":\"remove\",\"path\":\"/status\"}]",
PatchUtils.jsonDiff(rc1, rc2, false, new KubernetesSerialization()));
}

}

0 comments on commit 953c899

Please sign in to comment.