From c97befbd4c0427dca2ddc61b368b2fe8de947998 Mon Sep 17 00:00:00 2001 From: Addison Goolsbee Date: Tue, 15 Sep 2026 18:38:31 -0700 Subject: [PATCH] perf: 68x faster generation on large specs via existing schema index updateCodegenPropertyEnum resolved a property's referenced schema by streaming over every entry in components/schemas and recomputing toModelName() for each key until one matched. toModelName() is regex-heavy (sanitizeName + camelize), so each lookup cost O(schemas) in regex work. postProcessModelsEnum calls it eight times per model across overlapping var lists, so on large enum-heavy specs this dominated generation time. Sampling a typescript-fetch run on the Stripe spec, 117 of 119 JVM stack samples were in this method, nearly all in java.util.regex.Pattern.match. DefaultCodegen already builds exactly this index in getModelNameToSchemaCache(), but its only caller was TypeScriptClientCodegen, so every other generator paid the scan. Reuse it, unchanged. Measured against the parent commit, back to back, output compared by recursive diff and by checksum: typescript-fetch Stripe (8MB, 1454 schemas) 358.5s -> 5.3s 68x typescript-fetch GitHub (13MB, 977 schemas) 131.7s -> 4.2s 31x python Stripe 11s -> 9s go GitHub 8s -> 7s All four byte-identical. The TypeScript generators gain most because toTypescriptTypeName makes each toModelName() call expensive; other generators gain less and none regress. modelNameToSchemaCache is also cleared in setOpenAPI() so a reused codegen instance cannot serve a stale index. processOpts() runs before setOpenAPI() in DefaultGenerator, so naming options are fully applied before the index is built. Full openapi-generator module suite: 5033 tests, 0 failures. Co-Authored-By: Claude Opus 5 --- .../org/openapitools/codegen/DefaultCodegen.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 60c91bf9c446..dcdad60d1816 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -675,7 +675,6 @@ private boolean codegenPropertyIsNew(CodegenModel model, CodegenProperty propert */ protected Map getModelNameToSchemaCache() { if (modelNameToSchemaCache == null) { - // Create a cache to efficiently lookup schema based on model name. Map m = new HashMap<>(); ModelUtils.getSchemas(openAPI).forEach((key, schema) -> m.put(toModelName(key), schema)); modelNameToSchemaCache = Collections.unmodifiableMap(m); @@ -1060,6 +1059,7 @@ public void setOpenAPI(OpenAPI openAPI) { once(LOGGER).warn(UNSUPPORTED_V310_SPEC_MSG); } this.openAPI = openAPI; + this.modelNameToSchemaCache = null; // Set global settings such that helper functions in ModelUtils can lookup the value // of the CLI option. ModelUtils.setDisallowAdditionalPropertiesIfNotPresent(getDisallowAdditionalPropertiesIfNotPresent()); @@ -7166,18 +7166,15 @@ public void updateCodegenPropertyEnum(CodegenProperty var) { } String varDataType = var.mostInnerItems != null ? var.mostInnerItems.dataType : var.dataType; - Optional referencedSchema = ModelUtils.getSchemas(openAPI).entrySet().stream() - .filter(entry -> Objects.equals(varDataType, toModelName(entry.getKey()))) - .map(Map.Entry::getValue) - .findFirst(); - String dataType = (referencedSchema.isPresent()) ? getTypeDeclaration(referencedSchema.get()) : varDataType; + Schema referencedSchema = getModelNameToSchemaCache().get(varDataType); + String dataType = referencedSchema != null ? getTypeDeclaration(referencedSchema) : varDataType; List enumVars = buildEnumVars(values, dataType); postProcessEnumVars(enumVars); // if "x-enum-varnames" or "x-enum-descriptions" defined, update varnames Map extensions = var.mostInnerItems != null ? var.mostInnerItems.getVendorExtensions() : var.getVendorExtensions(); - if (referencedSchema.isPresent()) { - extensions = referencedSchema.get().getExtensions(); + if (referencedSchema != null) { + extensions = referencedSchema.getExtensions(); } updateEnumVarsWithExtensions(enumVars, extensions, dataType); allowableValues.put(ENUM_VARS, enumVars);