Skip to content

Commit

Permalink
fix: rely upon jackson json schema for java types
Browse files Browse the repository at this point in the history
closes #5866

Signed-off-by: Steve Hawkins <[email protected]>
  • Loading branch information
shawkins committed Apr 10, 2024
1 parent fbcc9b6 commit c1580cf
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Fix #5847: Missing `Log4j2Plugins.dat` descriptor in Kubernetes Lookup
* Fix #5853: [java-generator] Gracefully handle colliding enum definitions
* Fix #5860: Corrections to java-generator gradle plugin extension
* Fix #5866: Addressed cycle in crd generation with Java 19+ and ZonedDateTime
* Fix #5817: NPE on EKS OIDC cluster when token needs to be refreshed

#### Improvements
Expand Down
5 changes: 5 additions & 0 deletions crd-generator/api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
<artifactId>kubernetes-client-api</artifactId>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jsonSchema</artifactId>
</dependency>

<dependency>
<groupId>io.fabric8</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@
package io.fabric8.crd.generator;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
import io.fabric8.crd.generator.InternalSchemaSwaps.SwapResult;
import io.fabric8.crd.generator.annotation.SchemaSwap;
import io.fabric8.crd.generator.utils.Types;
import io.fabric8.generator.annotation.ValidationRule;
import io.fabric8.kubernetes.api.model.Duration;
import io.fabric8.kubernetes.api.model.IntOrString;
import io.fabric8.kubernetes.api.model.Quantity;
import io.fabric8.kubernetes.client.utils.KubernetesSerialization;
import io.sundr.builder.internal.functions.TypeAs;
import io.sundr.model.AnnotationRef;
import io.sundr.model.ClassRef;
Expand All @@ -43,6 +47,7 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
Expand Down Expand Up @@ -122,6 +127,9 @@ public abstract class AbstractJsonSchema<T, B> {
public static final String JSON_NODE_TYPE = "com.fasterxml.jackson.databind.JsonNode";
public static final String ANY_TYPE = "io.fabric8.kubernetes.api.model.AnyType";

private static final JsonSchemaGenerator GENERATOR;
private static final Set<String> COMPLEX_JAVA_TYPES = new HashSet<>();

static {
COMMON_MAPPINGS.put(STRING_REF, STRING_MARKER);
COMMON_MAPPINGS.put(DATE_REF, STRING_MARKER);
Expand All @@ -138,6 +146,10 @@ public abstract class AbstractJsonSchema<T, B> {
COMMON_MAPPINGS.put(QUANTITY_REF, INT_OR_STRING_MARKER);
COMMON_MAPPINGS.put(INT_OR_STRING_REF, INT_OR_STRING_MARKER);
COMMON_MAPPINGS.put(DURATION_REF, STRING_MARKER);
ObjectMapper mapper = new ObjectMapper();
// initialize with client defaults
new KubernetesSerialization(mapper, false);
GENERATOR = new JsonSchemaGenerator(mapper);
}

public static String getSchemaTypeFor(TypeRef typeRef) {
Expand Down Expand Up @@ -853,18 +865,55 @@ private T internalFromImpl(String name, TypeRef typeRef, LinkedHashMap<String, S

private T resolveNestedClass(String name, TypeDef def, LinkedHashMap<String, String> visited,
InternalSchemaSwaps schemaSwaps) {
if (visited.put(def.getFullyQualifiedName(), name) != null) {
String fullyQualifiedName = def.getFullyQualifiedName();
String mapping = resolveJavaClass(fullyQualifiedName);
if (mapping != null) {
return singleProperty(mapping);
}
if (visited.put(fullyQualifiedName, name) != null) {
throw new IllegalArgumentException(
"Found a cyclic reference involving the field of type " + def.getFullyQualifiedName() + " starting a field "
"Found a cyclic reference involving the field of type " + fullyQualifiedName + " starting a field "
+ visited.entrySet().stream().map(e -> e.getValue() + " >>\n" + e.getKey()).collect(Collectors.joining(".")) + "."
+ name);
}

T res = internalFromImpl(def, visited, schemaSwaps);
visited.remove(def.getFullyQualifiedName());
visited.remove(fullyQualifiedName);
return res;
}

private String resolveJavaClass(String fullyQualifiedName) {
if ((!fullyQualifiedName.startsWith("java.") && !fullyQualifiedName.startsWith("javax."))
|| COMPLEX_JAVA_TYPES.contains(fullyQualifiedName)) {
return null;
}
String mapping = null;
try {
Class<?> clazz = Class.forName(fullyQualifiedName);
JsonSchema schema = GENERATOR.generateSchema(clazz);
if (schema.isIntegerSchema()) {
mapping = INTEGER_MARKER;
} else if (schema.isNumberSchema()) {
mapping = NUMBER_MARKER;
} else if (schema.isBooleanSchema()) {
mapping = BOOLEAN_MARKER;
} else if (schema.isStringSchema()) {
mapping = STRING_MARKER;
}
} catch (Exception e) {
LOGGER.debug(
"Something went wrong with detecting java type schema for {}, will use full introspection instead",
fullyQualifiedName, e);
}
// cache the result for subsequent calls
if (mapping != null) {
COMMON_MAPPINGS.put(TypeDef.forName(fullyQualifiedName).toReference(), mapping);
} else {
COMPLEX_JAVA_TYPES.add(fullyQualifiedName);
}
return mapping;
}

/**
* Builds the schema for specifically handled property types (e.g. intOrString properties)
*
Expand Down

0 comments on commit c1580cf

Please sign in to comment.