From eec18ee67deea4896923a8c443db0d921cc31f68 Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Wed, 4 Sep 2024 13:00:43 +0200 Subject: [PATCH] feat(openapi): configurable java type mappings to OpenAPI refs Signed-off-by: Marc Nuri --- .../schema/generator/GeneratorSettings.java | 3 ++ .../generator/schema/SchemaFlattener.java | 21 +++++++---- .../schema/generator/schema/SchemaUtils.java | 34 +++++++---------- .../schema/generator/SchemaUtilsTest.java | 37 ++++++++++++++++++- 4 files changed, 66 insertions(+), 29 deletions(-) diff --git a/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/GeneratorSettings.java b/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/GeneratorSettings.java index 827b6f3ac08..4eb59e05d91 100644 --- a/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/GeneratorSettings.java +++ b/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/GeneratorSettings.java @@ -37,6 +37,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; @@ -78,6 +79,8 @@ public class GeneratorSettings { @Singular private Map packageMappings; private final AtomicBoolean packageMappingsProcessed = new AtomicBoolean(false); + @Builder.Default + private Properties refToJavaTypeMappings = new Properties(); @Singular private Set skipGenerationRegexes; @Singular diff --git a/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/schema/SchemaFlattener.java b/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/schema/SchemaFlattener.java index 7b71071f342..ab0f4a008bf 100644 --- a/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/schema/SchemaFlattener.java +++ b/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/schema/SchemaFlattener.java @@ -123,7 +123,7 @@ private static final class SchemaFlattenerContext { /** * Retrieves the context from the provided OpenAPI extensions. - * + * * @param openAPI the openAPI instance where the context is stored. * @return the context. */ @@ -137,7 +137,7 @@ private static synchronized SchemaFlattenerContext get(OpenAPI openAPI) { /** * Remove the context from the OpenAPI extensions. - * + * * @param openAPI the openAPI instance where the context is stored. */ private static synchronized void clear(OpenAPI openAPI) { @@ -153,18 +153,23 @@ private static synchronized void clear(OpenAPI openAPI) { public SchemaFlattenerContext(OpenAPI openAPI) { this.openAPI = openAPI; - uniqueNames = ConcurrentHashMap.newKeySet(); - generatedComponentSignatures = new ConcurrentHashMap<>(); - componentsToAdd = new ConcurrentHashMap<>(); - } - - Components getComponents() { if (openAPI.getComponents() == null) { openAPI.setComponents(new Components()); } if (openAPI.getComponents().getSchemas() == null) { openAPI.getComponents().setSchemas(new HashMap<>()); } + uniqueNames = ConcurrentHashMap.newKeySet(); + generatedComponentSignatures = new ConcurrentHashMap<>(); + // Compute signatures of all defined components to be able to reuse them from inlined component definitions + for (String key : openAPI.getComponents().getSchemas().keySet()) { + final Schema schema = openAPI.getComponents().getSchemas().get(key); + generatedComponentSignatures.put(toJson(schema), key); + } + componentsToAdd = new ConcurrentHashMap<>(); + } + + Components getComponents() { return openAPI.getComponents(); } diff --git a/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/schema/SchemaUtils.java b/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/schema/SchemaUtils.java index 46c05d90f32..4bdb06e23b9 100644 --- a/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/schema/SchemaUtils.java +++ b/kubernetes-model-generator/openapi/maven-plugin/src/main/java/io/fabric8/kubernetes/schema/generator/schema/SchemaUtils.java @@ -25,7 +25,6 @@ import io.swagger.v3.oas.models.Paths; import io.swagger.v3.oas.models.SpecVersion; import io.swagger.v3.oas.models.media.ArraySchema; -import io.swagger.v3.oas.models.media.ComposedSchema; import io.swagger.v3.oas.models.media.DateTimeSchema; import io.swagger.v3.oas.models.media.MapSchema; import io.swagger.v3.oas.models.media.Schema; @@ -211,10 +210,10 @@ public String schemaToClassName(ImportManager imports, Schema schema) { if (javaPrimitive.isPresent()) { return javaPrimitive.get(); } - final Optional javaType = schemaRefToJavaType(schema); - if (javaType.isPresent()) { - imports.addImport(javaType.get()); - return javaType.get().substring(javaType.get().lastIndexOf('.') + 1); + final String javaType = schemaRefToJavaType(schema); + if (javaType != null) { + imports.addImport(javaType); + return javaType.substring(javaType.lastIndexOf('.') + 1); } if (imports.hasSimpleClassName(refToModelPackage(ref))) { return refToModelPackage(ref); @@ -249,14 +248,10 @@ public boolean isHasMetadata(Schema schema) { return schema != null && schema.getProperties() != null && schema.getProperties().containsKey("metadata") - && schemaRefToJavaType(schema.getProperties().get("metadata")) - .filter(settings.getObjectMetaClass()::equals).isPresent(); + && Objects.equals(settings.getObjectMetaClass(), schemaRefToJavaType(schema.getProperties().get("metadata"))); } public static boolean isMap(Schema schema) { - if (schema instanceof MapSchema) { - return true; - } if (schema != null && schema.getAdditionalProperties() instanceof Schema) { return true; } @@ -264,7 +259,7 @@ public static boolean isMap(Schema schema) { && (Boolean) schema.getAdditionalProperties()) { return true; } - return false; + return schema instanceof MapSchema; } public static boolean isRef(Schema schema) { @@ -277,16 +272,12 @@ public static boolean isObject(Schema schema) { public boolean isString(Schema schema) { final String ref = schema.get$ref(); - if (ref != null && (REF_TO_JAVA_PRIMITIVE_MAP.containsKey(ref) || REF_TO_JAVA_TYPE_MAP.containsKey(ref))) { + if (ref != null && (REF_TO_JAVA_PRIMITIVE_MAP.containsKey(ref) || schemaRefToJavaType(schema) != null)) { return false; } return schema instanceof StringSchema || isRefInstanceOf(ref, StringSchema.class); } - public static boolean isComposed(Schema schema) { - return schema instanceof ComposedSchema; - } - public boolean isRefInstanceOf(String ref, Class clazz) { if (ref == null) { return false; @@ -312,8 +303,11 @@ private static Optional schemaRefToJavaPrimitive(Schema schema) { return Optional.ofNullable(REF_TO_JAVA_PRIMITIVE_MAP.get(schema.get$ref())); } - private static Optional schemaRefToJavaType(Schema schema) { - return Optional.ofNullable(REF_TO_JAVA_TYPE_MAP.get(schema.get$ref())); + private String schemaRefToJavaType(Schema schema) { + if (settings.getRefToJavaTypeMappings().containsKey(schema.get$ref())) { + return settings.getRefToJavaTypeMappings().getProperty(schema.get$ref()); + } + return REF_TO_JAVA_TYPE_MAP.get(schema.get$ref()); } private static String schemaTypeToJavaPrimitive(Schema schema) { @@ -334,8 +328,8 @@ public static String sanitizeDescription(String description) { .replace("*", "*") .replace("<", "<") .replace(">", ">") - .replace('\u201C', '"') - .replace('\u201D', '"') + .replace('“', '"') + .replace('”', '"') .replace("\n", "

"); } diff --git a/kubernetes-model-generator/openapi/maven-plugin/src/test/java/io/fabric8/kubernetes/schema/generator/SchemaUtilsTest.java b/kubernetes-model-generator/openapi/maven-plugin/src/test/java/io/fabric8/kubernetes/schema/generator/SchemaUtilsTest.java index b1b29b6158e..de873432ff0 100644 --- a/kubernetes-model-generator/openapi/maven-plugin/src/test/java/io/fabric8/kubernetes/schema/generator/SchemaUtilsTest.java +++ b/kubernetes-model-generator/openapi/maven-plugin/src/test/java/io/fabric8/kubernetes/schema/generator/SchemaUtilsTest.java @@ -36,6 +36,7 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Properties; import java.util.TreeSet; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -248,7 +249,7 @@ void _double() { class Ref { @Test - void ref() { + void refFromDefault() { final ObjectSchema schema = new ObjectSchema(); schema.set$ref("#/definitions/io.k8s.api.core.v1.Pod"); final String result = schemaUtils.schemaToClassName(importManager, schema); @@ -309,6 +310,40 @@ void plainObject() { assertEquals("io.fabric8.kubernetes.api.model.KubernetesResource", importManager.getImports().iterator().next()); } + @Test + void mappingDefault() { + final ObjectSchema schema = new ObjectSchema(); + schema.set$ref("#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"); + final String result = schemaUtils.schemaToClassName(importManager, schema); + assertEquals("ObjectMeta", result); + assertEquals("io.fabric8.kubernetes.api.model.ObjectMeta", importManager.getImports().iterator().next()); + } + + @Test + void mappingConfiguredInSettings() { + final Properties properties = new Properties(); + properties.put("io.k8s.api.core.v1.ToBeMapped", "io.fabric8.kubernetes.api.model.Mapped"); + final ObjectSchema schema = new ObjectSchema(); + schema.set$ref("io.k8s.api.core.v1.ToBeMapped"); + schemaUtils = new SchemaUtils(generatorSettingsBuilder.refToJavaTypeMappings(properties).build()); + final String result = schemaUtils.schemaToClassName(importManager, schema); + assertEquals("Mapped", result); + assertEquals("io.fabric8.kubernetes.api.model.Mapped", importManager.getImports().iterator().next()); + } + + @Test + void configuredInSettingsTakesPrecedence() { + final Properties properties = new Properties(); + properties.put("#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", + "io.fabric8.kubernetes.api.model.Mapped"); + final ObjectSchema schema = new ObjectSchema(); + schema.set$ref("#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"); + schemaUtils = new SchemaUtils(generatorSettingsBuilder.refToJavaTypeMappings(properties).build()); + final String result = schemaUtils.schemaToClassName(importManager, schema); + assertEquals("Mapped", result); + assertEquals("io.fabric8.kubernetes.api.model.Mapped", importManager.getImports().iterator().next()); + } + } @Nested