Skip to content

Commit

Permalink
feat(openapi): configurable java type mappings to OpenAPI refs
Browse files Browse the repository at this point in the history
Signed-off-by: Marc Nuri <[email protected]>
  • Loading branch information
manusa authored Sep 4, 2024
1 parent 6758880 commit eec18ee
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -78,6 +79,8 @@ public class GeneratorSettings {
@Singular
private Map<String, String> packageMappings;
private final AtomicBoolean packageMappingsProcessed = new AtomicBoolean(false);
@Builder.Default
private Properties refToJavaTypeMappings = new Properties();
@Singular
private Set<String> skipGenerationRegexes;
@Singular
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -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) {
Expand All @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -211,10 +210,10 @@ public String schemaToClassName(ImportManager imports, Schema<?> schema) {
if (javaPrimitive.isPresent()) {
return javaPrimitive.get();
}
final Optional<String> 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);
Expand Down Expand Up @@ -249,22 +248,18 @@ 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;
}
if (schema != null && schema.getAdditionalProperties() instanceof Boolean
&& (Boolean) schema.getAdditionalProperties()) {
return true;
}
return false;
return schema instanceof MapSchema;
}

public static boolean isRef(Schema<?> schema) {
Expand All @@ -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;
Expand All @@ -312,8 +303,11 @@ private static Optional<String> schemaRefToJavaPrimitive(Schema<?> schema) {
return Optional.ofNullable(REF_TO_JAVA_PRIMITIVE_MAP.get(schema.get$ref()));
}

private static Optional<String> 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) {
Expand All @@ -334,8 +328,8 @@ public static String sanitizeDescription(String description) {
.replace("*", "&#42;")
.replace("<", "&lt;")
.replace(">", "&gt;")
.replace('\u201C', '"')
.replace('\u201D', '"')
.replace('', '"')
.replace('', '"')
.replace("\n", "<br><p> ");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit eec18ee

Please sign in to comment.