|
10 | 10 | import org.slf4j.helpers.MessageFormatter; |
11 | 11 |
|
12 | 12 | import java.util.*; |
| 13 | +import java.util.stream.Collectors; |
13 | 14 |
|
14 | 15 | import static org.openapitools.codegen.CodegenConstants.X_DISCRIMINATOR_VALUE; |
15 | 16 | import static org.openapitools.codegen.utils.OnceLogger.once; |
@@ -322,6 +323,132 @@ private static CodegenProperty getDiscriminatorCodegenProperty(OpenAPI openAPI, |
322 | 323 | return null; |
323 | 324 | } |
324 | 325 |
|
| 326 | + /** |
| 327 | + * Get the best matching simple types for all the mapped schemas |
| 328 | + * @param openAPI The openAPI specification |
| 329 | + * @param schema The Schema that may contain the discriminator |
| 330 | + * @param discPropName The String that is the discriminator propertyName in the schema |
| 331 | + * @return the distinct list of property Schema with the requested discPropName |
| 332 | + */ |
| 333 | + public static List<Schema> getDistinctTypes(OpenAPI openAPI, Schema schema, String discPropName) { |
| 334 | + List<Schema> mappedSchemas = getMappedSchemas(openAPI, schema); |
| 335 | + List<Schema> properties = new ArrayList<>(); |
| 336 | + for (Schema s: mappedSchemas) { |
| 337 | + Schema prop = findProperty(openAPI, s, discPropName, new HashSet<>()); |
| 338 | + if (prop != null && properties.stream().noneMatch(p -> |
| 339 | + Objects.equals(p.getType(), prop.getType()) && |
| 340 | + Objects.equals(p.get$ref(), prop.get$ref()) && |
| 341 | + Objects.equals(p.getEnum(), prop.getEnum()) && |
| 342 | + Objects.equals(p.getFormat(), prop.getFormat()))) { |
| 343 | + properties.add(prop); |
| 344 | + } |
| 345 | + } |
| 346 | + return properties; |
| 347 | + } |
| 348 | + |
| 349 | + /** |
| 350 | + * return the list of dereferenced mapping schemas. |
| 351 | + * @return the schemas found or empty list if not found. |
| 352 | + */ |
| 353 | + public static List<Schema> getMappedSchemas(OpenAPI openAPI, Schema schema) { |
| 354 | + if (schema.getDiscriminator() != null) { |
| 355 | + if (schema.getDiscriminator().getMapping() != null) { |
| 356 | + return schema.getDiscriminator().getMapping().values().stream() |
| 357 | + .map(ref -> getReferencedSchema(openAPI, ref)) |
| 358 | + .filter(Objects::nonNull) |
| 359 | + .collect(Collectors.toList()); |
| 360 | + } |
| 361 | + if (schema.getOneOf() != null && !schema.getOneOf().isEmpty()) { |
| 362 | + // try also oneOf without discriminator mapping |
| 363 | + List<Schema> oneOfs = (List<Schema>) schema.getOneOf(); |
| 364 | + return oneOfs.stream() |
| 365 | + .filter(Objects::nonNull) |
| 366 | + .map(oneOf -> oneOf.get$ref()!=null |
| 367 | + ? getReferencedSchema(openAPI, oneOf.get$ref()) |
| 368 | + : oneOf) |
| 369 | + .filter(Objects::nonNull) |
| 370 | + .collect(Collectors.toList()); |
| 371 | + } |
| 372 | + } |
| 373 | + return Collections.emptyList(); |
| 374 | + } |
| 375 | + |
| 376 | + private static Schema getReferencedSchema(OpenAPI openAPI, String ref) { |
| 377 | + if (ref == null) { |
| 378 | + return null; |
| 379 | + } |
| 380 | + if (ref.indexOf('/') >= 0) { |
| 381 | + ref = ModelUtils.getSimpleRef(ref); |
| 382 | + } |
| 383 | + return ModelUtils.getSchema(openAPI, ref); |
| 384 | + } |
| 385 | + |
| 386 | + /** |
| 387 | + * Recursively try to find the schema matching the propertyName. |
| 388 | + * |
| 389 | + * @return the schema found or null if not found |
| 390 | + */ |
| 391 | + public static Schema findProperty(OpenAPI openAPI, Schema schema, String propertyName, Set<Schema> visitedSchemas) { |
| 392 | + schema = ModelUtils.getReferencedSchema(openAPI, schema); |
| 393 | + if (propertyName == null || schema == null || visitedSchemas.contains(schema)) { |
| 394 | + return null; |
| 395 | + } |
| 396 | + visitedSchemas.add(schema); |
| 397 | + Map<String, Schema> properties = schema.getProperties(); |
| 398 | + if (properties != null) { |
| 399 | + Schema property = properties.get(propertyName); |
| 400 | + if (property != null) { |
| 401 | + Schema found = simplifyProperty(property, visitedSchemas); |
| 402 | + return found; |
| 403 | + } |
| 404 | + } |
| 405 | + // loop into parent allOfs |
| 406 | + List<Schema> allOfs = schema.getAllOf(); |
| 407 | + if (allOfs != null) { |
| 408 | + for (Schema child : allOfs) { |
| 409 | + Schema found = findProperty(openAPI, child, propertyName, visitedSchemas); |
| 410 | + if (found != null) { |
| 411 | + return simplifyProperty(found, visitedSchemas); |
| 412 | + } |
| 413 | + } |
| 414 | + } |
| 415 | + return null; |
| 416 | + } |
| 417 | + |
| 418 | + /** |
| 419 | + * simplify allOf property represented as [$ref, {description: ...}]. |
| 420 | + */ |
| 421 | + private static Schema simplifyProperty(Schema schema, Set<Schema> visitedSchemas) { |
| 422 | + if (!ModelUtils.isAllOf(schema)) { |
| 423 | + return schema; |
| 424 | + } |
| 425 | + if (visitedSchemas.contains(schema)) { |
| 426 | + return null; |
| 427 | + } |
| 428 | + visitedSchemas.add(schema); |
| 429 | + |
| 430 | + /* |
| 431 | + * handle type+description. For Example: |
| 432 | + * petType: |
| 433 | + * $ref: '#/components/schemas/PetType' |
| 434 | + * description: DOG |
| 435 | + */ |
| 436 | + Schema found = null; |
| 437 | + int count = 0; |
| 438 | + for (Schema sc: (List<Schema>)schema.getAllOf()) { |
| 439 | + if (ModelUtils.getType(sc) != null || ModelUtils.hasRef(sc)) { |
| 440 | + found = sc; |
| 441 | + count++; |
| 442 | + } |
| 443 | + } |
| 444 | + if (count == 1) { |
| 445 | + return found; |
| 446 | + } |
| 447 | + // multiple types, too complex. |
| 448 | + return null; |
| 449 | + |
| 450 | + } |
| 451 | + |
325 | 452 | public static class DiscriminatorData { |
326 | 453 | private final Discriminator discriminator; |
327 | 454 |
|
|
0 commit comments