|
17 | 17 |
|
18 | 18 | package org.openapitools.codegen; |
19 | 19 |
|
| 20 | +import com.fasterxml.jackson.core.type.TypeReference; |
| 21 | +import com.fasterxml.jackson.databind.ObjectMapper; |
20 | 22 | import com.github.benmanes.caffeine.cache.Cache; |
21 | 23 | import com.github.benmanes.caffeine.cache.Caffeine; |
22 | 24 | import com.github.benmanes.caffeine.cache.Ticker; |
|
69 | 71 | import org.openapitools.codegen.utils.ExamplesUtils; |
70 | 72 | import org.openapitools.codegen.utils.ModelUtils; |
71 | 73 | import org.openapitools.codegen.utils.OneOfImplementorAdditionalData; |
| 74 | +import org.openapitools.codegen.validations.oas.ModelVendorExtensionAdd; |
| 75 | +import org.openapitools.codegen.validations.oas.ModelVendorExtensionRemove; |
| 76 | +import org.openapitools.codegen.validations.oas.OperationVendorExtensionAdd; |
| 77 | +import org.openapitools.codegen.validations.oas.OperationVendorExtensionRemove; |
72 | 78 | import org.slf4j.Logger; |
73 | 79 | import org.slf4j.LoggerFactory; |
74 | 80 |
|
@@ -101,6 +107,29 @@ public class DefaultCodegen implements CodegenConfig { |
101 | 107 |
|
102 | 108 | public static FeatureSet DefaultFeatureSet; |
103 | 109 |
|
| 110 | + private final ObjectMapper mapper = new ObjectMapper(); |
| 111 | + |
| 112 | + public static final String MODEL_VENDOR_EXTENSION_REMOVE = "modelVendorExtensionRemove"; |
| 113 | + public static final String MODEL_VENDOR_EXTENSION_ADD = "modelVendorExtensionAdd"; |
| 114 | + public static final String OPERATION_VENDOR_EXTENSION_REMOVE = "operationVendorExtensionRemove"; |
| 115 | + public static final String OPERATION_VENDOR_EXTENSION_ADD = "operationVendorExtensionAdd"; |
| 116 | + |
| 117 | + @Getter |
| 118 | + @Setter |
| 119 | + private Map<String, ModelVendorExtensionRemove> modelVendorExtensionRemove = new HashMap<>(); |
| 120 | + |
| 121 | + @Getter |
| 122 | + @Setter |
| 123 | + private Map<String, ModelVendorExtensionAdd> modelVendorExtensionAdd = new HashMap<>(); |
| 124 | + |
| 125 | + @Getter |
| 126 | + @Setter |
| 127 | + private Map<String, OperationVendorExtensionRemove> operationVendorExtensionRemove = new HashMap<>(); |
| 128 | + |
| 129 | + @Getter |
| 130 | + @Setter |
| 131 | + private Map<String, OperationVendorExtensionAdd> operationVendorExtensionAdd = new HashMap<>(); |
| 132 | + |
104 | 133 | // A cache of sanitized words. The sanitizeName() method is invoked many times with the same |
105 | 134 | // arguments, this cache is used to optimized performance. |
106 | 135 | private static final Cache<SanitizeNameOptions, String> sanitizedNameCache; |
@@ -430,6 +459,28 @@ public void processOpts() { |
430 | 459 | parseDefaultToEmptyContainer((String) additionalProperties.get(DEFAULT_TO_EMPTY_CONTAINER)); |
431 | 460 | defaultToEmptyContainer = true; |
432 | 461 | } |
| 462 | + |
| 463 | + if(additionalProperties.containsKey(MODEL_VENDOR_EXTENSION_REMOVE)) { |
| 464 | + setModelVendorExtensionRemove( |
| 465 | + mapper.convertValue(additionalProperties.get(MODEL_VENDOR_EXTENSION_REMOVE), new TypeReference<Map<String, ModelVendorExtensionRemove>>() {}) |
| 466 | + ); |
| 467 | + } |
| 468 | + if(additionalProperties.containsKey(OPERATION_VENDOR_EXTENSION_REMOVE)) { |
| 469 | + setOperationVendorExtensionRemove( |
| 470 | + mapper.convertValue(additionalProperties.get(OPERATION_VENDOR_EXTENSION_REMOVE), new TypeReference<Map<String, OperationVendorExtensionRemove>>() {}) |
| 471 | + ); |
| 472 | + } |
| 473 | + |
| 474 | + if(additionalProperties.containsKey(MODEL_VENDOR_EXTENSION_ADD)) { |
| 475 | + setModelVendorExtensionAdd( |
| 476 | + mapper.convertValue(additionalProperties.get(MODEL_VENDOR_EXTENSION_ADD), new TypeReference<>() {}) |
| 477 | + ); |
| 478 | + } |
| 479 | + if(additionalProperties.containsKey(OPERATION_VENDOR_EXTENSION_ADD)) { |
| 480 | + setOperationVendorExtensionAdd( |
| 481 | + mapper.convertValue(additionalProperties.get(OPERATION_VENDOR_EXTENSION_ADD), new TypeReference<>() {}) |
| 482 | + ); |
| 483 | + } |
433 | 484 | } |
434 | 485 |
|
435 | 486 | /*** |
@@ -1136,6 +1187,97 @@ public void preprocessOpenAPI(OpenAPI openAPI) { |
1136 | 1187 | @Override |
1137 | 1188 | @SuppressWarnings("unused") |
1138 | 1189 | public void processOpenAPI(OpenAPI openAPI) { |
| 1190 | + LinkedHashMap<String, Operation> operationsByOperationId = openAPI.getPaths().entrySet().stream() |
| 1191 | + .flatMap(path -> path.getValue().readOperations().stream()) |
| 1192 | + .collect(Collectors.toMap(Operation::getOperationId, Function.identity(), (existing, replacement) -> existing, LinkedHashMap::new)); |
| 1193 | + Map<String, Schema> modelsByName = openAPI.getComponents().getSchemas(); |
| 1194 | + |
| 1195 | + // Remove model vendor extensions |
| 1196 | + modelVendorExtensionRemove.forEach((name, ext) -> { |
| 1197 | + if (modelsByName.containsKey(name)) { |
| 1198 | + Schema schema = modelsByName.get(name); |
| 1199 | + if (schema.getExtensions() != null) { |
| 1200 | + ext.getClazz().forEach(schema.getExtensions()::remove); |
| 1201 | + } |
| 1202 | + ext.getFields().forEach((fieldName, fieldExtensionsToRemove) -> { |
| 1203 | + Map<String, Schema> props = schema.getProperties(); |
| 1204 | + if (props != null && props.get(fieldName) != null && props.get(fieldName).getExtensions() != null) { |
| 1205 | + Map fieldExtensions = props.get(fieldName).getExtensions(); |
| 1206 | + fieldExtensionsToRemove.forEach(fieldExtensions::remove); |
| 1207 | + } |
| 1208 | + }); |
| 1209 | + } |
| 1210 | + }); |
| 1211 | + |
| 1212 | + // Add model vendor extensions |
| 1213 | + modelVendorExtensionAdd.forEach((name, ext) -> { |
| 1214 | + if (modelsByName.containsKey(name)) { |
| 1215 | + var schema = modelsByName.get(name); |
| 1216 | + // retrieve the extensions map or initialize |
| 1217 | + Map<String, Object> classExt = Objects.requireNonNullElse((Map<String, Object>) schema.getExtensions(), new HashMap<>()); |
| 1218 | + ext.getClazz().forEach((extName, extVals) -> mergeExtensions(classExt, extName, extVals)); |
| 1219 | + // put the modified map back |
| 1220 | + schema.setExtensions(classExt); |
| 1221 | + var props = schema.getProperties(); |
| 1222 | + if (props != null) { |
| 1223 | + ext.getFields().forEach((fieldName, fieldExts) -> { |
| 1224 | + if (props.containsKey(fieldName)) { |
| 1225 | + Schema fieldSchema = (Schema) props.get(fieldName); |
| 1226 | + // retrieve the extensions map or initialize |
| 1227 | + Map<String, Object> fieldExt = Objects.requireNonNullElse((Map<String, Object>) fieldSchema.getExtensions(), new HashMap<>()); |
| 1228 | + fieldExts.forEach((extName, extVals) -> mergeExtensions(fieldExt, extName, extVals)); |
| 1229 | + // put the modified map back |
| 1230 | + fieldSchema.setExtensions(fieldExt); |
| 1231 | + } |
| 1232 | + }); |
| 1233 | + } |
| 1234 | + } |
| 1235 | + }); |
| 1236 | + |
| 1237 | + // Remove operation vendor extensions |
| 1238 | + operationVendorExtensionRemove.forEach((opId, ext) -> { |
| 1239 | + if (operationsByOperationId.containsKey(opId)) { |
| 1240 | + var op = operationsByOperationId.get(opId); |
| 1241 | + if (op.getExtensions() != null) { |
| 1242 | + ext.getMethod().forEach(op.getExtensions()::remove); |
| 1243 | + } |
| 1244 | + ext.getParams().forEach((paramName, paramExtensionsToRemove) -> { |
| 1245 | + var params = op.getParameters().stream().collect(Collectors.toMap(Parameter::getName, Function.identity())); |
| 1246 | + if (params.containsKey(paramName) && params.get(paramName).getExtensions() != null) { |
| 1247 | + var paramsExtensions = params.get(paramName).getExtensions(); |
| 1248 | + paramExtensionsToRemove.forEach(paramsExtensions::remove); |
| 1249 | + } |
| 1250 | + }); |
| 1251 | + } |
| 1252 | + }); |
| 1253 | + |
| 1254 | + // Add operation vendor extensions |
| 1255 | + operationVendorExtensionAdd.forEach((opId, ext) -> { |
| 1256 | + if (operationsByOperationId.containsKey(opId)) { |
| 1257 | + var op = operationsByOperationId.get(opId); |
| 1258 | + // retrieve the extensions map or initialize |
| 1259 | + Map<String, Object> operationExtensions = Objects.requireNonNullElse(op.getExtensions(), new HashMap<>()); |
| 1260 | + ext.getMethod().forEach((extName, extVals) -> mergeExtensions(operationExtensions, extName, extVals)); |
| 1261 | + // put the modified map back |
| 1262 | + op.setExtensions(operationExtensions); |
| 1263 | + var params = op.getParameters().stream().collect(Collectors.toMap(Parameter::getName, Function.identity())); |
| 1264 | + ext.getParameters().forEach((paramName, paramExts) -> { |
| 1265 | + if (params.containsKey(paramName)) { |
| 1266 | + Parameter parameter = params.get(paramName); |
| 1267 | + // retrieve the extensions map or initialize |
| 1268 | + Map<String, Object> paramExt = Objects.requireNonNullElse(parameter.getExtensions(), new HashMap<>()); |
| 1269 | + paramExts.forEach((extName, extVals) -> mergeExtensions(paramExt, extName, extVals)); |
| 1270 | + // put the modified map back |
| 1271 | + parameter.setExtensions(paramExt); |
| 1272 | + } |
| 1273 | + }); |
| 1274 | + } |
| 1275 | + }); |
| 1276 | + } |
| 1277 | + |
| 1278 | + private void mergeExtensions(Map<String, Object> extensionsMap, String name, List<String> values) { |
| 1279 | + var existing = getObjectAsStringList(extensionsMap.get(name)); |
| 1280 | + extensionsMap.put(name, Stream.concat(existing.stream(), values.stream()).collect(Collectors.toList())); |
1139 | 1281 | } |
1140 | 1282 |
|
1141 | 1283 | // override with any special handling of the JMustache compiler |
|
0 commit comments