Skip to content

Commit

Permalink
Improved test coverage.
Browse files Browse the repository at this point in the history
Default to query parameter type if none is specified.

Default to path parameter type if none is specified and this parameter
name is in the path.
  • Loading branch information
noboomu committed May 22, 2017
1 parent f9a307f commit 3a57213
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,83 @@
import java.lang.reflect.Parameter;

import javax.ws.rs.FormParam;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;

import io.swagger.annotations.ApiParam;
import io.swagger.annotations.Example;

/**
* @author jbauer
*
*/
public class AnnotationHelper
{
public static FormParam createFormParam(Parameter parameter){

return new FormParam(){

/* (non-Javadoc)
* @see javax.ws.rs.FormParam#value()
*/
@Override
public String value()
{
// TODO Auto-generated method stub
return parameter.getName();
}

@Override
public Class<? extends Annotation> annotationType()
{
return FormParam.class;
}


};
public static FormParam createFormParam(Parameter parameter)
{

return new FormParam()
{

@Override
public String value()
{
return parameter.getName();
}

@Override
public Class<? extends Annotation> annotationType()
{
return FormParam.class;
}

};
}

public static ApiParam createApiParam(Parameter parameter){

return new ApiParam(){

public static QueryParam createQueryParam(Parameter parameter)
{

return new QueryParam()
{

@Override
public String value()
{
return parameter.getName();
}

@Override
public Class<? extends Annotation> annotationType()
{
return QueryParam.class;
}
};
}

public static PathParam createPathParam(Parameter parameter)
{

return new PathParam()
{

@Override
public String value()
{
return parameter.getName();
}

@Override
public Class<? extends Annotation> annotationType()
{
return PathParam.class;
}
};
}

public static ApiParam createApiParam(Parameter parameter)
{

return new ApiParam()
{

@Override
public Class<? extends Annotation> annotationType()
Expand All @@ -54,7 +94,7 @@ public Class<? extends Annotation> annotationType()

@Override
public String name()
{
{
return parameter.getName();
}

Expand All @@ -81,7 +121,7 @@ public String allowableValues()

@Override
public boolean required()
{
{
return !parameter.getParameterizedType().getTypeName().contains("java.util.Optional");
}

Expand Down Expand Up @@ -154,7 +194,7 @@ public String collectionFormat()
// TODO Auto-generated method stub
return null;
}

};
}
}
71 changes: 54 additions & 17 deletions src/main/java/io/sinistral/proteus/server/swagger/Reader.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.ws.rs.Consumes;
import javax.ws.rs.HttpMethod;
Expand Down Expand Up @@ -101,6 +103,8 @@ public class Reader {
private static final Logger LOGGER = LoggerFactory.getLogger(Reader.class);
private static final String SUCCESSFUL_OPERATION = "successful operation";
private static final String PATH_DELIMITER = "/";
private static final Pattern PATH_PATTERN = Pattern.compile("\\{([^\\}]*?)\\}");


private final ReaderConfig config;
private Swagger swagger;
Expand Down Expand Up @@ -308,17 +312,37 @@ private Swagger read(Class<?> cls, String parentPath, String parentMethod, boole
String operationPath = getPath(apiPath, methodPath, parentPath);
Map<String, String> regexMap = new LinkedHashMap<>();
operationPath = PathUtils.parsePath(operationPath, regexMap);



if (operationPath != null) {
if (isIgnored(operationPath)) {
continue;
}

List<String> pathParamNames = new ArrayList<>();

Matcher m = PATH_PATTERN.matcher(operationPath);
while(m.find())
{
String pathParamName = m.group(1);
int bracketIndex = pathParamName.indexOf('[');

if(bracketIndex > -1)
{
pathParamName = pathParamName.substring(0, bracketIndex);
}

pathParamNames.add(pathParamName);
}


final ApiOperation apiOperation = ReflectionUtils.getAnnotation(method, ApiOperation.class);
String httpMethod = extractOperationMethod(apiOperation, method, SwaggerExtensions.chain());

Operation operation = null;
if (apiOperation != null || config.isScanAllResources() || httpMethod != null || methodPath != null) {
operation = parseMethod(cls, method, annotatedMethod, globalParameters, classApiResponses);
operation = parseMethod(cls, method, annotatedMethod, globalParameters, classApiResponses,pathParamNames);
}
if (operation == null) {
continue;
Expand Down Expand Up @@ -799,12 +823,12 @@ public Operation parseMethod(Method method) {
JavaType classType = TypeFactory.defaultInstance().constructType(method.getDeclaringClass());
BeanDescription bd = new ObjectMapper().getSerializationConfig().introspect(classType);
return parseMethod(classType.getClass(), method, bd.findMethod(method.getName(), method.getParameterTypes()),
Collections.<Parameter> emptyList(), Collections.<ApiResponse> emptyList());
Collections.<Parameter> emptyList(), Collections.<ApiResponse> emptyList(),Collections.emptyList());
}

@SuppressWarnings("deprecation")
private Operation parseMethod(Class<?> cls, Method method, AnnotatedMethod annotatedMethod,
List<Parameter> globalParameters, List<ApiResponse> classApiResponses) {
List<Parameter> globalParameters, List<ApiResponse> classApiResponses, List<String> pathParamNames) {
Operation operation = new Operation();
if (annotatedMethod != null) {
method = annotatedMethod.getAnnotated();
Expand All @@ -831,26 +855,21 @@ private Operation parseMethod(Class<?> cls, Method method, AnnotatedMethod annot
} else {
operationId = this.getOperationId(method.getName());
}

// LOGGER.debug("initial operationId: " + operationId + " nickname: " + apiOperation.nickname());


String responseContainer = null;

Type responseType = null;
Map<String, Property> defaultResponseHeaders = new LinkedHashMap<String, Property>();




if (apiOperation != null) {
if (apiOperation.hidden()) {
return null;
}
if (operationId == null) {
operationId = apiOperation.nickname();
}

// LOGGER.debug("operationId after nickname: " + operationId);

}

defaultResponseHeaders = parseResponseHeaders(apiOperation.responseHeaders());

operation.summary(apiOperation.value()).description(apiOperation.notes());
Expand Down Expand Up @@ -1030,7 +1049,7 @@ else if( responseCls.isAssignableFrom(CompletableFuture.class) )
}


List<Parameter> parameters = getParameters(type, Arrays.asList(paramAnnotations[i]), methodParameters[i]);
List<Parameter> parameters = getParameters(type, Arrays.asList(paramAnnotations[i]), methodParameters[i], pathParamNames);

for (Parameter parameter : parameters) {
operation.parameter(parameter);
Expand All @@ -1050,7 +1069,7 @@ else if( responseCls.isAssignableFrom(CompletableFuture.class) )



List<Parameter> parameters = getParameters(type, Arrays.asList(paramAnnotations[i]),methodParameters[i]);
List<Parameter> parameters = getParameters(type, Arrays.asList(paramAnnotations[i]),methodParameters[i],pathParamNames);

for (Parameter parameter : parameters) {

Expand Down Expand Up @@ -1102,7 +1121,7 @@ private void addResponse(Operation operation, ApiResponse apiResponse) {
}
}

private List<Parameter> getParameters(Type type, List<Annotation> annotations, java.lang.reflect.Parameter methodParameter) {
private List<Parameter> getParameters(Type type, List<Annotation> annotations, java.lang.reflect.Parameter methodParameter, List<String> pathParamNames) {
final Iterator<SwaggerExtension> chain = SwaggerExtensions.chain();


Expand All @@ -1126,11 +1145,11 @@ private List<Parameter> getParameters(Type type, List<Annotation> annotations, j


annotations = new ArrayList<>(annotations);


if(! annotations.stream().filter( a -> a instanceof ApiParam ).findFirst().isPresent() )
{
annotations.add( AnnotationHelper.createApiParam( methodParameter ) ) ;

annotations.add( AnnotationHelper.createApiParam( methodParameter ) ) ;
}


Expand All @@ -1144,6 +1163,24 @@ private List<Parameter> getParameters(Type type, List<Annotation> annotations, j
annotations.add(AnnotationHelper.createFormParam(methodParameter));

}

if(annotations.size() == 1)
{
if( annotations.get(0) instanceof ApiParam)
{
// If there is only one ApiParam and the parameter type is a member of the java.lang and the name of that parameter is in the path operation's path make the assumption that this is a path param
if(methodParameter.getType().getName().indexOf("java.lang") > -1 && pathParamNames.contains(methodParameter.getName()))
{
annotations.add(AnnotationHelper.createPathParam(methodParameter));

}
// If there is only one ApiParam and the parameter type is a member of the java.lang or java.util package we make the assumption that this is a query param
else if( methodParameter.getType().getName().indexOf("java.lang") > -1 || methodParameter.getType().getName().indexOf("java.util") > -1 )
{
annotations.add(AnnotationHelper.createQueryParam(methodParameter));
}
}
}

final List<Parameter> parameters = extension.extractParameters(annotations, type, typesToSkip, chain);
if (!parameters.isEmpty()) {
Expand Down
17 changes: 12 additions & 5 deletions src/test/java/io/sinistral/proteus/controllers/Tests.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,18 @@ public CompletableFuture<ServerResponse<ImmutableMap<String,String>>> responseFu
@Consumes("*/*")
@ApiOperation(value = "Upload file path endpoint", httpMethod = "POST" )
public ServerResponse<ByteBuffer> responseUploadFilePath(ServerRequest request, @FormParam("file") java.nio.file.Path file ) throws Exception
{

return response(ByteBuffer.wrap(Files.toByteArray(file.toFile()))).applicationOctetStream();


{
return response(ByteBuffer.wrap(Files.toByteArray(file.toFile()))).applicationOctetStream();
}

@POST
@Path("/response/json/echo")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@Consumes("*/*")
@ApiOperation(value = "Echo json endpoint", httpMethod = "POST" )
public ServerResponse<User> responseEchoJson(ServerRequest request, @FormParam("user") User user ) throws Exception
{
return response(user).applicationJson();
}

@POST
Expand Down
4 changes: 4 additions & 0 deletions src/test/java/io/sinistral/proteus/models/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,9 @@ public UserType getType()
return type;
}

public static User generateUser()
{
return new User((long)(Math.random()*1000)+1L, UserType.ADMIN);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.sinistral.proteus.models.User;
import io.sinistral.proteus.models.User.UserType;

/*
* import static io.restassured.RestAssured.*; import static io.restassured.matcher.RestAssuredMatchers.*; import static org.hamcrest.Matchers.*;
Expand Down Expand Up @@ -101,6 +102,15 @@ public void responsePlaintext()
{
given().accept(ContentType.TEXT).log().uri().when().get("tests/response/plaintext").then().statusCode(200).and().body(containsString("Hello, World!"));
}

@Test
public void responseEchoUser()
{
User user = new User(101L,UserType.ADMIN);

given().contentType(ContentType.JSON).accept(ContentType.JSON).body(user).log().uri().when().post("tests/response/json/echo").then().statusCode(200).and().body(containsString("101"));

}

@Test
public void responseFutureUser()
Expand Down

0 comments on commit 3a57213

Please sign in to comment.