Skip to content

Commit

Permalink
Merge pull request #1079 from altro3/merge_4.9.2
Browse files Browse the repository at this point in the history
Merge 4.9.2
  • Loading branch information
graemerocher committed Jun 22, 2023
2 parents cdf4da4 + 3167376 commit ab23915
Show file tree
Hide file tree
Showing 11 changed files with 342 additions and 59 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ projectUrl=https://micronaut.io
githubSlug=micronaut-projects/micronaut-openapi
developers=Puneet Behl,Álvaro Sánchez-Mariscal,Iván López

org.gradle.caching=false
org.gradle.caching=true
kotlin.stdlib.default.dependency=false
org.gradle.jvmargs=-Xmx1g -Dfile.encoding=UTF-8
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@
import static io.micronaut.openapi.visitor.ElementUtils.isNullable;
import static io.micronaut.openapi.visitor.OpenApiApplicationVisitor.getSecurityProperties;
import static io.micronaut.openapi.visitor.OpenApiApplicationVisitor.isOpenApiEnabled;
import static io.micronaut.openapi.visitor.SchemaUtils.COMPONENTS_CALLBACKS_PREFIX;
import static io.micronaut.openapi.visitor.SchemaUtils.COMPONENTS_SCHEMAS_PREFIX;
import static io.micronaut.openapi.visitor.SchemaUtils.TYPE_OBJECT;
import static io.micronaut.openapi.visitor.Utils.DEFAULT_MEDIA_TYPES;

Expand All @@ -122,8 +124,6 @@
*/
public abstract class AbstractOpenApiEndpointVisitor extends AbstractOpenApiVisitor {

public static final String COMPONENTS_CALLBACKS_PREFIX = "#/components/callbacks/";

protected static final String CONTEXT_CHILD_PATH = "internal.child.path";
protected static final String CONTEXT_CHILD_OP_ID_PREFIX = "internal.opId.prefix";
protected static final String CONTEXT_CHILD_OP_ID_SUFFIX = "internal.opId.suffix";
Expand Down Expand Up @@ -398,6 +398,8 @@ public void visitMethod(MethodElement element, VisitorContext context) {
List<MediaType> consumesMediaTypes = consumesMediaTypes(element);
Map<PathItem, io.swagger.v3.oas.models.Operation> swaggerOperations = readOperations(pathItemEntry.getKey(), httpMethod, pathItems, element, context);

boolean isRequestBodySchemaSet = false;

for (Map.Entry<PathItem, io.swagger.v3.oas.models.Operation> operationEntry : swaggerOperations.entrySet()) {
io.swagger.v3.oas.models.Operation swaggerOperation = operationEntry.getValue();
io.swagger.v3.oas.models.ExternalDocumentation externalDocs = readExternalDocs(element, context);
Expand Down Expand Up @@ -427,7 +429,12 @@ public void visitMethod(MethodElement element, VisitorContext context) {
readResponse(element, context, openAPI, swaggerOperation, javadocDescription);

if (permitsRequestBody) {
RequestBody requestBody = readSwaggerRequestBody(element, consumesMediaTypes, context);
Pair<RequestBody, Boolean> requestBodyPair = readSwaggerRequestBody(element, consumesMediaTypes, context);
RequestBody requestBody = null;
if (requestBodyPair != null) {
requestBody = requestBodyPair.getFirst();
isRequestBodySchemaSet = requestBodyPair.getSecond();
}
if (requestBody != null) {
RequestBody currentRequestBody = swaggerOperation.getRequestBody();
if (currentRequestBody != null) {
Expand All @@ -454,14 +461,15 @@ public void visitMethod(MethodElement element, VisitorContext context) {
List<TypedElement> extraBodyParameters = new ArrayList<>();
for (io.swagger.v3.oas.models.Operation operation : swaggerOperations.values()) {
processParameters(element, context, openAPI, operation, javadocDescription, permitsRequestBody, pathVariables, consumesMediaTypes, extraBodyParameters, httpMethod, matchTemplates, pathItems);
processExtraBodyParameters(context, httpMethod, openAPI, operation, javadocDescription, consumesMediaTypes, extraBodyParameters);
processExtraBodyParameters(context, httpMethod, openAPI, operation, javadocDescription, isRequestBodySchemaSet, consumesMediaTypes, extraBodyParameters);
}
}
}

private void processExtraBodyParameters(VisitorContext context, HttpMethod httpMethod, OpenAPI openAPI,
io.swagger.v3.oas.models.Operation swaggerOperation,
JavadocDescription javadocDescription,
boolean isRequestBodySchemaSet,
List<MediaType> consumesMediaTypes,
List<TypedElement> extraBodyParameters) {
RequestBody requestBody = swaggerOperation.getRequestBody();
Expand Down Expand Up @@ -491,31 +499,39 @@ private void processExtraBodyParameters(VisitorContext context, HttpMethod httpM
mediaType.setSchema(schema);
}
if (schema.get$ref() != null) {
ComposedSchema composedSchema = new ComposedSchema();
Schema extraBodyParametersSchema = new Schema();
// Composition of existing + a new schema where extra body parameters are going to be added
composedSchema.addAllOfItem(schema);
composedSchema.addAllOfItem(extraBodyParametersSchema);
schema = extraBodyParametersSchema;
mediaType.setSchema(composedSchema);
if (isRequestBodySchemaSet) {
schema = openAPI.getComponents().getSchemas().get(schema.get$ref().substring(COMPONENTS_SCHEMAS_PREFIX.length()));
} else {
ComposedSchema composedSchema = new ComposedSchema();
Schema extraBodyParametersSchema = new Schema();
// Composition of existing + a new schema where extra body parameters are going to be added
composedSchema.addAllOfItem(schema);
composedSchema.addAllOfItem(extraBodyParametersSchema);
schema = extraBodyParametersSchema;
mediaType.setSchema(composedSchema);
}
}
for (TypedElement parameter : extraBodyParameters) {
processBodyParameter(context, openAPI, javadocDescription, MediaType.of(mediaTypeName), schema, parameter);
if (!isRequestBodySchemaSet) {
processBodyParameter(context, openAPI, javadocDescription, MediaType.of(mediaTypeName), schema, parameter);
}
if (mediaTypeName.equals(MediaType.MULTIPART_FORM_DATA)) {
for (String prop : (Set<String>) schema.getProperties().keySet()) {
Map<String, Encoding> encodings = mediaType.getEncoding();
if (encodings == null) {
encodings = new HashMap<>();
mediaType.setEncoding(encodings);
}
// if content type doesn't set by annotation,
// we can set application/octet-stream for file upload classes
Encoding encoding = encodings.get(prop);
if (encoding == null && isFileUpload(parameter.getType())) {
encoding = new Encoding();
encodings.put(prop, encoding);

encoding.setContentType(MediaType.APPLICATION_OCTET_STREAM);
if (CollectionUtils.isNotEmpty(schema.getProperties())) {
for (String prop : (Set<String>) schema.getProperties().keySet()) {
Map<String, Encoding> encodings = mediaType.getEncoding();
if (encodings == null) {
encodings = new HashMap<>();
mediaType.setEncoding(encodings);
}
// if content type doesn't set by annotation,
// we can set application/octet-stream for file upload classes
Encoding encoding = encodings.get(prop);
if (encoding == null && isFileUpload(parameter.getType())) {
encoding = new Encoding();
encodings.put(prop, encoding);

encoding.setContentType(MediaType.APPLICATION_OCTET_STREAM);
}
}
}
}
Expand Down Expand Up @@ -651,9 +667,9 @@ private void processParameter(VisitorContext context, OpenAPI openAPI,
return;
}
if (permitsRequestBody && swaggerOperation.getRequestBody() == null) {
RequestBody requestBody = readSwaggerRequestBody(parameter, consumesMediaTypes, context);
if (requestBody != null) {
swaggerOperation.setRequestBody(requestBody);
Pair<RequestBody, Boolean> requestBodyPair = readSwaggerRequestBody(parameter, consumesMediaTypes, context);
if (requestBodyPair != null && requestBodyPair.getFirst() != null) {
swaggerOperation.setRequestBody(requestBodyPair.getFirst());
}
}

Expand Down Expand Up @@ -1678,15 +1694,25 @@ private void processResponses(io.swagger.v3.oas.models.Operation operation, List
}
}

private RequestBody readSwaggerRequestBody(Element element, List<MediaType> consumesMediaTypes, VisitorContext context) {
// boolean - is swagger schema has implementation
private Pair<RequestBody, Boolean> readSwaggerRequestBody(Element element, List<MediaType> consumesMediaTypes, VisitorContext context) {
AnnotationValue<io.swagger.v3.oas.annotations.parameters.RequestBody> requestBodyAnnValue =
element.findAnnotation(io.swagger.v3.oas.annotations.parameters.RequestBody.class).orElse(null);

if (requestBodyAnnValue == null) {
return null;
}

boolean hasSchemaImplementation = false;

AnnotationValue<io.swagger.v3.oas.annotations.media.Content> content = requestBodyAnnValue.getAnnotation("content", io.swagger.v3.oas.annotations.media.Content.class).orElse(null);
if (content != null) {
AnnotationValue<io.swagger.v3.oas.annotations.media.Schema> swaggerSchema = content.getAnnotation("schema", io.swagger.v3.oas.annotations.media.Schema.class).orElse(null);
if (swaggerSchema != null) {
hasSchemaImplementation = swaggerSchema.stringValue("implementation").orElse(null) != null;
}
}

RequestBody requestBody = toValue(requestBodyAnnValue.getValues(), context, RequestBody.class).orElse(null);
// if media type doesn't set in swagger annotation, check micronaut annotation
if (content != null
Expand All @@ -1701,7 +1727,7 @@ private RequestBody readSwaggerRequestBody(Element element, List<MediaType> cons
}
}

return requestBody;
return Pair.of(requestBody, hasSchemaImplementation);
}

private void readServers(MethodElement element, VisitorContext context, io.swagger.v3.oas.models.Operation swaggerOperation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@
import static io.micronaut.openapi.visitor.OpenApiApplicationVisitor.getConfigurationProperty;
import static io.micronaut.openapi.visitor.OpenApiApplicationVisitor.getExpandableProperties;
import static io.micronaut.openapi.visitor.OpenApiApplicationVisitor.resolvePlaceholders;
import static io.micronaut.openapi.visitor.SchemaUtils.EMPTY_SCHEMA;
import static io.micronaut.openapi.visitor.SchemaUtils.TYPE_OBJECT;
import static io.micronaut.openapi.visitor.Utils.resolveComponents;
import static java.util.stream.Collectors.toMap;
Expand All @@ -148,7 +147,6 @@
abstract class AbstractOpenApiVisitor {

private static final Lock VISITED_ELEMENTS_LOCK = new ReentrantLock();
private static final ComposedSchema EMPTY_COMPOSED_SCHEMA = new ComposedSchema();

/**
* Stores relations between schema names and class names.
Expand Down Expand Up @@ -415,18 +413,17 @@ protected Map<CharSequence, Object> toValueMap(Map<CharSequence, Object> values,
Object[] a = (Object[]) value;
if (ArrayUtils.isNotEmpty(a)) {
Object first = a[0];
boolean areAnnotationValues = first instanceof AnnotationValue;
boolean areClassValues = first instanceof AnnotationClassValue;

if (areClassValues) {
// are class values
if ( first instanceof AnnotationClassValue) {
List<Class<?>> classes = new ArrayList<>(a.length);
for (Object o : a) {
AnnotationClassValue<?> acv = (AnnotationClassValue<?>) o;
acv.getType().ifPresent(classes::add);
}
newValues.put(key, classes);
} else if (areAnnotationValues) {
String annotationName = ((AnnotationValue<?>) first).getAnnotationName();
} else if (first instanceof AnnotationValue<?> annValue) {
String annotationName = annValue.getAnnotationName();
if (io.swagger.v3.oas.annotations.security.SecurityRequirement.class.getName().equals(annotationName)) {
List<SecurityRequirement> securityRequirements = new ArrayList<>(a.length);
for (Object o : a) {
Expand Down Expand Up @@ -835,8 +832,8 @@ protected Schema resolveSchema(OpenAPI openAPI, @Nullable Element definingElemen

Schema schema = null;

if (type instanceof EnumElement) {
schema = getSchemaDefinition(openAPI, context, type, typeArgs, definingElement, mediaTypes);
if (type instanceof EnumElement enumEl) {
schema = getSchemaDefinition(openAPI, context, enumEl, typeArgs, definingElement, mediaTypes);
} else {

boolean isPublisher = false;
Expand Down Expand Up @@ -972,7 +969,7 @@ protected Schema resolveSchema(OpenAPI openAPI, @Nullable Element definingElemen
if (schema != null) {

if (isSubstitudedType) {
processShemaAnn(schema, context, definingElement, schemaAnnotationValue);
processShemaAnn(schema, context, definingElement, type, schemaAnnotationValue);
}

if (definingElement != null && StringUtils.isEmpty(schema.getDescription())) {
Expand Down Expand Up @@ -1190,7 +1187,7 @@ protected Schema bindSchemaForElement(VisitorContext context, TypedElement eleme
Schema originalSchema = schemaToBind;

if (originalSchema.get$ref() != null) {
Schema schemaFromAnn = schemaFromAnnotation(context, element, schemaAnn);
Schema schemaFromAnn = schemaFromAnnotation(context, element, elementType, schemaAnn);
if (schemaFromAnn != null) {
schemaToBind = schemaFromAnn;
}
Expand Down Expand Up @@ -1257,7 +1254,7 @@ protected Schema bindSchemaForElement(VisitorContext context, TypedElement eleme
notOnlyRef = true;
}

boolean addSchemaToBind = !schemaToBind.equals(EMPTY_SCHEMA);
boolean addSchemaToBind = !SchemaUtils.isEmptySchema(schemaToBind);

if (addSchemaToBind) {
if (TYPE_OBJECT.equals(originalSchema.getType())) {
Expand All @@ -1266,7 +1263,7 @@ protected Schema bindSchemaForElement(VisitorContext context, TypedElement eleme
}
originalSchema.setType(null);
}
if (!originalSchema.equals(EMPTY_SCHEMA)) {
if (!SchemaUtils.isEmptySchema(originalSchema)) {
composedSchema.addAllOfItem(originalSchema);
}
} else if (isNullable && CollectionUtils.isEmpty(composedSchema.getAllOf())) {
Expand All @@ -1282,7 +1279,7 @@ protected Schema bindSchemaForElement(VisitorContext context, TypedElement eleme
composedSchema.addAllOfItem(schemaToBind);
}

if (!composedSchema.equals(EMPTY_COMPOSED_SCHEMA)
if (!SchemaUtils.isEmptySchema(composedSchema)
&& ((CollectionUtils.isNotEmpty(composedSchema.getAllOf()) && composedSchema.getAllOf().size() > 1)
|| CollectionUtils.isNotEmpty(composedSchema.getOneOf())
|| CollectionUtils.isNotEmpty(composedSchema.getAnyOf())
Expand Down Expand Up @@ -1462,18 +1459,18 @@ protected void processJavaxValidationAnnotations(Element element, ClassElement e
}
}

Schema schemaFromAnnotation(VisitorContext context, Element element, AnnotationValue<io.swagger.v3.oas.annotations.media.Schema> schemaAnn) {
Schema schemaFromAnnotation(VisitorContext context, Element element, ClassElement type, AnnotationValue<io.swagger.v3.oas.annotations.media.Schema> schemaAnn) {
if (schemaAnn == null) {
return null;
}

Schema schemaToBind = new Schema();
processShemaAnn(schemaToBind, context, element, schemaAnn);
processShemaAnn(schemaToBind, context, element, type, schemaAnn);

return schemaToBind;
}

void processShemaAnn(Schema schemaToBind, VisitorContext context, Element element, @NonNull AnnotationValue<io.swagger.v3.oas.annotations.media.Schema> schemaAnn) {
void processShemaAnn(Schema schemaToBind, VisitorContext context, Element element, ClassElement type, @NonNull AnnotationValue<io.swagger.v3.oas.annotations.media.Schema> schemaAnn) {

Map<CharSequence, Object> annValues = schemaAnn.getValues();
if (annValues.containsKey("description")) {
Expand Down Expand Up @@ -1536,7 +1533,7 @@ void processShemaAnn(Schema schemaToBind, VisitorContext context, Element elemen

String schemaDefaultValue = (String) annValues.get("defaultValue");
if (schemaDefaultValue != null) {
setDefaultValueObject(schemaToBind, schemaDefaultValue, element, schemaToBind.getType(), schemaToBind.getFormat(), false, context);
setDefaultValueObject(schemaToBind, schemaDefaultValue, type, schemaToBind.getType(), schemaToBind.getFormat(), false, context);
}
String schemaExample = (String) annValues.get("example");
if (StringUtils.isNotEmpty(schemaExample)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ public static SecurityRequirement mapToSecurityRequirement(AnnotationValue<io.sw
public static void setDefaultValueObject(Schema<?> schema, String defaultValue, @Nullable Element element, @Nullable String schemaType, @Nullable String schemaFormat, boolean isMicronautFormat, VisitorContext context) {
try {
Pair<String, String> typeAndFormat;
if (element instanceof EnumElement) {
typeAndFormat = ConvertUtils.checkEnumJsonValueType(context, (EnumElement) element, schemaType, schemaFormat);
if (element instanceof EnumElement enumEl) {
typeAndFormat = ConvertUtils.checkEnumJsonValueType(context, enumEl, schemaType, schemaFormat);
} else {
typeAndFormat = Pair.of(schemaType, schemaFormat);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;

import static io.micronaut.openapi.visitor.SchemaUtils.EMPTY_COMPOSED_SCHEMA;
import static io.micronaut.openapi.visitor.SchemaUtils.EMPTY_SCHEMA;
import static io.micronaut.openapi.visitor.SchemaUtils.EMPTY_SIMPLE_SCHEMA;
import static io.micronaut.openapi.visitor.SchemaUtils.TYPE_OBJECT;
import static io.swagger.v3.oas.models.Components.COMPONENTS_SCHEMAS_REF;
Expand Down Expand Up @@ -1451,7 +1449,7 @@ private Schema normalizeSchema(Schema schema) {
}
boolean isSameType = allOfSchema.getType() == null || allOfSchema.getType().equals(type);

if (schema.equals(EMPTY_SCHEMA) || schema.equals(EMPTY_COMPOSED_SCHEMA)
if (SchemaUtils.isEmptySchema(schema)
&& (serializedDefaultValue == null || serializedDefaultValue.equals(serializedAllOfDefaultValue))
&& (type == null || allOfSchema.getType() == null || allOfSchema.getType().equals(type))) {
normalizedSchema = allOfSchema;
Expand Down
Loading

0 comments on commit ab23915

Please sign in to comment.