Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.

Commit 9bc1ae1

Browse files
committed
v3 convert nested schemas into sequential schemas (#177)
* Writes nested schemas earlier and uses them later * Refactors order CodegenSchema properties are set in to match the order in getSchemas * Adjusts ref input to setSchemaLocationInfo * Tweak improves schema template * Adds properties classes * Replaces properties with field * Uses Schema_() * Uses dataclass properties * Adds missing type info * Updates all_of * Adds any_of, all_of tuples * Fixes types definition * Fixed test_any_type_schema tests * Fixes dataclass type setting issues * Fixes simple schema format type * Adds and uses PatternInfo for pattern schema info, validate_regex changed to validate_pattern * Fixes not constraint tests * Adds tuple_to_instance * Writes out allOf/anyOf/oneOf types * Updates classproperty decorator * Adds enum return types * Fixes type errors in schemas.py * Adds schema singleton metaclass * Replaces CodegenServer variables with object schema containing variables in properties * Generates server variables as an object schema to keep all schemas at the root depth * Fixes new signatures in servers schemas * Simplifies Server variables definition * Uses schema default for server variables * Adds required vars in server definition * Fixes classproperty and SchemaBase classes * Fixes broken configuration tests * Fixes server docs * Adds isInlineDefinition * Adds allOf/anyOf/oneOf/properties jsonPathPiece * Uses jsonPathPiece in properties/allOf/anyOf/oneOf * Fixes properties typeddict name * Templates updated to write allOf/anyOf/oneOf/properties earlier if possible * generates properties/allOf/anyOf/oneOf before class if possible * Adds and uses schemas.INPUT_TYPES_ALL_INCL_SCHEMA * Adds another usage of schemas.INPUT_TYPES_ALL_INCL_SCHEMA * Changes SchemaBase to SingletonMeta * Only calculates allSchemas once * Reduces iteration through allSchemas from 2x to 1x * Removes some getKey invocations * Consolidates more getKey usages * Deletes getKey with one input * Adds comment * Updates the definition of required properties, reduces the number of calls to getKey * Updates getKey to use sourceJsonPath * Adds class name generation that includes numbered suffixes when needed * Uses pre order traversal for naming schema classes * Fixes oneOf/anyOf/allOf type aliases * Adds and uses schemas.INPUT_BASE_TYPES * Adds string representation of CodegenKey * Fixes java tests * Samples regenerated * Samples regenerated
1 parent 646c57c commit 9bc1ae1

409 files changed

Lines changed: 13691 additions & 18415 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/CodegenConfig.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public interface CodegenConfig {
144144

145145
CodegenOperation fromOperation(Operation operation, String jsonPath);
146146

147-
CodegenKey getKey(String key);
147+
CodegenKey getKey(String key, String keyType);
148148

149149
CodegenSecurityScheme fromSecurityScheme(SecurityScheme securityScheme, String jsonPath);
150150

@@ -156,7 +156,7 @@ public interface CodegenConfig {
156156

157157
List<CodegenServer> fromServers(List<Server> servers, String jsonPath);
158158

159-
HashMap<CodegenKey, CodegenSchema> fromServerVariables(Map<String, ServerVariable> variables, String jsonPath);
159+
CodegenSchema fromServerVariables(Map<String, ServerVariable> variables, String jsonPath);
160160

161161
Map<String, String> typeMapping();
162162

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/DefaultCodegen.java

Lines changed: 170 additions & 136 deletions
Large diffs are not rendered by default.

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/languages/PythonClientCodegen.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -765,8 +765,13 @@ public String toModuleFilename(String name, String jsonPath) {
765765
return underscore(dropDots(toModelName(name, jsonPath)));
766766
}
767767

768+
/*
769+
This method requires jsonPath to be passed in
770+
It handles responses and schemas
771+
*/
768772
@Override
769773
public String toModelName(String name, String jsonPath) {
774+
boolean rootEntity = (jsonPath != null && jsonPath.endsWith(name));
770775
PairCacheKey key = new PairCacheKey(name, jsonPath);
771776
if (modelNameCache.containsKey(key)) {
772777
return modelNameCache.get(key);
@@ -809,8 +814,8 @@ public String toModelName(String name, String jsonPath) {
809814
// model name cannot use reserved keyword, e.g. return
810815
if (isReservedWord(camelizedName)) {
811816
String modelName = "_" + camelizedName; // e.g. return => ModelReturn (after camelize)
812-
if (isComponent) {
813-
LOGGER.warn("{} (reserved word) cannot be used as component name. Renamed to {}", camelizedName, modelName);
817+
if (isComponent && rootEntity) {
818+
LOGGER.warn("{} (reserved word) cannot be used as name. Renamed to {}", camelizedName, modelName);
814819
}
815820
modelNameCache.put(key, modelName);
816821
return modelName;
@@ -820,7 +825,7 @@ public String toModelName(String name, String jsonPath) {
820825
// model name starts with number
821826
if (camelizedName.matches("^\\d.*")) {
822827
String modelName = "_" + camelizedName; // e.g. return => ModelReturn (after camelize)
823-
if (isComponent) {
828+
if (isComponent && rootEntity) {
824829
LOGGER.warn("{} (component name starts with number) cannot be used as name. Renamed to {}", camelizedName, modelName);
825830
}
826831
modelNameCache.put(key, modelName);
@@ -1356,7 +1361,7 @@ private String toExampleValueRecursive(String modelName, Schema schema, Object o
13561361
String schemaName = getSchemaName(mm.modelName);
13571362
Schema modelSchema = getModelNameToSchemaCache().get(schemaName);
13581363
CodegenSchema cp = new CodegenSchema();
1359-
cp.jsonPathPiece = getKey(disc.propertyName.original);
1364+
cp.jsonPathPiece = getKey(disc.propertyName.original, "misc");
13601365
cp.example = discPropNameValue;
13611366
return exampleForObjectModel(modelSchema, fullPrefix, closeChars, cp, indentationLevel, exampleLine, closingIndentation, includedSchemas);
13621367
}
@@ -1523,7 +1528,7 @@ private String toExampleValueRecursive(String modelName, Schema schema, Object o
15231528
String schemaName = getSchemaName(mm.modelName);
15241529
Schema modelSchema = getModelNameToSchemaCache().get(schemaName);
15251530
CodegenSchema cp = new CodegenSchema();
1526-
cp.jsonPathPiece = getKey(disc.propertyName.original);
1531+
cp.jsonPathPiece = getKey(disc.propertyName.original, "misc");
15271532
cp.example = discPropNameValue;
15281533
return exampleForObjectModel(modelSchema, fullPrefix, closeChars, cp, indentationLevel, exampleLine, closingIndentation, includedSchemas);
15291534
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package org.openapijsonschematools.codegen.model;
2+
3+
import java.util.ArrayList;
4+
5+
/**
6+
* A class to store inline codegenschema definitions
7+
*/
8+
public class ArrayListWithContext<E> extends ArrayList<E> implements InlineContext {
9+
private boolean internalallAreInline = false;
10+
private CodegenKey internalJsonPathPiece = null;
11+
public boolean allAreInline() {
12+
return internalallAreInline;
13+
}
14+
15+
public void setAllAreInline(boolean allAreInline) {
16+
this.internalallAreInline = allAreInline;
17+
}
18+
19+
public CodegenKey jsonPathPiece() {
20+
return internalJsonPathPiece;
21+
}
22+
23+
public void setJsonPathPiece(CodegenKey jsonPathPiece) {
24+
this.internalJsonPathPiece = jsonPathPiece;
25+
}
26+
}

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/model/CodegenKey.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ public boolean equals(Object o) {
2929
Objects.equals(anchorPiece, that.anchorPiece);
3030
}
3131

32+
@Override
33+
public String toString() {
34+
final StringBuilder sb = new StringBuilder("CodegenKey{");
35+
sb.append("original=").append(original);
36+
sb.append(", isValid=").append(isValid);
37+
sb.append(", snakeCase=").append(snakeCase);
38+
sb.append(", camelCase=").append(camelCase);
39+
sb.append(", anchorPiece=").append(anchorPiece);
40+
sb.append('}');
41+
return sb.toString();
42+
}
43+
3244
@Override
3345
public int hashCode() {
3446
return Objects.hash(original, isValid, snakeCase, camelCase, anchorPiece);

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/model/CodegenSchema.java

Lines changed: 125 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import io.swagger.v3.oas.models.ExternalDocumentation;
2121

22+
import java.util.ArrayList;
2223
import java.util.HashMap;
2324
import java.util.LinkedHashMap;
2425
import java.util.LinkedHashSet;
@@ -46,12 +47,12 @@ public class CodegenSchema {
4647
public LinkedHashMap<CodegenKey, CodegenSchema> requiredProperties; // used to store required info
4748
public LinkedHashMap<EnumValue, String> enumValueToName; // enum info
4849
public String type;
49-
public List<CodegenSchema> allOf = null;
50-
public List<CodegenSchema> anyOf = null;
51-
public List<CodegenSchema> oneOf = null;
50+
public ArrayListWithContext<CodegenSchema> allOf = null;
51+
public ArrayListWithContext<CodegenSchema> anyOf = null;
52+
public ArrayListWithContext<CodegenSchema> oneOf = null;
5253
public CodegenSchema not = null;
5354
public CodegenSchema items;
54-
public LinkedHashMap<CodegenKey, CodegenSchema> properties;
55+
public LinkedHashMapWithContext<CodegenKey, CodegenSchema> properties;
5556
public CodegenSchema additionalProperties;
5657
public String description;
5758
public String format;
@@ -86,6 +87,12 @@ public class CodegenSchema {
8687
public LinkedHashMap<CodegenKey, CodegenSchema> optionalProperties;
8788
public boolean schemaIsFromAdditionalProperties;
8889
public HashMap<String, SchemaTestCase> testCases = new HashMap<>();
90+
/**
91+
* schema/allOfType/anyOfType/oneOfType/propertiesType/importsType
92+
* used in getAllSchemas to write type definitions for allOfType/anyOfType/oneOfType/propertiesType
93+
*/
94+
public String instanceType;
95+
private ArrayList<CodegenSchema> allSchemas = null;
8996

9097
public boolean hasValidation() {
9198
return maxItems != null || minItems != null || minProperties != null || maxProperties != null || minLength != null || maxLength != null || multipleOf != null || patternInfo != null || minimum != null || maximum != null || exclusiveMinimum != null || exclusiveMaximum != null || uniqueItems != null;
@@ -126,6 +133,118 @@ public CodegenSchema getSelfOrDeepestRef() {
126133
return refObject;
127134
}
128135

136+
/**
137+
* Returns all schemas in post order traversal, used by templates to write schema classes
138+
* @param schemasBeforeImports the input list that stores this and all required schemas
139+
* @return the list that stores this and all required schemas
140+
*/
141+
private void getAllSchemas(ArrayList<CodegenSchema> schemasBeforeImports, ArrayList<CodegenSchema> schemasAfterImports, int level) {
142+
/*
143+
post order traversal using alphabetic json schema keywords as the order
144+
keywords with schemas:
145+
additionalProperties
146+
allOf
147+
anyOf
148+
items
149+
not
150+
oneOf
151+
properties
152+
(self)
153+
154+
excluded:
155+
discriminator (not actually applicable because all values would be refs and do not need to be defined)
156+
$ref (because it is an import)
157+
*/
158+
if (isBooleanSchemaFalse) {
159+
// return early for isBooleanSchemaFalse so not_ will not be written
160+
schemasBeforeImports.add(this);
161+
return;
162+
}
163+
if (additionalProperties != null) {
164+
additionalProperties.getAllSchemas(schemasBeforeImports, schemasAfterImports, level + 1);
165+
}
166+
if (allOf != null) {
167+
for (CodegenSchema someSchema: allOf) {
168+
someSchema.getAllSchemas(schemasBeforeImports, schemasAfterImports, level + 1);
169+
}
170+
CodegenSchema extraSchema = new CodegenSchema();
171+
extraSchema.instanceType = "allOfType";
172+
extraSchema.allOf = allOf;
173+
if (allOf.allAreInline()) {
174+
schemasBeforeImports.add(extraSchema);
175+
} else {
176+
schemasAfterImports.add(extraSchema);
177+
}
178+
}
179+
if (anyOf != null) {
180+
for (CodegenSchema someSchema: anyOf) {
181+
someSchema.getAllSchemas(schemasBeforeImports, schemasAfterImports,level + 1);
182+
}
183+
CodegenSchema extraSchema = new CodegenSchema();
184+
extraSchema.instanceType = "anyOfType";
185+
extraSchema.anyOf = anyOf;
186+
if (anyOf.allAreInline()) {
187+
schemasBeforeImports.add(extraSchema);
188+
} else {
189+
schemasAfterImports.add(extraSchema);
190+
}
191+
}
192+
if (items != null) {
193+
items.getAllSchemas(schemasBeforeImports, schemasAfterImports, level + 1);
194+
}
195+
if (not != null) {
196+
not.getAllSchemas(schemasBeforeImports, schemasAfterImports, level + 1);
197+
}
198+
if (oneOf != null) {
199+
for (CodegenSchema someSchema: oneOf) {
200+
someSchema.getAllSchemas(schemasBeforeImports, schemasAfterImports, level + 1);
201+
}
202+
CodegenSchema extraSchema = new CodegenSchema();
203+
extraSchema.instanceType = "oneOfType";
204+
extraSchema.oneOf = oneOf;
205+
if (oneOf.allAreInline()) {
206+
schemasBeforeImports.add(extraSchema);
207+
} else {
208+
schemasAfterImports.add(extraSchema);
209+
}
210+
}
211+
if (properties != null) {
212+
for (CodegenSchema someSchema: properties.values()) {
213+
someSchema.getAllSchemas(schemasBeforeImports, schemasAfterImports, level + 1);
214+
}
215+
CodegenSchema extraSchema = new CodegenSchema();
216+
extraSchema.instanceType = "propertiesType";
217+
extraSchema.properties = properties;
218+
if (properties.allAreInline()) {
219+
schemasBeforeImports.add(extraSchema);
220+
} else {
221+
schemasAfterImports.add(extraSchema);
222+
}
223+
}
224+
if (refInfo != null && level > 0) {
225+
// do not add ref to schemas
226+
return;
227+
}
228+
schemasBeforeImports.add(this);
229+
if (level == 0 && imports != null && !imports.isEmpty()) {
230+
CodegenSchema extraSchema = new CodegenSchema();
231+
extraSchema.instanceType = "importsType";
232+
extraSchema.imports = imports;
233+
schemasBeforeImports.add(extraSchema);
234+
}
235+
}
236+
237+
public ArrayList<CodegenSchema> getSchemas() {
238+
if (allSchemas == null) {
239+
ArrayList<CodegenSchema> schemasBeforeImports = new ArrayList<>();
240+
ArrayList<CodegenSchema> schemasAfterImports = new ArrayList<>();
241+
getAllSchemas(schemasBeforeImports, schemasAfterImports, 0);
242+
schemasBeforeImports.addAll(schemasAfterImports);
243+
allSchemas = schemasBeforeImports;
244+
}
245+
return allSchemas;
246+
}
247+
129248
public boolean isComplicated() {
130249
// used by templates
131250

@@ -137,7 +256,7 @@ public boolean isComplicated() {
137256

138257
protected void addInstanceInfo(StringBuilder sb) {
139258
sb.append(", description='").append(description).append('\'');
140-
sb.append(", name='").append(jsonPathPiece).append('\'');
259+
sb.append(", jsonPathPiece='").append(jsonPathPiece).append('\'');
141260
sb.append(", defaultValue='").append(defaultValue).append('\'');
142261
sb.append(", title='").append(title).append('\'');
143262
sb.append(", unescapedDescription='").append(unescapedDescription).append('\'');
@@ -186,6 +305,7 @@ protected void addInstanceInfo(StringBuilder sb) {
186305
sb.append(", imports=").append(imports);
187306
sb.append(", componentModule=").append(componentModule);
188307
sb.append(", testCases=").append(testCases);
308+
sb.append(", instanceType=").append(instanceType);
189309
}
190310

191311
@Override

modules/openapi-json-schema-generator/src/main/java/org/openapijsonschematools/codegen/model/CodegenServer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ public class CodegenServer {
77
public final String url;
88
public final String defaultUrl;
99
public final String description;
10-
public final LinkedHashMap<CodegenKey, CodegenSchema> variables;
10+
public final CodegenSchema variables;
1111
public final CodegenKey jsonPathPiece;
1212
public final boolean rootServer;
1313

14-
public CodegenServer(String url, String description, LinkedHashMap<CodegenKey, CodegenSchema> variables, CodegenKey jsonPathPiece, boolean rootServer) {
14+
public CodegenServer(String url, String description, CodegenSchema variables, CodegenKey jsonPathPiece, boolean rootServer) {
1515
this.url = url;
1616
this.description = description;
1717
this.variables = variables;
@@ -21,7 +21,7 @@ public CodegenServer(String url, String description, LinkedHashMap<CodegenKey, C
2121
this.defaultUrl = url;
2222
} else {
2323
String defaultUrl = url;
24-
for (CodegenSchema variable: variables.values()) {
24+
for (CodegenSchema variable: variables.properties.values()) {
2525
defaultUrl = defaultUrl.replace("{" + variable.jsonPathPiece.original + "}", (String) variable.defaultValue.value);
2626
}
2727
this.defaultUrl = defaultUrl;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.openapijsonschematools.codegen.model;
2+
3+
public interface InlineContext {
4+
public boolean allAreInline();
5+
6+
public void setAllAreInline(boolean allAreInline);
7+
8+
public CodegenKey jsonPathPiece();
9+
10+
public void setJsonPathPiece(CodegenKey jsonPathPiece);
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.openapijsonschematools.codegen.model;
2+
3+
import java.util.LinkedHashMap;
4+
5+
public class LinkedHashMapWithContext<K, V> extends LinkedHashMap<K, V> implements InlineContext {
6+
private boolean internalallAreInline = false;
7+
private CodegenKey internalJsonPathPiece = null;
8+
public boolean allAreInline() {
9+
return internalallAreInline;
10+
}
11+
12+
public void setAllAreInline(boolean allAreInline) {
13+
this.internalallAreInline = allAreInline;
14+
}
15+
16+
public CodegenKey jsonPathPiece() {
17+
return internalJsonPathPiece;
18+
}
19+
20+
public void setJsonPathPiece(CodegenKey jsonPathPiece) {
21+
this.internalJsonPathPiece = jsonPathPiece;
22+
}
23+
}

modules/openapi-json-schema-generator/src/main/resources/python/_helper_types_all_incl_schema.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ None,
1414
bytes,
1515
io.FileIO,
1616
io.BufferedReader,
17-
'Schema',
17+
'Schema',

0 commit comments

Comments
 (0)