Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
propSchemaOrArray == null ?
null :
propSchemaOrArray instanceof io.swagger.v3.oas.annotations.media.ArraySchema ?
((io.swagger.v3.oas.annotations.media.ArraySchema) propSchemaOrArray).schema() :
((io.swagger.v3.oas.annotations.media.ArraySchema) propSchemaOrArray).arraySchema() :
(io.swagger.v3.oas.annotations.media.Schema) propSchemaOrArray;

io.swagger.v3.oas.annotations.media.Schema.AccessMode accessMode = resolveAccessMode(propDef, type, propResolvedSchemaAnnotation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.swagger.v3.core.jackson.ModelResolver;
import io.swagger.v3.core.model.ApiDescription;
import io.swagger.v3.core.util.Configuration;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.core.util.PrimitiveType;
import io.swagger.v3.jaxrs2.matchers.SerializationMatchers;
import io.swagger.v3.jaxrs2.petstore31.PetResource;
Expand Down Expand Up @@ -83,6 +84,7 @@
import io.swagger.v3.jaxrs2.resources.Ticket3731BisResource;
import io.swagger.v3.jaxrs2.resources.Ticket3731Resource;
import io.swagger.v3.jaxrs2.resources.Ticket4065Resource;
import io.swagger.v3.jaxrs2.resources.Ticket4341Resource;
import io.swagger.v3.jaxrs2.resources.Ticket4412Resource;
import io.swagger.v3.jaxrs2.resources.Ticket4446Resource;
import io.swagger.v3.jaxrs2.resources.Ticket4483Resource;
Expand Down Expand Up @@ -795,6 +797,32 @@ public void test2497() {
assertEquals(openAPI.getComponents().getSchemas().get("User").getRequired().get(0), "issue3438");
}

@Test(description = "array required property resolved from ArraySchema.arraySchema.requiredMode")
public void test4341() {
Reader reader = new Reader(new OpenAPI());
OpenAPI openAPI = reader.read(Ticket4341Resource.class);
Schema userSchema = openAPI.getComponents().getSchemas().get("User");
List<String> required = userSchema.getRequired();

assertTrue(required.contains("requiredArray"));
assertFalse(required.contains("notRequiredArray"));
assertFalse(required.contains("notRequiredArrayWithNotNull"));
assertTrue(required.contains("autoRequiredWithNotNull"));
assertFalse(required.contains("autoNotRequired"));

assertTrue(
required.contains("requiredArrayArraySchemaOnly"),
"arraySchema.requiredMode=REQUIRED should make the array property required " +
"even when items schema is not explicitly provided"
);

assertFalse(
required.contains("requiredItemsOnlyArray"),
"schema(requiredMode=REQUIRED) on items must not make the array property required; " +
"requiredness is controlled by arraySchema.requiredMode"
);
}

@Test(description = "test resource with subresources")
public void testResourceWithSubresources() {
Reader reader = new Reader(new OpenAPI());
Expand Down Expand Up @@ -5503,4 +5531,81 @@ public void testTicket4907() {
SerializationMatchers.assertEqualsToYaml31(openAPI, yaml);
ModelConverters.reset();
}

@Test(description = "array property metadata is resolved from ArraySchema.arraySchema, items metadata from ArraySchema.schema")
public void test4341ArraySchemaOtherAttributes() {
Reader reader = new Reader(new OpenAPI());
OpenAPI openAPI = reader.read(Ticket4341Resource.class);
System.out.println(Json.pretty(openAPI));

Schema userSchema = openAPI.getComponents().getSchemas().get("User");
assertNotNull(userSchema, "User schema should be present");

@SuppressWarnings("unchecked")
Map<String, Schema> properties = userSchema.getProperties();
assertNotNull(properties, "User properties should not be null");

Schema metadataArray = properties.get("metadataArray");
assertNotNull(metadataArray, "metadataArray property should be present");
assertTrue(metadataArray instanceof ArraySchema, "metadataArray should be an ArraySchema");

// Property-level assertions
assertEquals(
metadataArray.getDescription(),
"array-level description",
"Array property description should come from arraySchema, not items schema"
);

assertEquals(
metadataArray.getDeprecated(),
Boolean.TRUE,
"Array property deprecated should come from arraySchema"
);

assertEquals(
metadataArray.getReadOnly(),
Boolean.TRUE,
"Array property readOnly should be true from arraySchema.accessMode=READ_ONLY"
);
assertNotEquals(
metadataArray.getWriteOnly(),
Boolean.TRUE,
"Array property writeOnly should not be true when accessMode=READ_ONLY"
);

// Item-level assertions

ArraySchema metadataArraySchema = (ArraySchema) metadataArray;
Schema items = metadataArraySchema.getItems();
assertNotNull(items, "Items schema should not be null");

assertEquals(
items.getDescription(),
"item-level description",
"Items description should come from schema element of @ArraySchema"
);

assertNotEquals(
items.getDeprecated(),
Boolean.TRUE,
"Items deprecated should not be true when schema.deprecated=false"
);

assertEquals(
items.getWriteOnly(),
Boolean.TRUE,
"Items writeOnly should be true from schema.accessMode=WRITE_ONLY"
);
assertNotEquals(
items.getReadOnly(),
Boolean.TRUE,
"Items readOnly should not be true when accessMode=WRITE_ONLY"
);

assertEquals(
items.getFormat(),
"email",
"Items format should come from schema.format"
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.swagger.v3.jaxrs2.resources;

import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.NotNull;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.util.List;

public class Ticket4341Resource {

@GET
@Path("/user")
public User getUsers() {
return null;
}

static class User {
@ArraySchema(
arraySchema = @Schema(requiredMode = Schema.RequiredMode.REQUIRED),
schema = @Schema(type = "string")
)
public List<String> requiredArray;

@ArraySchema(
arraySchema = @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED),
schema = @Schema(type = "string")
)
public List<String> notRequiredArray;

@ArraySchema(
arraySchema = @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED),
schema = @Schema(type = "string")
)
@NotNull
public List<String> notRequiredArrayWithNotNull;

@ArraySchema(
arraySchema = @Schema(requiredMode = Schema.RequiredMode.AUTO),
schema = @Schema(type = "string")
)
@NotNull
public List<String> autoRequiredWithNotNull;

@ArraySchema(
arraySchema = @Schema(requiredMode = Schema.RequiredMode.AUTO),
schema = @Schema(type = "string")
)
public List<String> autoNotRequired;

@ArraySchema(
arraySchema = @Schema(requiredMode = Schema.RequiredMode.REQUIRED)
)
public List<String> requiredArrayArraySchemaOnly;

@ArraySchema(
schema = @Schema(type = "string", requiredMode = Schema.RequiredMode.REQUIRED)
)
public List<String> requiredItemsOnlyArray;

@ArraySchema(
arraySchema = @Schema(
description = "array-level description",
deprecated = true,
accessMode = Schema.AccessMode.READ_ONLY
),
schema = @Schema(
description = "item-level description",
deprecated = false,
accessMode = Schema.AccessMode.WRITE_ONLY,
format = "email"
)
)
public List<String> metadataArray;
}
}
Loading