Skip to content

Commit

Permalink
Improve OpenAPI 3 method handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
noboomu committed Oct 22, 2018
1 parent b7d5cf6 commit 34b5aa4
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 74 deletions.
6 changes: 2 additions & 4 deletions src/main/java/io/sinistral/proteus/server/ServerRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
import java.util.Deque;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingDeque;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.sinistral.proteus.server.predicates.ServerPredicates;
import io.undertow.io.Receiver;
Expand All @@ -33,6 +29,8 @@
* @author jbauer
*
*/


public class ServerRequest
{
protected static final Receiver.ErrorCallback ERROR_CALLBACK = new Receiver.ErrorCallback() {
Expand Down
92 changes: 84 additions & 8 deletions src/main/java/io/sinistral/proteus/server/tools/oas/Reader.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.fasterxml.jackson.databind.introspect.AnnotatedParameter;
import com.fasterxml.jackson.databind.type.TypeFactory;

import io.sinistral.proteus.server.ServerRequest;
import io.sinistral.proteus.server.ServerResponse;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.core.converter.ModelConverters;
Expand Down Expand Up @@ -96,7 +97,7 @@ public class Reader extends io.swagger.v3.jaxrs2.Reader
public static final String DEFAULT_DESCRIPTION = "default response";

protected OpenAPIConfiguration config;

private Application application;
private OpenAPI openAPI;
private Components components;
Expand All @@ -114,6 +115,8 @@ public class Reader extends io.swagger.v3.jaxrs2.Reader

public Reader()
{
// Json.mapper().addMixIn(ServerRequest.class, ServerRequestMixIn.class);

this.openAPI = new OpenAPI();
paths = new Paths();
openApiTags = new LinkedHashSet<>();
Expand All @@ -124,6 +127,7 @@ public Reader()
public Reader(OpenAPI openAPI)
{
this();

setConfiguration(new SwaggerConfiguration().openAPI(openAPI));
}

Expand Down Expand Up @@ -448,6 +452,8 @@ public OpenAPI read(Class<?> cls,
Optional<io.swagger.v3.oas.models.ExternalDocumentation> classExternalDocumentation = AnnotationsUtils.getExternalDocumentation(apiExternalDocs);

JavaType classType = TypeFactory.defaultInstance().constructType(cls);


BeanDescription bd = Json.mapper().getSerializationConfig().introspect(classType);

final List<Parameter> globalParameters = new ArrayList<>();
Expand All @@ -466,7 +472,13 @@ public OpenAPI read(Class<?> cls,
{
continue;
}
AnnotatedMethod annotatedMethod = bd.findMethod(method.getName(), method.getParameterTypes());

Class<?>[] parameterTypes = Arrays.stream(method.getParameterTypes()).filter( p -> !p.isAssignableFrom(ServerRequest.class) ).toArray(Class<?>[]::new);


AnnotatedMethod annotatedMethod = bd.findMethod(method.getName(), parameterTypes);


javax.ws.rs.Produces methodProduces = ReflectionUtils.getAnnotation(method, javax.ws.rs.Produces.class);
javax.ws.rs.Consumes methodConsumes = ReflectionUtils.getAnnotation(method, javax.ws.rs.Consumes.class);

Expand Down Expand Up @@ -539,20 +551,33 @@ else if (StringUtils.isBlank(httpMethod) && subResource != null)
classResponses);
if (operation != null)
{

//LOGGER.debug("operation is not null");

List<Parameter> operationParameters = new ArrayList<>();
List<Parameter> formParameters = new ArrayList<>();
Annotation[][] paramAnnotations = getParameterAnnotations(method);
if (annotatedMethod == null)
{ // annotatedMethod not null only when method with 0-2
// parameters
Type[] genericParameterTypes = method.getGenericParameterTypes();

genericParameterTypes = Arrays.stream(genericParameterTypes).filter( t -> !t.getTypeName().contains("ServerRequest")).toArray(Type[]::new);
//
// for( Type t : genericParameterTypes )
// {
// LOGGER.warn("Generic parameter type: " + t);
// }
//
// LOGGER.warn("paramAnnotations length: " + paramAnnotations.length + " genericParameterTypes length: " + genericParameterTypes.length);

for (int i = 0; i < genericParameterTypes.length; i++)
{
final Type type = TypeFactory.defaultInstance().constructType(genericParameterTypes[i], cls);
io.swagger.v3.oas.annotations.Parameter paramAnnotation = AnnotationsUtils
.getAnnotation(io.swagger.v3.oas.annotations.Parameter.class, paramAnnotations[i]);

Type paramType = ParameterProcessor.getParameterType(paramAnnotation, true);

if (paramType == null)
{
paramType = type;
Expand All @@ -564,15 +589,21 @@ else if (StringUtils.isBlank(httpMethod) && subResource != null)
paramType = type;
}
}

// LOGGER.warn(i + " Arrays.asList(paramAnnotations[i]): " + Arrays.asList(paramAnnotations[i]));

ResolvedParameter resolvedParameter = getParameters(
paramType, Arrays.asList(paramAnnotations[i]), operation, classConsumes, methodConsumes,
jsonViewAnnotation);


for (Parameter p : resolvedParameter.parameters)
{
operationParameters.add(p);
}
if (resolvedParameter.requestBody != null)
{
// LOGGER.warn("Found request body param for " + paramType);
processRequestBody(
resolvedParameter.requestBody,
operation,
Expand All @@ -585,6 +616,8 @@ else if (StringUtils.isBlank(httpMethod) && subResource != null)
}
else if (resolvedParameter.formParameter != null)
{
// LOGGER.warn("Found request form param for " + paramType);

// collect params to use together as request
// Body
formParameters.add(resolvedParameter.formParameter);
Expand All @@ -596,7 +629,9 @@ else if (resolvedParameter.formParameter != null)
for (int i = 0; i < annotatedMethod.getParameterCount(); i++)
{
AnnotatedParameter param = annotatedMethod.getParameter(i);

final Type type = TypeFactory.defaultInstance().constructType(param.getParameterType(), cls);

io.swagger.v3.oas.annotations.Parameter paramAnnotation = AnnotationsUtils
.getAnnotation(io.swagger.v3.oas.annotations.Parameter.class, paramAnnotations[i]);
Type paramType = ParameterProcessor.getParameterType(paramAnnotation, true);
Expand All @@ -611,6 +646,7 @@ else if (resolvedParameter.formParameter != null)
paramType = type;
}
}

ResolvedParameter resolvedParameter = getParameters(
paramType, Arrays.asList(paramAnnotations[i]), operation, classConsumes, methodConsumes,
jsonViewAnnotation);
Expand Down Expand Up @@ -766,29 +802,39 @@ else if (resolvedParameter.formParameter != null)

return openAPI;
}

public boolean isOptionalType(JavaType propType) {
return Arrays.asList("com.google.common.base.Optional", "java.util.Optional")
.contains(propType.getRawClass().getCanonicalName());
}


public static Annotation[][] getParameterAnnotations(Method method)
{

Annotation[][] methodAnnotations = method.getParameterAnnotations();

LOGGER.warn("methodAnnotations length at start: " + methodAnnotations.length);

java.lang.reflect.Parameter[] params = method.getParameters();

List<Integer> filteredParameterIndices = new ArrayList<>();

for (int i = 0; i < params.length; i++)
{
Annotation[] paramAnnotations = methodAnnotations[i];

if (!params[i].getType().isAssignableFrom(io.sinistral.proteus.server.ServerRequest.class) && !params[i].getType().getName().startsWith("io.undertow"))
{
String annotationStrings = Arrays.stream(paramAnnotations).map(a -> a.annotationType().getName()).collect(Collectors.joining(" "));
// String annotationStrings = Arrays.stream(paramAnnotations).map(a -> a.annotationType().getName()).collect(Collectors.joining(" "));

LOGGER.debug("\nparameter: " + params[i] + " | name: " + params[i].getName() + " type: " + params[i].getType() + " -> " + annotationStrings);
// LOGGER.debug("\nparameter: " + params[i] + " | name: " + params[i].getName() + " type: " + params[i].getType() + " -> " + annotationStrings);

if (paramAnnotations.length == 0)
{
final String parameterName = params[i].getName();

LOGGER.debug("creating query parameter for " + parameterName);
// LOGGER.debug("creating query parameter for " + parameterName);

QueryParam queryParam = new QueryParam()
{
Expand All @@ -809,8 +855,20 @@ public Class<? extends Annotation> annotationType()
methodAnnotations[i] = new Annotation[] { queryParam };
}
}

else
{
filteredParameterIndices.add(i);
}
}

ArrayList<Annotation[]> annotations = Arrays.stream(methodAnnotations).collect(Collectors.toCollection(ArrayList::new));

for( int index : filteredParameterIndices )
{
annotations.remove(index);
}

methodAnnotations = annotations.stream().toArray(Annotation[][]::new);

Method overriddenmethod = ReflectionUtils.getOverriddenMethod(method);

Expand Down Expand Up @@ -876,6 +934,20 @@ protected void processRequestBody( Parameter requestBodyParameter, Operation ope
JsonView jsonViewAnnotation)
{

boolean isOptional = false;

if(type != null)
{
JavaType classType = TypeFactory.defaultInstance().constructType(type);

if(classType != null)
{
isOptional = isOptionalType(classType);
type = classType;
}
}


io.swagger.v3.oas.annotations.parameters.RequestBody requestBodyAnnotation = getRequestBody(Arrays.asList(paramAnnotations));
if (requestBodyAnnotation != null)
{
Expand Down Expand Up @@ -918,6 +990,7 @@ else if (StringUtils.isBlank(requestBody.get$ref()) &&
}
}
}
requestBody.setRequired(!isOptional);
operation.setRequestBody(requestBody);
}
}
Expand Down Expand Up @@ -952,6 +1025,7 @@ else if (StringUtils.isBlank(requestBody.get$ref()) &&
if (!isRequestBodyEmpty)
{
// requestBody.setExtensions(extensions);
requestBody.setRequired(!isOptional);
operation.setRequestBody(requestBody);
}
}
Expand Down Expand Up @@ -1154,7 +1228,7 @@ private Operation parseMethod(
}
if (apiParameters != null)
{

getParametersListFromAnnotation(
apiParameters.toArray(new io.swagger.v3.oas.annotations.Parameter[apiParameters.size()]),
classConsumes,
Expand All @@ -1166,6 +1240,7 @@ private Operation parseMethod(
// RequestBody in Method
if (apiRequestBody != null && operation.getRequestBody() == null)
{

OperationParser.getRequestBody(apiRequestBody, classConsumes, methodConsumes, components, jsonViewAnnotation).ifPresent(
operation::setRequestBody);
}
Expand All @@ -1179,6 +1254,7 @@ private Operation parseMethod(
// classResponses
if (classResponses != null && classResponses.length > 0)
{

OperationParser.getApiResponses(
classResponses,
classProduces,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public ResolvedParameter extractParameters(List<Annotation> annotations,

boolean isRequired = true;

if(_isOptionalType(javaType))
if(isOptionalType(javaType))
{
isRequired = false;
}
Expand Down Expand Up @@ -161,7 +161,6 @@ public ResolvedParameter extractParameters(List<Annotation> annotations,
}
for (Parameter p : parameters) {


Parameter processedParameter = ParameterProcessor.applyAnnotations(
p,
type,
Expand All @@ -172,14 +171,16 @@ public ResolvedParameter extractParameters(List<Annotation> annotations,
jsonViewAnnotation);

if (processedParameter != null) {
processedParameter.setRequired(isRequired);

extractParametersResult.parameters.add(processedParameter);
}
}


return extractParametersResult;
}

protected boolean _isOptionalType(JavaType propType) {
public boolean isOptionalType(JavaType propType) {
return Arrays.asList("com.google.common.base.Optional", "java.util.Optional")
.contains(propType.getRawClass().getCanonicalName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public RoutingHandler get()
.setCacheTime(assetsCacheTime)
));

this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withProduces("*/*").withPathTemplate(assetsPath).withControllerName("Assets").withMethod(Methods.GET).build());
this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withProduces("*/*").withPathTemplate(assetsPath).withControllerName(this.getClass().getSimpleName()).withMethod(Methods.GET).build());

return router;
}
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/io/sinistral/proteus/services/SwaggerService.java
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception

});

this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withPathTemplate(pathTemplate).withControllerName("Swagger").withMethod(Methods.GET).withProduces(MediaType.APPLICATION_JSON).build());
this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withPathTemplate(pathTemplate).withControllerName(this.getClass().getSimpleName()).withMethod(Methods.GET).withProduces(MediaType.APPLICATION_JSON).build());

/*
* YAML path
Expand Down Expand Up @@ -520,7 +520,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception

});

this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withPathTemplate(pathTemplate).withControllerName("Swagger").withMethod(Methods.GET).withProduces(io.sinistral.proteus.server.MediaType.TEXT_YAML.contentType()).build());
this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withPathTemplate(pathTemplate).withControllerName(this.getClass().getSimpleName()).withMethod(Methods.GET).withProduces(io.sinistral.proteus.server.MediaType.TEXT_YAML.contentType()).build());

pathTemplate = this.basePath + "/" + this.redocPath;

Expand All @@ -538,7 +538,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception
});


this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withPathTemplate(pathTemplate).withControllerName("Swagger").withMethod(Methods.GET).withProduces(MediaType.TEXT_HTML).build());
this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withPathTemplate(pathTemplate).withControllerName(this.getClass().getSimpleName()).withMethod(Methods.GET).withProduces(MediaType.TEXT_HTML).build());

pathTemplate = this.basePath;

Expand All @@ -556,7 +556,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception

});

this.registeredEndpoints.add(EndpointInfo.builder().withConsumes(MediaType.WILDCARD).withProduces(MediaType.TEXT_HTML).withPathTemplate(pathTemplate).withControllerName("Swagger").withMethod(Methods.GET).build());
this.registeredEndpoints.add(EndpointInfo.builder().withConsumes(MediaType.WILDCARD).withProduces(MediaType.TEXT_HTML).withPathTemplate(pathTemplate).withControllerName(this.getClass().getSimpleName()).withMethod(Methods.GET).build());


try
Expand Down Expand Up @@ -610,7 +610,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception



this.registeredEndpoints.add(EndpointInfo.builder().withConsumes(MediaType.WILDCARD).withProduces(MediaType.WILDCARD).withPathTemplate(pathTemplate).withControllerName("Swagger").withMethod(Methods.GET).build());
this.registeredEndpoints.add(EndpointInfo.builder().withConsumes(MediaType.WILDCARD).withProduces(MediaType.WILDCARD).withPathTemplate(pathTemplate).withControllerName(this.getClass().getSimpleName()).withMethod(Methods.GET).build());



Expand Down
Loading

0 comments on commit 34b5aa4

Please sign in to comment.