Skip to content

Commit 028f3d7

Browse files
committed
update Schema resolution and casting
1 parent d45b70a commit 028f3d7

File tree

14 files changed

+437
-50
lines changed

14 files changed

+437
-50
lines changed

modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
import io.swagger.v3.oas.models.media.IntegerSchema;
6060
import io.swagger.v3.oas.models.media.JsonSchema;
6161
import io.swagger.v3.oas.models.media.MapSchema;
62-
import io.swagger.v3.oas.models.media.NumberSchema;
6362
import io.swagger.v3.oas.models.media.ObjectSchema;
6463
import io.swagger.v3.oas.models.media.Schema;
6564
import io.swagger.v3.oas.models.media.StringSchema;
@@ -153,6 +152,7 @@ public ObjectMapper objectMapper() {
153152

154153
@Override
155154
public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context, Iterator<ModelConverter> next) {
155+
boolean implicitObject = false;
156156
boolean isPrimitive = false;
157157
Schema model = null;
158158
List<String> requiredProps = new ArrayList<>();
@@ -269,7 +269,7 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
269269
resolveArraySchema(annotatedType, schema, resolvedArrayAnnotation);
270270
Schema innerSchema = null;
271271

272-
Schema primitive = PrimitiveType.createProperty(cls);
272+
Schema primitive = PrimitiveType.createProperty(cls, openapi31);
273273
if (primitive != null) {
274274
innerSchema = primitive;
275275
} else {
@@ -310,31 +310,31 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
310310
primitiveType = PrimitiveType.fromName(resolvedSchemaAnnotation.type());
311311
}
312312
if (primitiveType != null) {
313-
Schema primitive = primitiveType.createProperty();
313+
Schema primitive = openapi31 ? primitiveType.createProperty31() : primitiveType.createProperty();
314314
model = primitive;
315315
isPrimitive = true;
316316

317317
}
318318
}
319319

320320
if (model == null && type.isEnumType()) {
321-
model = new StringSchema();
321+
model = openapi31 ? new JsonSchema().typesItem("string") : new StringSchema();
322322
_addEnumProps(type.getRawClass(), model);
323323
isPrimitive = true;
324324
}
325325
if (model == null) {
326326
if (resolvedSchemaAnnotation != null && StringUtils.isEmpty(resolvedSchemaAnnotation.type())) {
327327
PrimitiveType primitiveType = PrimitiveType.fromTypeAndFormat(type, resolvedSchemaAnnotation.format());
328328
if (primitiveType != null) {
329-
model = primitiveType.createProperty();
329+
model = openapi31 ? primitiveType.createProperty31() : primitiveType.createProperty();
330330
isPrimitive = true;
331331
}
332332
}
333333

334334
if (model == null) {
335335
PrimitiveType primitiveType = PrimitiveType.fromType(type);
336336
if (primitiveType != null) {
337-
model = primitiveType.createProperty();
337+
model = openapi31 ? primitiveType.createProperty31() : primitiveType.createProperty();
338338
isPrimitive = true;
339339
}
340340
}
@@ -561,10 +561,16 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
561561
}
562562
} else if (isComposedSchema) {
563563
model = new ComposedSchema().name(name);
564-
if (openapi31 && resolvedArrayAnnotation == null) {
565-
model.addType("object");
564+
if (
565+
(openapi31 && Boolean.TRUE.equals(PrimitiveType.explicitObjectType)) ||
566+
(!openapi31 && (!Boolean.FALSE.equals(PrimitiveType.explicitObjectType)))) {
567+
if (openapi31 && resolvedArrayAnnotation == null) {
568+
model.addType("object");
569+
} else {
570+
model.type("object");
571+
}
566572
} else {
567-
model.type("object");
573+
implicitObject = true;
568574
}
569575
} else {
570576
AnnotatedType aType = ReferenceTypeUtils.unwrapReference(annotatedType);
@@ -573,10 +579,16 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
573579
return model;
574580
} else {
575581
model = new Schema().name(name);
576-
if (openapi31 && resolvedArrayAnnotation == null) {
577-
model.addType("object");
582+
if (
583+
(openapi31 && Boolean.TRUE.equals(PrimitiveType.explicitObjectType)) ||
584+
(!openapi31 && (!Boolean.FALSE.equals(PrimitiveType.explicitObjectType)))) {
585+
if (openapi31 && resolvedArrayAnnotation == null) {
586+
model.addType("object");
587+
} else {
588+
model.type("object");
589+
}
578590
} else {
579-
model.type("object");
591+
implicitObject = true;
580592
}
581593
}
582594
}
@@ -1080,11 +1092,18 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
10801092
// define the model here to support self/cyclic referencing of models
10811093
context.defineModel(name, model, annotatedType, null);
10821094
}
1083-
1095+
// check if it has "object" related keywords
1096+
if (isInferredObjectSchema(model) && model.get$ref() == null) {
1097+
if (openapi31 && model.getTypes() == null) {
1098+
model.addType("object");
1099+
} else if (!openapi31 && model.getType() == null){
1100+
model.type("object");
1101+
}
1102+
}
10841103
Schema.SchemaResolution resolvedSchemaResolution = AnnotationsUtils.resolveSchemaResolution(this.schemaResolution, resolvedSchemaAnnotation);
10851104

10861105
if (model != null && annotatedType.isResolveAsRef() &&
1087-
(isComposedSchema || isObjectSchema(model)) &&
1106+
(isComposedSchema || isObjectSchema(model) || implicitObject) &&
10881107
StringUtils.isNotBlank(model.getName())) {
10891108
if (context.getDefinedModels().containsKey(model.getName())) {
10901109
if (!Schema.SchemaResolution.INLINE.equals(resolvedSchemaResolution)) {
@@ -1290,9 +1309,13 @@ protected void _addEnumProps(Class<?> propClass, Schema property) {
12901309
} else {
12911310
n = _intr().findEnumValue(en);
12921311
}
1293-
if (property instanceof StringSchema) {
1294-
StringSchema sp = (StringSchema) property;
1295-
sp.addEnumItem(n);
1312+
if (isStringSchema(property)) {
1313+
if (openapi31) {
1314+
property.addEnumItemObject(n);
1315+
} else {
1316+
StringSchema sp = (StringSchema) property;
1317+
sp.addEnumItem(n);
1318+
}
12961319
}
12971320
}
12981321
}
@@ -1431,7 +1454,7 @@ protected Schema processAsId(String propertyName, AnnotatedType type,
14311454
final AnnotatedMember propMember = def.getPrimaryMember();
14321455
final JavaType propType = propMember.getType();
14331456
if (PrimitiveType.fromType(propType) != null) {
1434-
return PrimitiveType.createProperty(propType);
1457+
return PrimitiveType.createProperty(propType, openapi31);
14351458
} else {
14361459
List<Annotation> list = new ArrayList<>();
14371460
for (Annotation a : propMember.annotations()) {
@@ -2593,7 +2616,7 @@ protected void resolveDiscriminatorProperty(JavaType type, ModelConverterContext
25932616
modelToUpdate = context.getDefinedModels().get(model.get$ref().substring(SCHEMA_COMPONENT_PREFIX));
25942617
}
25952618
if (modelToUpdate.getProperties() == null || !modelToUpdate.getProperties().keySet().contains(typeInfoProp)) {
2596-
Schema discriminatorSchema = new StringSchema().name(typeInfoProp);
2619+
Schema discriminatorSchema = openapi31 ? new JsonSchema().typesItem("string").name(typeInfoProp) : new StringSchema().name(typeInfoProp);
25972620
modelToUpdate.addProperties(typeInfoProp, discriminatorSchema);
25982621
if (modelToUpdate.getRequired() == null || !modelToUpdate.getRequired().contains(typeInfoProp)) {
25992622
modelToUpdate.addRequiredItem(typeInfoProp);
@@ -3429,7 +3452,20 @@ public void setConfiguration(Configuration configuration) {
34293452
}
34303453

34313454
protected boolean isObjectSchema(Schema schema) {
3432-
return (schema.getTypes() != null && schema.getTypes().contains("object")) || "object".equals(schema.getType()) || (schema.getType() == null && schema.getProperties() != null && !schema.getProperties().isEmpty());
3455+
return (schema.getTypes() != null && schema.getTypes().contains("object")) || "object".equals(schema.getType()) || (schema.getType() == null && ((schema.getProperties() != null && !schema.getProperties().isEmpty()) || (schema.getPatternProperties() != null && !schema.getPatternProperties().isEmpty())));
3456+
}
3457+
3458+
protected boolean isInferredObjectSchema(Schema schema) {
3459+
return ((schema.getProperties() != null && !schema.getProperties().isEmpty())
3460+
|| (schema.getPatternProperties() != null && !schema.getPatternProperties().isEmpty())
3461+
|| (schema.getAdditionalProperties() != null)
3462+
|| (schema.getUnevaluatedProperties() != null)
3463+
|| (schema.getRequired() != null && !schema.getRequired().isEmpty())
3464+
|| (schema.getPropertyNames() != null)
3465+
|| (schema.getDependentRequired() != null && !schema.getDependentRequired().isEmpty())
3466+
|| (schema.getDependentSchemas() != null && !schema.getDependentSchemas().isEmpty())
3467+
|| (schema.getMinProperties() != null && schema.getMinProperties() > 0)
3468+
|| (schema.getMaxProperties() != null && schema.getMaxProperties() > 0));
34333469
}
34343470

34353471
protected boolean isArraySchema(Schema schema) {

modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ public static Optional<Schema> getArraySchema(io.swagger.v3.oas.annotations.medi
506506
arraySchemaObject = new ArraySchema();
507507
} else {
508508
if (existingSchema == null) {
509-
arraySchemaObject = new ArraySchema();
509+
arraySchemaObject = new JsonSchema().typesItem("array");
510510
} else {
511511
arraySchemaObject = existingSchema;
512512
}
@@ -889,7 +889,7 @@ public static Schema resolveSchemaFromType(Class<?> schemaImplementation, Compon
889889
Schema schemaObject;
890890
PrimitiveType primitiveType = PrimitiveType.fromType(schemaImplementation);
891891
if (primitiveType != null) {
892-
schemaObject = primitiveType.createProperty();
892+
schemaObject = openapi31 ? primitiveType.createProperty31() : primitiveType.createProperty();
893893
} else {
894894
schemaObject = new Schema();
895895
ResolvedSchema resolvedSchema = null;
@@ -1583,7 +1583,7 @@ public static Optional<Content> getContent(io.swagger.v3.oas.annotations.media.C
15831583
}
15841584
if (annotationContent.schemaProperties().length > 0) {
15851585
if (mediaType.getSchema() == null) {
1586-
mediaType.schema(new Schema<Object>().type("object"));
1586+
mediaType.schema(openapi31 ? new JsonSchema().typesItem("object") : new Schema<Object>().type("object"));
15871587
}
15881588
Schema oSchema = mediaType.getSchema();
15891589
for (SchemaProperty sp: annotationContent.schemaProperties()) {

modules/swagger-core/src/main/java/io/swagger/v3/core/util/ModelDeserializer.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.fasterxml.jackson.databind.node.ArrayNode;
88
import com.fasterxml.jackson.databind.node.ObjectNode;
99
import com.fasterxml.jackson.databind.node.TextNode;
10+
import io.swagger.v3.oas.models.media.ArbitrarySchema;
1011
import io.swagger.v3.oas.models.media.ArraySchema;
1112
import io.swagger.v3.oas.models.media.BooleanSchema;
1213
import io.swagger.v3.oas.models.media.ComposedSchema;
@@ -32,6 +33,15 @@
3233

3334
public class ModelDeserializer extends JsonDeserializer<Schema> {
3435

36+
static Boolean useArbitrarySchema = false;
37+
static {
38+
if (System.getenv(Schema.USE_ARBITRARY_SCHEMA_PROPERTY) != null) {
39+
useArbitrarySchema = Boolean.parseBoolean(System.getenv(Schema.USE_ARBITRARY_SCHEMA_PROPERTY));
40+
} else if (System.getProperty(Schema.USE_ARBITRARY_SCHEMA_PROPERTY) != null) {
41+
useArbitrarySchema = Boolean.parseBoolean(System.getProperty(Schema.USE_ARBITRARY_SCHEMA_PROPERTY));
42+
}
43+
}
44+
3545
protected boolean openapi31 = false;
3646
@Override
3747
public Schema deserialize(JsonParser jp, DeserializationContext ctxt)
@@ -85,18 +95,18 @@ public Schema deserialize(JsonParser jp, DeserializationContext ctxt)
8595
schema = Json.mapper().convertValue(node, StringSchema.class);
8696
}
8797
} else if (type.textValue().equals("object")) {
88-
schema = deserializeObjectSchema(node);
98+
schema = deserializeArbitraryOrObjectSchema(node, true);
8999
}
90100
} else if (node.get("$ref") != null) {
91101
schema = new Schema().$ref(node.get("$ref").asText());
92-
} else { // assume object
93-
schema = deserializeObjectSchema(node);
102+
} else {
103+
schema = deserializeArbitraryOrObjectSchema(node, false);
94104
}
95105

96106
return schema;
97107
}
98108

99-
private Schema deserializeObjectSchema(JsonNode node) {
109+
private Schema deserializeArbitraryOrObjectSchema(JsonNode node, boolean alwaysObject) {
100110
JsonNode additionalProperties = node.get("additionalProperties");
101111
Schema schema = null;
102112
if (additionalProperties != null) {
@@ -117,7 +127,11 @@ private Schema deserializeObjectSchema(JsonNode node) {
117127
schema = ms;
118128
}
119129
} else {
120-
schema = Json.mapper().convertValue(node, ObjectSchema.class);
130+
if (!Boolean.TRUE.equals(useArbitrarySchema) || alwaysObject) {
131+
schema = Json.mapper().convertValue(node, ObjectSchema.class);
132+
} else {
133+
schema = Json.mapper().convertValue(node, ArbitrarySchema.class);
134+
}
121135
}
122136
if (schema != null) {
123137
schema.jsonSchema(Json31.jsonSchemaAsMap(node));

modules/swagger-core/src/main/java/io/swagger/v3/core/util/ParameterProcessor.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ public static Parameter applyAnnotations(
253253
if (parameter.getSchema() == null) {
254254
parameter.setSchema(new ArraySchema());
255255
}
256-
if (parameter.getSchema() instanceof ArraySchema) {
257-
ArraySchema as = (ArraySchema) parameter.getSchema();
256+
if (isArraySchema(parameter.getSchema())) {
257+
Schema as = parameter.getSchema();
258258
Integer min = (Integer) annotation.annotationType().getMethod("min").invoke(annotation);
259259
if (min != null) {
260260
as.setMinItems(min);
@@ -281,10 +281,9 @@ public static Parameter applyAnnotations(
281281
}
282282
}
283283
if (paramSchema != null) {
284-
if (paramSchema instanceof ArraySchema) {
285-
ArraySchema as = (ArraySchema) paramSchema;
284+
if (isArraySchema(paramSchema)) {
286285
if (defaultValue != null) {
287-
as.getItems().setDefault(defaultValue);
286+
paramSchema.getItems().setDefault(defaultValue);
288287
}
289288
} else {
290289
if (defaultValue != null) {
@@ -295,6 +294,10 @@ public static Parameter applyAnnotations(
295294
return parameter;
296295
}
297296

297+
public static boolean isArraySchema(Schema schema) {
298+
return "array".equals(schema.getType()) || (schema.getTypes() != null && schema.getTypes().contains("array"));
299+
}
300+
298301
public static void setParameterExplode(Parameter parameter, io.swagger.v3.oas.annotations.Parameter p) {
299302
if (isExplodable(p, parameter)) {
300303
if (Explode.TRUE.equals(p.explode())) {

0 commit comments

Comments
 (0)