Define codegen vendor extensions in CodegenConstants (#22054)

* Add an enum to centralize common internal vendor extensions used for Codegen processing

* Extend the normalizer tests to illustrate that an AllOfs with several refs have all of them marked as parents

* Add x-internal to the Codegen vendor extensions

* Move the Codegen vendor extensions into CodegenConstants

* Add assertion to JavaClient CodegenTest
This commit is contained in:
Mattias Sehlstedt 2025-10-01 19:44:11 +02:00 committed by GitHub
parent ddb15d4b9d
commit e8a688a724
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 103 additions and 58 deletions

View File

@ -456,4 +456,7 @@ public class CodegenConstants {
public static final String USE_DEFAULT_VALUES_FOR_REQUIRED_VARS = "useDefaultValuesForRequiredVars";
public static final String DEFAULT_TO_EMPTY_CONTAINER = "defaultToEmptyContainer";
public static final String X_INTERNAL = "x-internal";
public static final String X_PARENT = "x-parent";
}

View File

@ -88,8 +88,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.openapitools.codegen.CodegenConstants.DEFAULT_TO_EMPTY_CONTAINER;
import static org.openapitools.codegen.CodegenConstants.UNSUPPORTED_V310_SPEC_MSG;
import static org.openapitools.codegen.CodegenConstants.*;
import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER;
import static org.openapitools.codegen.utils.OnceLogger.once;
import static org.openapitools.codegen.utils.StringUtils.*;
@ -5197,7 +5196,7 @@ public class DefaultCodegen implements CodegenConfig {
String method = p.getKey();
Operation op = p.getValue();
if (op.getExtensions() != null && Boolean.TRUE.equals(op.getExtensions().get("x-internal"))) {
if (op.getExtensions() != null && Boolean.TRUE.equals(op.getExtensions().get(X_INTERNAL))) {
// skip operation if x-internal sets to true
LOGGER.info("Operation ({} {} - {}) not generated since x-internal is set to true",
method, expression, op.getOperationId());

View File

@ -61,6 +61,7 @@ import java.util.function.Supplier;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.removeStart;
import static org.openapitools.codegen.CodegenConstants.X_INTERNAL;
import static org.openapitools.codegen.utils.OnceLogger.once;
@SuppressWarnings("rawtypes")
@ -486,7 +487,7 @@ public class DefaultGenerator implements Generator {
Schema schema = ModelUtils.getSchemas(this.openAPI).get(name);
if (schema.getExtensions() != null && Boolean.TRUE.equals(schema.getExtensions().get("x-internal"))) {
if (schema.getExtensions() != null && Boolean.TRUE.equals(schema.getExtensions().get(X_INTERNAL))) {
LOGGER.info("Model {} not generated since x-internal is set to true", name);
continue;
} else if (ModelUtils.isFreeFormObject(schema, openAPI)) { // check to see if it's a free-form object
@ -1564,7 +1565,7 @@ public class DefaultGenerator implements Generator {
final List<SecurityRequirement> globalSecurities = openAPI.getSecurity();
for (Tag tag : tags) {
try {
if (operation.getExtensions() != null && Boolean.TRUE.equals(operation.getExtensions().get("x-internal"))) {
if (operation.getExtensions() != null && Boolean.TRUE.equals(operation.getExtensions().get(X_INTERNAL))) {
// skip operation if x-internal sets to true
LOGGER.info("Operation ({} {} - {}) not generated since x-internal is set to true",
httpMethod, resourcePath, operation.getOperationId());

View File

@ -37,6 +37,8 @@ import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.openapitools.codegen.CodegenConstants.X_INTERNAL;
import static org.openapitools.codegen.CodegenConstants.X_PARENT;
import static org.openapitools.codegen.utils.ModelUtils.simplifyOneOfAnyOfWithOnlyOneNonNullSubSchema;
import static org.openapitools.codegen.utils.StringUtils.getUniqueString;
@ -127,7 +129,6 @@ public class OpenAPINormalizer {
// when set to true, remove x-internal: true from models, operations
final String REMOVE_X_INTERNAL = "REMOVE_X_INTERNAL";
final String X_INTERNAL = "x-internal";
boolean removeXInternal;
// when set (e.g. operationId:getPetById|addPet), filter out (or remove) everything else
@ -431,17 +432,17 @@ public class OpenAPINormalizer {
for (Operation operation : operations) {
if (operationIdFilters.size() > 0) {
if (operationIdFilters.contains(operation.getOperationId())) {
operation.addExtension("x-internal", false);
operation.addExtension(X_INTERNAL, false);
} else {
LOGGER.info("operation `{}` marked as internal only (x-internal: true) by the operationId FILTER", operation.getOperationId());
operation.addExtension("x-internal", true);
operation.addExtension(X_INTERNAL, true);
}
} else if (!tagFilters.isEmpty()) {
if (operation.getTags().stream().anyMatch(tagFilters::contains)) {
operation.addExtension("x-internal", false);
operation.addExtension(X_INTERNAL, false);
} else {
LOGGER.info("operation `{}` marked as internal only (x-internal: true) by the tag FILTER", operation.getOperationId());
operation.addExtension("x-internal", true);
operation.addExtension(X_INTERNAL, true);
}
}
@ -1083,10 +1084,10 @@ public class OpenAPINormalizer {
refSchema.setExtensions(new HashMap<>());
}
if (refSchema.getExtensions().containsKey("x-parent")) {
if (refSchema.getExtensions().containsKey(X_PARENT)) {
// doing nothing as x-parent already exists
} else {
refSchema.getExtensions().put("x-parent", true);
refSchema.getExtensions().put(X_PARENT, true);
}
LOGGER.debug("processUseAllOfRefAsParent added `x-parent: true` to {}", refSchema);
@ -1108,7 +1109,7 @@ public class OpenAPINormalizer {
return;
}
if (Boolean.parseBoolean(String.valueOf(operation.getExtensions().get("x-internal")))) {
if (Boolean.parseBoolean(String.valueOf(operation.getExtensions().get(X_INTERNAL)))) {
operation.getExtensions().remove(X_INTERNAL);
}
}

View File

@ -26,8 +26,7 @@ public enum VendorExtension {
X_OPERATION_EXTRA_ANNOTATION("x-operation-extra-annotation", ExtensionLevel.OPERATION, "List of custom annotations to be added to operation", null),
X_VERSION_PARAM("x-version-param", ExtensionLevel.OPERATION_PARAMETER, "Marker property that tells that this parameter would be used for endpoint versioning. Applicable for headers & query params. true/false", null),
X_PATTERN_MESSAGE("x-pattern-message", Arrays.asList(ExtensionLevel.FIELD, ExtensionLevel.OPERATION_PARAMETER), "Add this property whenever you need to customize the invalidation error message for the regex pattern of a variable", null),
X_ZERO_BASED_ENUM("x-zero-based-enum", ExtensionLevel.MODEL, "When used on an enum, the index will not be generated and the default numbering will be used, zero-based", "false"),
;
X_ZERO_BASED_ENUM("x-zero-based-enum", ExtensionLevel.MODEL, "When used on an enum, the index will not be generated and the default numbering will be used, zero-based", "false");
private final String name;
private final List<ExtensionLevel> levels;

View File

@ -56,6 +56,7 @@ import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import static org.openapitools.codegen.CodegenConstants.X_PARENT;
import static org.openapitools.codegen.utils.OnceLogger.once;
public class ModelUtils {
@ -1716,7 +1717,7 @@ public class ModelUtils {
return false;
}
Object xParent = schema.getExtensions().get("x-parent");
Object xParent = schema.getExtensions().get(X_PARENT);
if (xParent == null) {
return false;
} else if (xParent instanceof Boolean) {

View File

@ -30,30 +30,48 @@ import java.util.*;
import static org.testng.Assert.*;
public class OpenAPINormalizerTest {
private static final String REF_AS_PARENT_IN_ALLOF = "REF_AS_PARENT_IN_ALLOF";
private static final String X_PARENT = "x-parent";
private static final String X_INTERNAL = "x-internal";
@Test
public void testOpenAPINormalizerRefAsParentInAllOf() {
// to test the rule REF_AS_PARENT_IN_ALLOF
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/allOf_extension_parent.yaml");
Schema schema = openAPI.getComponents().getSchemas().get("AnotherPerson");
assertNull(schema.getExtensions());
Schema<?> anotherPerson = openAPI.getComponents().getSchemas().get("AnotherPerson");
assertNull(anotherPerson.getExtensions());
Schema schema2 = openAPI.getComponents().getSchemas().get("Person");
assertEquals(schema2.getExtensions().get("x-parent"), "abstract");
Schema<?>person = openAPI.getComponents().getSchemas().get("Person");
assertEquals(person.getExtensions().get(X_PARENT), "abstract");
Schema<?> preNormPersonA = openAPI.getComponents().getSchemas().get("PersonA");
assertNull(preNormPersonA.getExtensions());
Schema<?> preNormPersonB = openAPI.getComponents().getSchemas().get("PersonB");
assertNull(preNormPersonB.getExtensions());
Map<String, String> options = new HashMap<>();
options.put("REF_AS_PARENT_IN_ALLOF", "true");
options.put(REF_AS_PARENT_IN_ALLOF, "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
Schema schema3 = openAPI.getComponents().getSchemas().get("AnotherPerson");
assertEquals(schema3.getExtensions().get("x-parent"), true);
Schema<?>schema3 = openAPI.getComponents().getSchemas().get("AnotherPerson");
assertEquals(schema3.getExtensions().get(X_PARENT), true);
Schema schema4 = openAPI.getComponents().getSchemas().get("AnotherParent");
assertEquals(schema4.getExtensions().get("x-parent"), true);
Schema<?>schema4 = openAPI.getComponents().getSchemas().get("AnotherParent");
assertEquals(schema4.getExtensions().get(X_PARENT), true);
Schema schema5 = openAPI.getComponents().getSchemas().get("Person");
assertEquals(schema5.getExtensions().get("x-parent"), "abstract");
Schema<?>schema5 = openAPI.getComponents().getSchemas().get("Person");
assertEquals(schema5.getExtensions().get(X_PARENT), "abstract");
// Verify that all allOf refs gets marked as parents
Schema<?>schemaWithTwoParents = openAPI.getComponents().getSchemas().get("SchemaWithTwoParents");
assertNull(schemaWithTwoParents.getExtensions());
Schema<?>personA = openAPI.getComponents().getSchemas().get("PersonA");
assertEquals(personA.getExtensions().get(X_PARENT), true);
Schema<?>personB = openAPI.getComponents().getSchemas().get("PersonB");
assertEquals(personB.getExtensions().get(X_PARENT), true);
}
@Test
@ -68,13 +86,13 @@ public class OpenAPINormalizerTest {
assertNull(schema2.getExtensions());
Map<String, String> options = new HashMap<>();
options.put("REF_AS_PARENT_IN_ALLOF", "true");
options.put(REF_AS_PARENT_IN_ALLOF, "true");
options.put("REFACTOR_ALLOF_WITH_PROPERTIES_ONLY", "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
Schema schema3 = openAPI.getComponents().getSchemas().get("Ancestor");
assertEquals(schema3.getExtensions().get("x-parent"), true);
assertEquals(schema3.getExtensions().get(X_PARENT), true);
Schema schema4 = openAPI.getComponents().getSchemas().get("Child");
assertNull(schema4.getExtensions());
@ -585,8 +603,8 @@ public class OpenAPINormalizerTest {
Schema s = openAPI.getComponents().getSchemas().get("Dummy");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(s.getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(s.getExtensions().get(X_INTERNAL), true);
Map<String, String> options = new HashMap<>();
options.put("REMOVE_X_INTERNAL", "true");
@ -595,8 +613,8 @@ public class OpenAPINormalizerTest {
Schema s2 = openAPI.getComponents().getSchemas().get("Dummy");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), null);
assertEquals(s2.getExtensions().get("x-internal"), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), null);
assertEquals(s2.getExtensions().get(X_INTERNAL), null);
}
@Test
@ -604,7 +622,7 @@ public class OpenAPINormalizerTest {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = new HashMap<>();
@ -612,9 +630,9 @@ public class OpenAPINormalizerTest {
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get("x-internal"), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
@Test
@ -622,7 +640,7 @@ public class OpenAPINormalizerTest {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = new HashMap<>();
@ -630,9 +648,9 @@ public class OpenAPINormalizerTest {
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get("x-internal"), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
@Test
@ -640,7 +658,7 @@ public class OpenAPINormalizerTest {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = new HashMap<>();
@ -648,16 +666,16 @@ public class OpenAPINormalizerTest {
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get("x-internal"), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
@Test
public void testFilterWithMethodWithTrim() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = new HashMap<>();
@ -665,9 +683,9 @@ public class OpenAPINormalizerTest {
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get("x-internal"), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
@Test
@ -675,7 +693,7 @@ public class OpenAPINormalizerTest {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = new HashMap<>();
@ -683,16 +701,16 @@ public class OpenAPINormalizerTest {
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get("x-internal"), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
@Test
public void testFilterWithTagWithTrim() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/enableKeepOnlyFirstTagInOperation_test.yaml");
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions(), null);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions(), null);
Map<String, String> options = new HashMap<>();
@ -700,9 +718,9 @@ public class OpenAPINormalizerTest {
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get("x-internal"), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get("x-internal"), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getGet().getExtensions().get(X_INTERNAL), false);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getDelete().getExtensions().get(X_INTERNAL), true);
assertEquals(openAPI.getPaths().get("/person/display/{personId}").getPut().getExtensions().get(X_INTERNAL), true);
}
@Test

View File

@ -1791,11 +1791,13 @@ public class JavaClientCodegenTest {
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
validateJavaSourceFiles(files);
assertThat(files).hasSize(33);
assertThat(files).hasSize(42);
assertThat(output.resolve("src/main/java/xyz/abcdef/model/Child.java"))
.content().contains("public class Child extends Person {");
assertThat(output.resolve("src/main/java/xyz/abcdef/model/Adult.java"))
.content().contains("public class Adult extends Person {");
assertThat(output.resolve("src/main/java/xyz/abcdef/model/SchemaWithTwoParents.java"))
.content().contains("public class SchemaWithTwoParents {");
assertThat(output.resolve("src/main/java/xyz/abcdef/model/AnotherChild.java"))
.content().contains("public class AnotherChild {");
}

View File

@ -37,6 +37,17 @@ components:
type: string
firstName:
type: string
PersonA:
type: object
properties:
lastName:
type: string
PersonB:
description:
type: object
properties:
firstName:
type: string
Adult:
description: A representation of an adult
allOf:
@ -65,6 +76,16 @@ components:
type: integer
format: int32
- $ref: '#/components/schemas/AnotherPerson'
SchemaWithTwoParents:
description: A schema that has two allOfs with refs
allOf:
- type: object
properties:
age:
type: integer
format: int32
- $ref: '#/components/schemas/PersonA'
- $ref: '#/components/schemas/PersonB'
AnotherPerson:
description: person object without x-parent extension
type: object