Skip to content

Commit

Permalink
Update Mixins to latest from swagger and handle explode attribute i…
Browse files Browse the repository at this point in the history
…n Parameter (#163)

* Update mixins to latest.

* Process Parameter explode field

was causing exception.

upgrade swagger to latest
  • Loading branch information
croudet authored Mar 4, 2020
1 parent 08e1d38 commit 71b1ae7
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 42 deletions.
4 changes: 3 additions & 1 deletion docs-examples/example-groovy/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ plugins {

dependencyManagement {
imports {
mavenBom "io.micronaut:micronaut-bom:$micronautVersion"
mavenBom("io.micronaut:micronaut-bom:$micronautVersion") {
bomProperty 'swagger.version', swaggerVersion
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion docs-examples/example-java/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ plugins {

dependencyManagement {
imports {
mavenBom "io.micronaut:micronaut-bom:$micronautVersion"
mavenBom("io.micronaut:micronaut-bom:$micronautVersion") {
bomProperty 'swagger.version', swaggerVersion
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion docs-examples/example-kotlin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ plugins {

dependencyManagement {
imports {
mavenBom "io.micronaut:micronaut-bom:$micronautVersion"
mavenBom("io.micronaut:micronaut-bom:$micronautVersion") {
bomProperty 'swagger.version', swaggerVersion
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ grailsVersion=3.3.8
spockVersion=1.2-groovy-2.5
micronautTestVersion=1.1.0
rxJava2Version=2.2.6
swaggerVersion=2.0.10
swaggerVersion=2.1.1
title=OpenAPI/Swagger Support
projectDesc=Configuration to integrate Micronaut and OpenAPI/Swagger
projectUrl=http://micronaut.io
Expand Down
79 changes: 42 additions & 37 deletions openapi/src/main/java/io/micronaut/openapi/util/Yaml.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@

import io.micronaut.core.annotation.Internal;
import io.swagger.v3.core.jackson.SchemaSerializer;
import io.swagger.v3.core.jackson.mixin.ComponentsMixin;
import io.swagger.v3.core.jackson.mixin.DateSchemaMixin;
import io.swagger.v3.core.jackson.mixin.ExtensionsMixin;
import io.swagger.v3.core.jackson.mixin.OpenAPIMixin;
import io.swagger.v3.core.jackson.mixin.OperationMixin;
import io.swagger.v3.core.util.DeserializationModule;
import io.swagger.v3.oas.models.*;
import io.swagger.v3.oas.models.callbacks.Callback;
Expand All @@ -43,6 +47,7 @@
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.security.OAuthFlow;
import io.swagger.v3.oas.models.security.OAuthFlows;
import io.swagger.v3.oas.models.security.Scopes;
Expand All @@ -52,10 +57,8 @@
import io.swagger.v3.oas.models.servers.ServerVariables;
import io.swagger.v3.oas.models.tags.Tag;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.LinkedHashMap;
import java.util.Map;

/**
* Helper class for generating Swagger YAML.
Expand Down Expand Up @@ -100,40 +103,42 @@ public JsonSerializer<?> modifySerializer(
}
}).registerModule(new DeserializationModule()).registerModule(new JavaTimeModule());

List<Class<?>> mixinTargets = Arrays.asList(
ApiResponse.class,
Callback.class,
Components.class,
Contact.class,
Encoding.class,
EncodingProperty.class,
Example.class,
ExternalDocumentation.class,
Header.class,
Info.class,
License.class,
Link.class,
LinkParameter.class,
MediaType.class,
OAuthFlow.class,
OAuthFlows.class,
OpenAPI.class,
Operation.class,
Parameter.class,
PathItem.class,
Paths.class,
RequestBody.class,
Scopes.class,
SecurityScheme.class,
Server.class,
ServerVariable.class,
ServerVariables.class,
Tag.class,
XML.class,
Schema.class
);
mapper.setMixIns(mixinTargets.stream().collect(Collectors.toMap(Function.identity(), c -> ExtensionsMixin.class)));
Map<Class<?>, Class<?>> sourceMixins = new LinkedHashMap<>(40);

sourceMixins.put(ApiResponses.class, ExtensionsMixin.class);
sourceMixins.put(ApiResponse.class, ExtensionsMixin.class);
sourceMixins.put(Callback.class, ExtensionsMixin.class);
sourceMixins.put(Components.class, ComponentsMixin.class);
sourceMixins.put(Contact.class, ExtensionsMixin.class);
sourceMixins.put(Encoding.class, ExtensionsMixin.class);
sourceMixins.put(EncodingProperty.class, ExtensionsMixin.class);
sourceMixins.put(Example.class, ExtensionsMixin.class);
sourceMixins.put(ExternalDocumentation.class, ExtensionsMixin.class);
sourceMixins.put(Header.class, ExtensionsMixin.class);
sourceMixins.put(Info.class, ExtensionsMixin.class);
sourceMixins.put(License.class, ExtensionsMixin.class);
sourceMixins.put(Link.class, ExtensionsMixin.class);
sourceMixins.put(LinkParameter.class, ExtensionsMixin.class);
sourceMixins.put(MediaType.class, ExtensionsMixin.class);
sourceMixins.put(OAuthFlow.class, ExtensionsMixin.class);
sourceMixins.put(OAuthFlows.class, ExtensionsMixin.class);
sourceMixins.put(OpenAPI.class, OpenAPIMixin.class);
sourceMixins.put(Operation.class, OperationMixin.class);
sourceMixins.put(Parameter.class, ExtensionsMixin.class);
sourceMixins.put(PathItem.class, ExtensionsMixin.class);
sourceMixins.put(Paths.class, ExtensionsMixin.class);
sourceMixins.put(RequestBody.class, ExtensionsMixin.class);
sourceMixins.put(Scopes.class, ExtensionsMixin.class);
sourceMixins.put(SecurityScheme.class, ExtensionsMixin.class);
sourceMixins.put(Server.class, ExtensionsMixin.class);
sourceMixins.put(ServerVariable.class, ExtensionsMixin.class);
sourceMixins.put(ServerVariables.class, ExtensionsMixin.class);
sourceMixins.put(Tag.class, ExtensionsMixin.class);
sourceMixins.put(XML.class, ExtensionsMixin.class);
sourceMixins.put(Schema.class, ExtensionsMixin.class);
sourceMixins.put(DateSchema.class, DateSchemaMixin.class);

mapper.setMixIns(sourceMixins);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.callbacks.Callback;
import io.swagger.v3.oas.annotations.enums.Explode;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.models.Components;
Expand Down Expand Up @@ -374,7 +375,7 @@ public void visitMethod(MethodElement element, VisitorContext context) {
} else if (parameter.isAnnotationPresent(QueryValue.class)) {
paramValues.put("in", ParameterIn.QUERY.toString());
}

processExplode(paramAnn, paramValues);

JsonNode jsonNode = jsonMapper.valueToTree(paramValues);

Expand Down Expand Up @@ -509,6 +510,40 @@ public void visitMethod(MethodElement element, VisitorContext context) {
});
}

private void processExplode(AnnotationValue<io.swagger.v3.oas.annotations.Parameter> paramAnn, Map<CharSequence, Object> paramValues) {
Optional<Explode> explode = paramAnn.enumValue("explode", Explode.class);
if (explode.isPresent()) {
Explode ex = explode.get();
switch (ex) {
case TRUE:
paramValues.put("explode", Boolean.TRUE);
break;
case FALSE:
paramValues.put("explode", Boolean.FALSE);
break;
case DEFAULT:
default:
String in = (String) paramValues.get("in");
if (in == null || in.isEmpty()) {
in = "DEFAULT";
}
switch (ParameterIn.valueOf(in.toUpperCase(Locale.US))) {
case COOKIE:
case QUERY:
paramValues.put("explode", Boolean.TRUE);
break;
case DEFAULT:
case HEADER:
case PATH:
default:
paramValues.put("explode", Boolean.FALSE);
break;
}
break;
}
}
}

private boolean isIgnoredParameterType(ClassElement parameterType) {
return parameterType == null ||
parameterType.isAssignable(Principal.class) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
package io.micronaut.openapi.visitor

import io.micronaut.annotation.processing.test.AbstractTypeElementSpec
import io.swagger.v3.oas.annotations.enums.ParameterIn
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.PathItem
import io.swagger.v3.oas.models.media.Schema
import io.swagger.v3.oas.models.parameters.HeaderParameter

class OpenApiParameterMappingSpec extends AbstractTypeElementSpec {

Expand Down Expand Up @@ -453,6 +455,96 @@ class MyBean {}
pathItem.get.parameters[1].name == 'name'
pathItem.get.parameters[1].in == 'query'
}

void "test @Parameter in header and explode is true"() {

given:"An API definition"
when:
buildBeanDefinition('test.MyBean', '''
package test;
import io.reactivex.*;
import io.micronaut.http.annotation.*;
import io.micronaut.http.*;
import java.util.List;
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 com.fasterxml.jackson.annotation.*;
/**
* @author graemerocher
* @since 1.0
*/
@Controller("/networks")
interface NetworkOperations {
/**
* @param fooBar some other description
*/
@Operation(
summary = "Gets mappings from TTT using vod provider mappings",
description = "Migration of /networks endpoint from TTT. Gets mappings from XYZ using provider mappings",
responses = {
@ApiResponse(
responseCode = "200", description = "Successfully got abc data from TTT",
content = {
@Content(
mediaType = "application/json", schema = @Schema(implementation = Greeting.class)
)
}
)
})
@Get
public HttpResponse<Greeting> getNetworks(
@Parameter(
in = ParameterIn.HEADER,
name = "fooBar",
description = "NA/true/false (case insensitive)",
required = false,
explode = Explode.TRUE,
schema = @Schema(
implementation = Greeting.class
)
)
Greeting fooBar
);
}
class Greeting {
public String message;
}
@javax.inject.Singleton
class MyBean {}
''')
then:"the state is correct"
AbstractOpenApiVisitor.testReference != null

when:"The OpenAPI is retrieved"
OpenAPI openAPI = AbstractOpenApiVisitor.testReference
Schema greetingSchema = openAPI.components.schemas['Greeting']

then:"the components are valid"
greetingSchema.type == 'object'
greetingSchema.properties.size() == 1
greetingSchema.properties['message'].type == 'string'

when:"the /pets path is retrieved"
PathItem pathItem = openAPI.paths.get("/networks")

then:"it is included in the OpenAPI doc"
pathItem.get.operationId == 'getNetworks'
pathItem.get.parameters.size() == 1
pathItem.get.parameters[0].name =='fooBar'
pathItem.get.parameters[0].class == HeaderParameter
pathItem.get.parameters[0].explode
pathItem.get.parameters[0].description == 'NA/true/false (case insensitive)'
!pathItem.get.parameters[0].required
pathItem.get.parameters[0].schema.$ref == '#/components/schemas/Greeting'
}
}


0 comments on commit 71b1ae7

Please sign in to comment.