Skip to content

Commit

Permalink
fix: allow defaults to be full json or yaml
Browse files Browse the repository at this point in the history
closes: #6900

Signed-off-by: Steve Hawkins <[email protected]>
  • Loading branch information
shawkins committed Feb 26, 2025
1 parent 4efef7e commit bd07b6a
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 53 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#### Bugs
* Fix #6892: rolling().restart() doesn't remove preexistent pod template annotations
* Fix #6900: The Default annotation and JsonProperty default value should accept JSON values

#### Improvements

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import io.fabric8.kubernetes.api.model.IntOrString;
import io.fabric8.kubernetes.api.model.Quantity;
import io.fabric8.kubernetes.api.model.runtime.RawExtension;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.utils.Utils;
import io.fabric8.kubernetes.model.annotation.LabelSelector;
import io.fabric8.kubernetes.model.annotation.SpecReplicas;
Expand Down Expand Up @@ -85,7 +86,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static io.fabric8.crdv2.generator.CRDUtils.toTargetType;
import static java.util.Optional.ofNullable;

/**
Expand Down Expand Up @@ -232,7 +232,7 @@ class PropertyMetadata {

private boolean required;
private final String description;
private final Object defaultValue;
private final JsonNode defaultValue;
private Double min;
private Boolean exclusiveMinimum;
private Double max;
Expand Down Expand Up @@ -315,13 +315,22 @@ public PropertyMetadata(JsonSchema value, BeanProperty beanProperty) {
// TODO: should the following be deprecated?
required = beanProperty.getAnnotation(Required.class) != null;

if (beanProperty.getMetadata().getDefaultValue() != null) {
defaultValue = toTargetType(beanProperty.getType(), beanProperty.getMetadata().getDefaultValue());
} else if (ofNullable(beanProperty.getAnnotation(Default.class)).map(Default::value).isPresent()) {
defaultValue = toTargetType(beanProperty.getType(),
ofNullable(beanProperty.getAnnotation(Default.class)).map(Default::value).get());
} else {
defaultValue = null;
Optional<String> defaultAnnotationValue = ofNullable(beanProperty.getAnnotation(Default.class)).map(Default::value);

defaultValue = toJsonNode(beanProperty.getType(),
defaultAnnotationValue.orElse(beanProperty.getMetadata().getDefaultValue()));
}

JsonNode toJsonNode(JavaType type, String value) {
if (value == null) {
return null;
}
Optional<Class<?>> rawType = Optional.ofNullable(type).map(JavaType::getRawClass);
try {
Object typedValue = resolvingContext.kubernetesSerialization.unmarshal(value, rawType.orElse(Object.class));
return resolvingContext.kubernetesSerialization.convertValue(typedValue, JsonNode.class);
} catch (KubernetesClientException e) {
throw new IllegalArgumentException("Cannot parse default value: '" + value + "' as valid YAML or JSON.", e);
}
}

Expand Down Expand Up @@ -355,14 +364,7 @@ private void setMinMax(BeanProperty beanProperty,

public void updateSchema(T schema) {
schema.setDescription(description);

if (defaultValue != null) {
try {
schema.setDefault(resolvingContext.kubernetesSerialization.convertValue(defaultValue, JsonNode.class));
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Cannot parse default value: '" + defaultValue + "' as valid YAML.", e);
}
}
schema.setDefault(defaultValue);
if (nullable) {
schema.setNullable(true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@
package io.fabric8.crdv2.generator;

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;

import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -94,23 +92,4 @@ public static Map<String, String> toMap(String[] arr) {
return res;
}

static Object toTargetType(JavaType type, String value) {
if (type == null || value == null) {
return null;
}
try {
if (Number.class.isAssignableFrom(type.getRawClass()) || int.class.isAssignableFrom(type.getRawClass())
|| long.class.isAssignableFrom(type.getRawClass()) || float.class.isAssignableFrom(type.getRawClass())
|| double.class.isAssignableFrom(type.getRawClass())) {
return NumberFormat.getInstance().parse(value);
}
if (Boolean.class.isAssignableFrom(type.getRawClass()) || boolean.class.isAssignableFrom(type.getRawClass())) {
return Boolean.valueOf(value);
}
} catch (Exception ex) {
// NO OP
}
return value;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.DoubleNode;
import com.fasterxml.jackson.databind.node.FloatNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.LongNode;
import io.fabric8.generator.annotation.Default;
import org.assertj.core.api.InstanceOfAssertFactories;
Expand Down Expand Up @@ -55,24 +58,28 @@ private static final class ClassInTest {
@JsonProperty(defaultValue = "1337")
int defaultValueForInt;

@JsonProperty(defaultValue = "1337L")
@JsonProperty(defaultValue = "1337")
long defaultValueForLong;

@JsonProperty(defaultValue = "13.37")
float defaultValueForFloat;

@JsonProperty(defaultValue = "13.37d")
@JsonProperty(defaultValue = "13.37")
double defaultValueForDouble;

@JsonProperty
@Default("[]")
double[] defaultValueForDoubleArray;
}

@Test
@DisplayName("JsonProperty default value should take precedence over Default annotation")
@DisplayName("Default annotation should take precedence over JsonProperty")
void precedence() {
assertThat(JsonSchema.from(ClassInTest.class).getProperties())
.extracting("precedence._default")
.asInstanceOf(InstanceOfAssertFactories.type(JsonNode.class))
.extracting(JsonNode::asText)
.isEqualTo("precedence-from-json-property");
.isEqualTo("precedence-from-default-annotation");
}

@Test
Expand Down Expand Up @@ -135,7 +142,7 @@ void intFromJsonPropertyAnnotation() {
assertThat(JsonSchema.from(ClassInTest.class).getProperties())
.extracting("defaultValueForInt._default")
.asInstanceOf(InstanceOfAssertFactories.type(JsonNode.class))
.isInstanceOf(LongNode.class)
.isInstanceOf(IntNode.class)
.extracting(JsonNode::asInt)
.isEqualTo(1337);
}
Expand All @@ -157,9 +164,9 @@ void floatFromJsonPropertyAnnotation() {
assertThat(JsonSchema.from(ClassInTest.class).getProperties())
.extracting("defaultValueForFloat._default")
.asInstanceOf(InstanceOfAssertFactories.type(JsonNode.class))
.isInstanceOf(DoubleNode.class)
.extracting(JsonNode::asDouble)
.isEqualTo(13.37);
.isInstanceOf(FloatNode.class)
.extracting(JsonNode::asText)
.isEqualTo("13.37");
}

@Test
Expand All @@ -172,4 +179,15 @@ void doubleFromJsonPropertyAnnotation() {
.extracting(JsonNode::asDouble)
.isEqualTo(13.37);
}

@Test
@DisplayName("JsonProperty defaultValue annotation for double array")
void doubleArrayFromJsonPropertyAnnotation() {
assertThat(JsonSchema.from(ClassInTest.class).getProperties())
.extracting("defaultValueForDoubleArray._default")
.asInstanceOf(InstanceOfAssertFactories.type(JsonNode.class))
.isInstanceOf(ArrayNode.class)
.extracting(JsonNode::toPrettyString)
.isEqualTo("[ ]");
}
}
7 changes: 0 additions & 7 deletions doc/CRD-generator-migration-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,3 @@ myMap:
type: "string"
type: "object"
```
## Default values for CRD fields can be numeric or boolean
Previously default values defined by `@Default` could only be used on string fields.
With CRD Generator v2 defaults can be set on numeric and boolean fields, too.
In the same way is `@JsonProperty(defaultValue)` now working.

0 comments on commit bd07b6a

Please sign in to comment.