|
94 | 94 | import static org.openapitools.codegen.CodegenConstants.*; |
95 | 95 | import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; |
96 | 96 | import static org.openapitools.codegen.utils.DiscriminatorUtils.*; |
97 | | -import static org.openapitools.codegen.utils.EnumUtils.getEnumValues; |
| 97 | +import static org.openapitools.codegen.utils.EnumUtils.*; |
98 | 98 | import static org.openapitools.codegen.utils.OnceLogger.once; |
99 | 99 | import static org.openapitools.codegen.utils.StringUtils.*; |
100 | 100 |
|
@@ -199,6 +199,8 @@ public class DefaultCodegen implements CodegenConfig { |
199 | 199 | protected Map<String, String> enumNameMapping = new HashMap<>(); |
200 | 200 | // a map to store the mapping between operation id name and the name provided by the user |
201 | 201 | protected Map<String, String> operationIdNameMapping = new HashMap<>(); |
| 202 | + // a map to inject vendor extensions into model classes or their properties: key=ModelName.x-extension-name or ModelName.propertyBaseName.x-extension-name, value=extensionValue |
| 203 | + protected Map<String, String> injectModelVendorExtensions = new HashMap<>(); |
202 | 204 | // a map to store the rules in OpenAPI Normalizer |
203 | 205 | protected Map<String, String> openapiNormalizer = new HashMap<>(); |
204 | 206 | @Setter |
@@ -547,6 +549,42 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs) |
547 | 549 | } |
548 | 550 | } |
549 | 551 |
|
| 552 | + // Inject vendor extensions from --inject-property-extensions into matching schema properties |
| 553 | + if (!injectModelVendorExtensions.isEmpty()) { |
| 554 | + for (Map.Entry<String, ModelsMap> entry : objs.entrySet()) { |
| 555 | + CodegenModel model = ModelUtils.getModelByName(entry.getKey(), objs); |
| 556 | + if (model == null) continue; |
| 557 | + |
| 558 | + for (Map.Entry<String, String> extEntry : injectModelVendorExtensions.entrySet()) { |
| 559 | + String[] parts = extEntry.getKey().split("\\.", 3); |
| 560 | + if (parts.length < 2) continue; |
| 561 | + String modelName = parts[0]; |
| 562 | + String extensionValue = extEntry.getValue(); |
| 563 | + |
| 564 | + if (!modelName.equals(entry.getKey())) continue; |
| 565 | + |
| 566 | + if (parts.length == 2) { |
| 567 | + // class-level extension: ModelName.x-extension-name |
| 568 | + model.vendorExtensions.put(parts[1], extensionValue); |
| 569 | + } else { |
| 570 | + // property-level extension: ModelName.propertyBaseName.x-extension-name |
| 571 | + String propertyBaseName = parts[1]; |
| 572 | + String extensionName = parts[2]; |
| 573 | + List<List<CodegenProperty>> allPropertyLists = Arrays.asList( |
| 574 | + model.vars, model.allVars, model.readWriteVars, model.requiredVars, |
| 575 | + model.optionalVars, model.parentVars, model.readOnlyVars, model.nonNullableVars); |
| 576 | + for (List<CodegenProperty> properties : allPropertyLists) { |
| 577 | + for (CodegenProperty property : properties) { |
| 578 | + if (propertyBaseName.equals(property.baseName)) { |
| 579 | + property.vendorExtensions.put(extensionName, extensionValue); |
| 580 | + } |
| 581 | + } |
| 582 | + } |
| 583 | + } |
| 584 | + } |
| 585 | + } |
| 586 | + } |
| 587 | + |
550 | 588 | if (this.useOneOfInterfaces) { |
551 | 589 | // First, add newly created oneOf interfaces |
552 | 590 | for (CodegenModel cm : addOneOfInterfaces) { |
@@ -1366,6 +1404,11 @@ public Map<String, String> operationIdNameMapping() { |
1366 | 1404 | return operationIdNameMapping; |
1367 | 1405 | } |
1368 | 1406 |
|
| 1407 | + @Override |
| 1408 | + public Map<String, String> injectModelVendorExtensions() { |
| 1409 | + return injectModelVendorExtensions; |
| 1410 | + } |
| 1411 | + |
1369 | 1412 | @Override |
1370 | 1413 | public Map<String, String> openapiNormalizer() { |
1371 | 1414 | return openapiNormalizer; |
@@ -6799,31 +6842,59 @@ protected List<Map<String, Object>> buildEnumVars(List<Object> values, String da |
6799 | 6842 | } |
6800 | 6843 |
|
6801 | 6844 | if (enumUnknownDefaultCase) { |
6802 | | - // If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response. |
6803 | | - // With this option enabled, each enum will have a new case, 'unknown_default_open_api', so that when the server sends an enum case that is not known by the client/spec, they can safely fallback to this case. |
6804 | | - Map<String, Object> enumVar = new HashMap<>(); |
6805 | | - String enumName = enumUnknownDefaultCaseName; |
6806 | | - |
6807 | | - String enumValue = isDataTypeString(dataType) |
6808 | | - ? enumUnknownDefaultCaseName |
6809 | | - : // This is a dummy value that attempts to avoid collisions with previously specified cases. |
6810 | | - // Int.max / 192 |
6811 | | - // The number 192 that is used to calculate this random value, is the Swift Evolution proposal for frozen/non-frozen enums. |
6812 | | - // [SE-0192](https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md) |
6813 | | - // Since this functionality was born in the Swift 5 generator and latter on broth to all generators |
6814 | | - // https://github.com/OpenAPITools/openapi-generator/pull/11013 |
6815 | | - String.valueOf(11184809); |
6816 | | - |
6817 | | - enumVar.put(ENUM_NAME, toEnumVarName(enumName, dataType)); |
6818 | | - enumVar.put(ENUM_VALUE, toEnumValue(enumValue, dataType)); |
6819 | | - enumVar.put(ENUM_IS_STRING, isDataTypeString(dataType)); |
6820 | | - // TODO: add isNumeric |
6821 | | - enumVars.add(enumVar); |
| 6845 | + injectEnumUnknownDefaultCase(enumVars, dataType); |
6822 | 6846 | } |
6823 | 6847 |
|
6824 | 6848 | return enumVars; |
6825 | 6849 | } |
6826 | 6850 |
|
| 6851 | + /** |
| 6852 | + * If the server adds new enum cases, that are unknown by an old spec/client, the client will fail to parse the network response. |
| 6853 | + * This adds a default case to the enum, {@link DefaultCodegen#enumUnknownDefaultCaseName}, that can be used as a fallback for unknown values. |
| 6854 | + * |
| 6855 | + * @param enumVars the enumVars |
| 6856 | + * @param dataType the data type of the enum parameter |
| 6857 | + */ |
| 6858 | + private void injectEnumUnknownDefaultCase(List<Map<String, Object>> enumVars, String dataType) { |
| 6859 | + Map<String, Object> enumVar = new HashMap<>(); |
| 6860 | + String enumName = enumUnknownDefaultCaseName; |
| 6861 | + |
| 6862 | + String enumValue = isDataTypeString(dataType) |
| 6863 | + ? enumUnknownDefaultCaseName |
| 6864 | + : // This is a dummy value that attempts to avoid collisions with previously specified cases. |
| 6865 | + // Int.max / 192 |
| 6866 | + // The number 192 that is used to calculate this random value, is the Swift Evolution proposal for frozen/non-frozen enums. |
| 6867 | + // [SE-0192](https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md) |
| 6868 | + // Since this functionality was born in the Swift 5 generator and latter on broth to all generators |
| 6869 | + // https://github.com/OpenAPITools/openapi-generator/pull/11013 |
| 6870 | + String.valueOf(11184809); |
| 6871 | + |
| 6872 | + enumVar.put(ENUM_NAME, toEnumVarName(enumName, dataType)); |
| 6873 | + enumVar.put(ENUM_VALUE, toEnumValue(enumValue, dataType)); |
| 6874 | + enumVar.put(ENUM_IS_STRING, isDataTypeString(dataType)); |
| 6875 | + // TODO: add isNumeric |
| 6876 | + enumVars.add(enumVar); |
| 6877 | + } |
| 6878 | + |
| 6879 | + /** |
| 6880 | + * Removes any injected default enum value that was created with {@link DefaultCodegen#injectEnumUnknownDefaultCase} |
| 6881 | + * from an operation's non-body enum parameters. This can for example be of interest when generating client code |
| 6882 | + * where a fallback is superfluous for a value that is only sent and never received. |
| 6883 | + * |
| 6884 | + * @param operation operation to be processed |
| 6885 | + */ |
| 6886 | + protected void removeEnumUnknownDefaultCase(CodegenOperation operation) { |
| 6887 | + for (CodegenParameter param : operation.allParams) { |
| 6888 | + if (!param.isBodyParam && param.isEnum && hasEnumVars(param.allowableValues)) { |
| 6889 | + List<Map<String, Object>> enumVars = getEnumVars(param.allowableValues); |
| 6890 | + if (enumVars != null) { |
| 6891 | + String unknownName = toEnumVarName(enumUnknownDefaultCaseName, param.dataType); |
| 6892 | + enumVars.removeIf(ev -> unknownName.equals(ev.get(ENUM_NAME))); |
| 6893 | + } |
| 6894 | + } |
| 6895 | + } |
| 6896 | + } |
| 6897 | + |
6827 | 6898 | protected void postProcessEnumVars(List<Map<String, Object>> enumVars) { |
6828 | 6899 | Collections.reverse(enumVars); |
6829 | 6900 | enumVars.forEach(v -> { |
|
0 commit comments