Ticket4904Test.java
package io.swagger.v3.core.resolving;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.core.converter.ModelConverterContextImpl;
import io.swagger.v3.core.jackson.ModelResolver;
import io.swagger.v3.oas.annotations.media.DiscriminatorMapping;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.models.media.ComposedSchema;
import io.swagger.v3.oas.models.media.JsonSchema;
import org.testng.annotations.Test;
import static io.swagger.v3.core.resolving.SwaggerTestBase.mapper;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
public class Ticket4904Test {
@Test
public void testComposedSchemaWithDiscriminator() {
final ModelResolver modelResolver = new ModelResolver(mapper());
modelResolver.setOpenapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema schema = context.resolve(new AnnotatedType(ParentClass.class));
assertNotNull(schema);
assertTrue(schema instanceof JsonSchema, "Expected JsonSchema in OpenAPI 3.1 mode, but got: " + schema.getClass());
JsonSchema jsonSchema = (JsonSchema) schema;
assertNotNull(jsonSchema.getOneOf());
assertEquals(jsonSchema.getOneOf().size(), 2);
assertEquals(( jsonSchema.getOneOf().get(0)).get$ref(), "#/components/schemas/ChildClassA");
assertEquals(( jsonSchema.getOneOf().get(1)).get$ref(), "#/components/schemas/ChildClassB");
assertNotNull(jsonSchema.getDiscriminator());
assertEquals(jsonSchema.getDiscriminator().getPropertyName(), "objectType");
assertNotNull(jsonSchema.getDiscriminator().getMapping());
assertEquals(jsonSchema.getDiscriminator().getMapping().size(), 2);
assertEquals(jsonSchema.getDiscriminator().getMapping().get("A"), "#/components/schemas/ChildClassA");
assertEquals(jsonSchema.getDiscriminator().getMapping().get("B"), "#/components/schemas/ChildClassB");
}
@Test
public void testMultiElementAllOf() {
final ModelResolver modelResolver = new ModelResolver(mapper());
modelResolver.setOpenapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema schema = context.resolve(new AnnotatedType(MultiAllOfClass.class));
assertNotNull(schema);
assertTrue(schema instanceof JsonSchema, "Expected JsonSchema in OpenAPI 3.1 mode, but got: " + schema.getClass());
assertNotNull(schema.getAllOf());
assertEquals(schema.getAllOf().size(), 3);
assertEquals(((io.swagger.v3.oas.models.media.Schema) schema.getAllOf().get(0)).get$ref(), "#/components/schemas/ClassA");
assertEquals(((io.swagger.v3.oas.models.media.Schema) schema.getAllOf().get(1)).get$ref(), "#/components/schemas/ClassB");
assertEquals(((io.swagger.v3.oas.models.media.Schema) schema.getAllOf().get(2)).get$ref(), "#/components/schemas/ClassC");
}
@Test
public void testMultiElementAllOfOpenApi30() {
final ModelResolver modelResolver = new ModelResolver(mapper());
modelResolver.setOpenapi31(false);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema schema = context.resolve(new AnnotatedType(MultiAllOfClass.class));
assertNotNull(schema);
assertTrue(schema instanceof ComposedSchema, "Expected ComposedSchema in OpenAPI 3.0 mode, but got: " + schema.getClass());
ComposedSchema composedSchema = (ComposedSchema) schema;
assertNotNull(composedSchema.getAllOf());
assertEquals(composedSchema.getAllOf().size(), 3);
assertEquals(composedSchema.getAllOf().get(0).get$ref(), "#/components/schemas/ClassA");
assertEquals(composedSchema.getAllOf().get(1).get$ref(), "#/components/schemas/ClassB");
assertEquals(composedSchema.getAllOf().get(2).get$ref(), "#/components/schemas/ClassC");
}
@Test
public void testMixedComposition() {
final ModelResolver modelResolver = new ModelResolver(mapper());
modelResolver.setOpenapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema schema = context.resolve(new AnnotatedType(MixedCompositionClass.class));
assertNotNull(schema);
assertTrue(schema instanceof JsonSchema, "Expected JsonSchema in OpenAPI 3.1 mode, but got: " + schema.getClass());
JsonSchema jsonSchema = (JsonSchema) schema;
assertNotNull(jsonSchema.getAllOf());
assertEquals(jsonSchema.getAllOf().size(), 3);
assertEquals(jsonSchema.getAllOf().get(0).get$ref(), "#/components/schemas/ClassA");
assertEquals(jsonSchema.getAllOf().get(1).get$ref(), "#/components/schemas/ClassB");
io.swagger.v3.oas.models.media.Schema inlineSchema = jsonSchema.getAllOf().get(2);
assertNotNull(inlineSchema);
assertEquals(inlineSchema.get$ref(), null);
assertNotNull(inlineSchema.getProperties());
assertTrue(inlineSchema.getProperties().containsKey("additionalProperty"));
io.swagger.v3.oas.models.media.Schema additionalPropertySchema =
(io.swagger.v3.oas.models.media.Schema) inlineSchema.getProperties().get("additionalProperty");
assertNotNull(additionalPropertySchema);
assertEquals(additionalPropertySchema.getDescription(), "Additional property");
}
@Test
public void testAnyOfComposition() {
final ModelResolver modelResolver = new ModelResolver(mapper());
modelResolver.setOpenapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema schema = context.resolve(new AnnotatedType(AnyOfClass.class));
assertNotNull(schema);
assertTrue(schema instanceof JsonSchema, "Expected JsonSchema in OpenAPI 3.1 mode, but got: " + schema.getClass());
JsonSchema jsonSchema = (JsonSchema) schema;
assertNotNull(jsonSchema.getAnyOf());
assertEquals(jsonSchema.getAnyOf().size(), 3);
assertEquals(((io.swagger.v3.oas.models.media.Schema) jsonSchema.getAnyOf().get(0)).get$ref(), "#/components/schemas/ClassA");
assertEquals(((io.swagger.v3.oas.models.media.Schema) jsonSchema.getAnyOf().get(1)).get$ref(), "#/components/schemas/ClassB");
assertEquals(((io.swagger.v3.oas.models.media.Schema) jsonSchema.getAnyOf().get(2)).get$ref(), "#/components/schemas/ClassC");
}
@Test
public void testOneOfWithReferences() {
final ModelResolver modelResolver = new ModelResolver(mapper());
modelResolver.setOpenapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema schema = context.resolve(new AnnotatedType(OneOfWithRefsClass.class));
assertNotNull(schema);
assertTrue(schema instanceof JsonSchema, "Expected JsonSchema in OpenAPI 3.1 mode, but got: " + schema.getClass());
JsonSchema jsonSchema = (JsonSchema) schema;
assertNotNull(jsonSchema.getOneOf());
assertEquals(jsonSchema.getOneOf().size(), 2);
assertEquals((jsonSchema.getOneOf().get(0)).get$ref(), "#/components/schemas/RefSubtypeA");
assertEquals((jsonSchema.getOneOf().get(1)).get$ref(), "#/components/schemas/RefSubtypeB");
}
@Test
public void testJacksonPolymorphismWithTypeInfo() {
final ModelResolver modelResolver = new ModelResolver(mapper());
modelResolver.setOpenapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema schema = context.resolve(new AnnotatedType(JacksonPolymorphicParent.class));
assertNotNull(schema);
assertTrue(schema instanceof JsonSchema, "Expected JsonSchema in OpenAPI 3.1 mode, but got: " + schema.getClass());
JsonSchema jsonSchema = (JsonSchema) schema;
if (jsonSchema.getOneOf() != null) {
assertEquals(jsonSchema.getOneOf().size(), 2);
assertEquals((jsonSchema.getOneOf().get(0)).get$ref(), "#/components/schemas/JacksonChildA");
assertEquals((jsonSchema.getOneOf().get(1)).get$ref(), "#/components/schemas/JacksonChildB");
assertNotNull(jsonSchema.getDiscriminator());
assertEquals(jsonSchema.getDiscriminator().getPropertyName(), "type");
} else {
assertNotNull(jsonSchema.getProperties());
assertTrue(jsonSchema.getProperties().containsKey("commonProperty") ||
jsonSchema.getProperties().containsKey("type"),
"Expected to find either commonProperty or type discriminator property");
}
}
@Test
public void testComplexAllOfWithInlineProperties() {
final ModelResolver modelResolver = new ModelResolver(mapper());
modelResolver.setOpenapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema schema = context.resolve(new AnnotatedType(ComplexAllOfClass.class));
assertNotNull(schema);
assertTrue(schema instanceof JsonSchema, "Expected JsonSchema in OpenAPI 3.1 mode, but got: " + schema.getClass());
JsonSchema jsonSchema = (JsonSchema) schema;
assertNotNull(jsonSchema.getAllOf());
assertEquals(jsonSchema.getAllOf().size(), 3);
assertEquals((jsonSchema.getAllOf().get(0)).get$ref(), "#/components/schemas/ClassA");
assertEquals((jsonSchema.getAllOf().get(1)).get$ref(), "#/components/schemas/ClassB");
io.swagger.v3.oas.models.media.Schema inlineSchema = jsonSchema.getAllOf().get(2);
assertNotNull(inlineSchema);
assertEquals(inlineSchema.get$ref(), null);
assertNotNull(inlineSchema.getProperties());
assertTrue(inlineSchema.getProperties().containsKey("complexProperty"));
assertTrue(inlineSchema.getProperties().containsKey("additionalField"));
}
@Test
public void testNestedComposition() {
final ModelResolver modelResolver = new ModelResolver(mapper());
modelResolver.setOpenapi31(true);
final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
io.swagger.v3.oas.models.media.Schema schema = context.resolve(new AnnotatedType(NestedCompositionClass.class));
assertNotNull(schema);
assertTrue(schema instanceof JsonSchema, "Expected JsonSchema in OpenAPI 3.1 mode, but got: " + schema.getClass());
JsonSchema jsonSchema = (JsonSchema) schema;
assertNotNull(jsonSchema.getOneOf());
assertNotNull(jsonSchema.getAllOf());
assertEquals(jsonSchema.getOneOf().size(), 2);
assertEquals(jsonSchema.getAllOf().size(), 1);
assertEquals((jsonSchema.getOneOf().get(0)).get$ref(), "#/components/schemas/ChildClassA");
assertEquals((jsonSchema.getOneOf().get(1)).get$ref(), "#/components/schemas/ChildClassB");
assertEquals((jsonSchema.getAllOf().get(0)).get$ref(), "#/components/schemas/ClassA");
}
@Schema(
type = "object",
discriminatorMapping = {
@DiscriminatorMapping(value = "A", schema = ChildClassA.class),
@DiscriminatorMapping(value = "B", schema = ChildClassB.class)
},
oneOf = {ChildClassA.class, ChildClassB.class},
discriminatorProperty = "objectType"
)
public abstract static class ParentClass {
}
public static class ChildClassA extends ParentClass {
}
public static class ChildClassB extends ParentClass {
}
@Schema(allOf = {ClassA.class, ClassB.class, ClassC.class})
public static class MultiAllOfClass {
}
@Schema(
allOf = {ClassA.class, ClassB.class},
type = "object",
description = "Mixed composition with allOf and additional properties",
format = "custom-format"
)
public static class MixedCompositionClass {
@Schema(description = "Additional property")
public String additionalProperty;
}
public static class ClassA {
public String propertyA;
}
public static class ClassB {
public String propertyB;
}
public static class ClassC {
public String propertyC;
}
@Schema(anyOf = {ClassA.class, ClassB.class, ClassC.class})
public static class AnyOfClass {
}
@Schema(oneOf = {RefSubtypeA.class, RefSubtypeB.class})
public static class OneOfWithRefsClass {
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = JacksonChildA.class, name = "A"),
@JsonSubTypes.Type(value = JacksonChildB.class, name = "B")
})
public static class JacksonPolymorphicParent {
public String commonProperty;
}
public static class JacksonChildA extends JacksonPolymorphicParent {
public String childAProperty;
}
public static class JacksonChildB extends JacksonPolymorphicParent {
public String childBProperty;
}
@Schema(allOf = {ClassA.class, ClassB.class})
public static class ComplexAllOfClass {
@Schema(description = "Complex property with nested structure")
public String complexProperty;
@Schema(description = "Additional field for testing")
public String additionalField;
}
@Schema(
oneOf = {ChildClassA.class, ChildClassB.class},
allOf = {ClassA.class}
)
public static class NestedCompositionClass {
}
// Additional classes for $ref subtypes testing
public static class RefSubtypeA {
public String refPropertyA;
}
public static class RefSubtypeB {
public String refPropertyB;
}
}