Skip to content

Commit

Permalink
fix for array schema in ApiResponse and Parameter annotations. (micro…
Browse files Browse the repository at this point in the history
  • Loading branch information
croudet authored Feb 17, 2020
1 parent 78c70c9 commit 931e767
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,29 @@ private Optional<Object> parseJsonString(Object object) {
return Optional.empty();
}

private <T extends Schema> void processAnnotationValue(VisitorContext context, AnnotationValue<?> annotationValue, Map<CharSequence, Object> arraySchemaMap, List<String> filters, Class<T> type) {
Map<CharSequence, Object> values = annotationValue.getValues().entrySet().stream()
.filter(entry -> filters == null || ! filters.contains(entry.getKey()))
.collect(toMap(
e -> e.getKey().equals("requiredProperties") ? "required" : e.getKey(), Map.Entry::getValue));
JsonNode schemaJson = toJson(values, context);
try {
T schema = treeToValue(schemaJson, type);
if (schema != null) {
schemaToValueMap(arraySchemaMap, schema);
}
} catch (JsonProcessingException e) {
context.warn("Error reading Swagger Schema: " + e.getMessage(), null);
}
}

private Map<CharSequence, Object> resolveArraySchemaAnnotationValues(VisitorContext context, AnnotationValue<?> av) {
final Map<CharSequence, Object> arraySchemaMap = new HashMap<>(10);
// properties
av.get("arraySchema", AnnotationValue.class).ifPresent(annotationValue -> {
processAnnotationValue(context, (AnnotationValue<?>) annotationValue, arraySchemaMap, Arrays.asList("ref", "implementation"), Schema.class);
});
// items
av.get("schema", AnnotationValue.class).ifPresent(annotationValue -> {
Optional<String> impl = ((AnnotationValue<?>) annotationValue).get("implementation", String.class);
Optional<String> type = ((AnnotationValue<?>) annotationValue).get("type", String.class);
Expand Down Expand Up @@ -446,9 +467,11 @@ private Map<CharSequence, Object> resolveArraySchemaAnnotationValues(VisitorCont
schemaToValueMap(arraySchemaMap, schema);
}
} else {
arraySchemaMap.putAll(resolveAnnotationValues(context, av));
arraySchemaMap.putAll(resolveAnnotationValues(context, annotationValue));
}
});
// other properties (minItems,...)
processAnnotationValue(context, av, arraySchemaMap, Arrays.asList("schema", "arraySchema"), ArraySchema.class);
return arraySchemaMap;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
package io.micronaut.openapi.visitor

import io.micronaut.annotation.processing.test.AbstractTypeElementSpec
import io.micronaut.http.MediaType
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.enums.ParameterIn
import io.swagger.v3.oas.annotations.media.ArraySchema
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.Operation

Expand All @@ -24,7 +31,7 @@ class OpenApiArraySchemaSpec extends AbstractTypeElementSpec {
System.setProperty(AbstractOpenApiVisitor.ATTR_TEST_MODE, "true")
}

void "test ArraySchema with arraySchema field"() {
void "test ArraySchema with arraySchema field in class"() {
given:
buildBeanDefinition('test.MyBean', '''
package test;
Expand Down Expand Up @@ -98,4 +105,107 @@ class MyBean {}
openAPI.components.schemas['Pets'].properties['primitiveIds'].items.description == 'Yes'
openAPI.components.schemas['Pets'].properties['primitiveIds'].items.nullable == true
}

void "test ArraySchema with arraySchema field in Controller ApiResponse"() {
given:
buildBeanDefinition('test.MyBean', '''
package test;
import io.swagger.v3.oas.annotations.*;
import io.swagger.v3.oas.annotations.parameters.*;
import io.swagger.v3.oas.annotations.responses.*;
import io.swagger.v3.oas.annotations.security.*;
import io.swagger.v3.oas.annotations.media.*;
import io.swagger.v3.oas.annotations.enums.*;
import io.swagger.v3.oas.annotations.links.*;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.*;
import java.util.List;
@Controller("/")
class MyController {
@Get("/")
@Operation(description = "Lists the Pets.")
@ApiResponse(responseCode = "200", description = "Returns a list of _Pet_s.", content = @Content(mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema(minItems = 2, arraySchema = @Schema(description = "A list of Pets", example = "[{'name': 'cat'}, {'name': 'dog'}]"), schema = @Schema(implementation = Pet.class))))
public List<Pet> findPets() {
return null;
}
}
@Schema(description = "Pet")
class Pet {
@Schema(description = "The name of the pet")
public String name;
}
@javax.inject.Singleton
class MyBean {}
''')

OpenAPI openAPI = AbstractOpenApiVisitor.testReference
Operation operation = openAPI.paths?.get("/")?.get

expect:
operation
operation.responses.size() == 1
operation.responses.'200'.content.'application/json'.schema.description == 'A list of Pets'
operation.responses.'200'.content.'application/json'.schema.minItems == 2
operation.responses.'200'.content.'application/json'.schema.items.$ref == '#/components/schemas/Pet'

}

void "test ArraySchema with arraySchema field in Controller Parameter"() {
given:
buildBeanDefinition('test.MyBean', '''
package test;
import io.swagger.v3.oas.annotations.*;
import io.swagger.v3.oas.annotations.parameters.*;
import io.swagger.v3.oas.annotations.responses.*;
import io.swagger.v3.oas.annotations.security.*;
import io.swagger.v3.oas.annotations.media.*;
import io.swagger.v3.oas.annotations.enums.*;
import io.swagger.v3.oas.annotations.links.*;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.*;
import java.util.List;
@Controller("/")
class MyController {
@Get("/{?names*}")
@Operation(description = "Lists the Pets.")
@ApiResponse(responseCode = "200", description = "Returns a list of _Pet_s.", content = @Content(mediaType = MediaType.APPLICATION_JSON, array = @ArraySchema(minItems = 2, arraySchema = @Schema(description = "A list of Pets", example = "[{'name': 'cat'}, {'name': 'dog'}]"), schema = @Schema(implementation = Pet.class))))
public List<Pet> findPets(@Parameter(in = ParameterIn.QUERY, required = true, description = "A list of names", example = "['dog', 'cat']", array = @ArraySchema(minItems = 2, arraySchema = @Schema(description = "A list of _Pet_'s name"), schema = @Schema(type = "string"))) List<String> names) {
return null;
}
}
@Schema(description = "Pet")
class Pet {
@Schema(description = "The name of the pet")
public String name;
}
@javax.inject.Singleton
class MyBean {}
''')

OpenAPI openAPI = AbstractOpenApiVisitor.testReference
Operation operation = openAPI.paths?.get("/")?.get

expect:
operation
operation.responses.size() == 1
operation.responses.'200'.content.'application/json'.schema.description == 'A list of Pets'
operation.responses.'200'.content.'application/json'.schema.minItems == 2
operation.responses.'200'.content.'application/json'.schema.items.$ref == '#/components/schemas/Pet'

operation.parameters
operation.parameters.size() == 1
operation.parameters[0].schema.description == 'A list of _Pet_\'s name'
operation.parameters[0].schema.minItems == 2
operation.parameters[0].schema.items.type == 'string'
}
}

0 comments on commit 931e767

Please sign in to comment.