diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e9206e..2b3cb85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Proteus Changelog. ## Unreleased ### No issue +**Added travis config.** + + +[d710f0f986d2a8e](https://github.com/noboomu/proteus/commit/d710f0f986d2a8e) Joshua Bauer *2019-09-17 21:32:50* + **Support for JsonView in OpenAPI.** diff --git a/core/pom.xml b/core/pom.xml index 8cd27a0..6f4fbbb 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -210,6 +210,12 @@ Proteus Changelog. 1.3.3 + + javax.validation + validation-api + 2.0.1.Final + + org.yaml snakeyaml diff --git a/core/src/main/java/io/sinistral/proteus/server/MediaType.java b/core/src/main/java/io/sinistral/proteus/server/MediaType.java index 5003c4d..3de9054 100644 --- a/core/src/main/java/io/sinistral/proteus/server/MediaType.java +++ b/core/src/main/java/io/sinistral/proteus/server/MediaType.java @@ -816,6 +816,8 @@ public class MediaType public static final MediaType APPLICATION_X_RESEARCH_INFO_SYSTEMS = create("application/x-research-info-systems", "RIS"); public static final MediaType APPLICATION_X_RUBY = create("application/x-ruby", "rb"); + public static final MediaType APPLICATION_X_WWW_FORM_URLENCODED = create("application/x-www-form-urlencoded"); + public static final MediaType APPLICATION_X_SCILAB = create("application/x-scilab", "sci", "sce"); public static final MediaType APPLICATION_X_SHAR = create("application/x-shar", "shar"); public static final MediaType APPLICATION_X_SHOCKWAVE_FLASH = create("application/x-shockwave-flash", "swf", "swfl"); @@ -1191,6 +1193,11 @@ public static synchronized MediaType create(String type, String[] attributes, St { MediaType mt = new MediaType(type, attributes); + if(fileExtensisons == null) + { + fileExtensisons = new String[]{}; + } + if(!Arrays.stream(attributes).anyMatch(a -> a.equals(UTF8_ATTR[0]))) { for (String ext : fileExtensisons) { FILE_EXTENSIONS.put(ext, mt); @@ -1202,6 +1209,11 @@ public static synchronized MediaType create(String type, String[] attributes, St public static synchronized MediaType createUTF8(String type, String... fileExtensisons) { + if(fileExtensisons == null) + { + fileExtensisons = new String[]{}; + } + for (String ext : fileExtensisons) { if(!FILE_EXTENSIONS.containsKey(ext)) { FILE_EXTENSIONS.put(ext, create(type, fileExtensisons)); diff --git a/core/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java b/core/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java index 91f4bf4..1d24e2d 100644 --- a/core/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java +++ b/core/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java @@ -399,6 +399,7 @@ protected void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class cla } } else { + producesContentTypes = Arrays.stream(producesAnnotation.get().value()).flatMap(v -> Arrays.stream((v.split(",")))).collect(Collectors.toList()); producesContentType = producesContentTypes.stream().collect(Collectors.joining(",")); diff --git a/core/src/main/java/io/sinistral/proteus/server/handlers/TypeHandler.java b/core/src/main/java/io/sinistral/proteus/server/handlers/TypeHandler.java index a9290d9..8e480ab 100644 --- a/core/src/main/java/io/sinistral/proteus/server/handlers/TypeHandler.java +++ b/core/src/main/java/io/sinistral/proteus/server/handlers/TypeHandler.java @@ -6,7 +6,10 @@ import com.squareup.javapoet.MethodSpec; import io.sinistral.proteus.server.handlers.HandlerGenerator.StatementParameterType; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; import javax.ws.rs.*; +import javax.ws.rs.core.Response; import java.lang.reflect.Parameter; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -160,10 +163,11 @@ public static void addStatement(MethodSpec.Builder builder, Parameter parameter, { Object[] args = new Object[handler.parameterTypes.length]; + String pName = parameter.getName(); for (int i = 0; i < handler.parameterTypes.length; i++) { if (handler.parameterTypes[i] instanceof StatementParameterType) { - String pName = parameter.getName(); + if (parameter.isAnnotationPresent(QueryParam.class)) { QueryParam qp = parameter.getAnnotation(QueryParam.class); @@ -215,6 +219,44 @@ public static void addStatement(MethodSpec.Builder builder, Parameter parameter, } builder.addStatement(handler.statement, args); + + Max max = parameter.isAnnotationPresent(Max.class) ? parameter.getAnnotationsByType(Max.class)[0] : null; + + Min min = parameter.isAnnotationPresent(Min.class) ? parameter.getAnnotationsByType(Min.class)[0] : null; + + + if(max != null || min != null) + { + if(max != null && min != null) + { + long maxValue = min.value(); + long minValue = min.value(); + + builder.beginControlFlow("if( $L < $L )", pName, minValue); + builder.addStatement("throw new io.sinistral.proteus.server.exceptions.ServerException($S,javax.ws.rs.core.Response.Status.BAD_REQUEST)",min.message().equals("{javax.validation.constraints.Min.message}") ? "must be greater than or equal to " + minValue : min.message()); + builder.endControlFlow(); + builder.beginControlFlow("else if( $L > $L )", pName, maxValue); + builder.addStatement("throw new io.sinistral.proteus.server.exceptions.ServerException($S,javax.ws.rs.core.Response.Status.BAD_REQUEST)",max.message().equals("{javax.validation.constraints.Max.message}") ? "must be less than or equal to " + maxValue : max.message()); + builder.endControlFlow(); + + } + else if(max != null) + { + long maxValue = max.value(); + + builder.beginControlFlow("if( $L > $L )", pName, maxValue); + builder.addStatement("throw new io.sinistral.proteus.server.exceptions.ServerException($S,javax.ws.rs.core.Response.Status.BAD_REQUEST)",max.message().equals("{javax.validation.constraints.Max.message}") ? "must be less than or equal to " + maxValue : max.message()); + builder.endControlFlow(); + } + else + { + long minValue = min.value(); + + builder.beginControlFlow("if( $L < $L )", pName, minValue); + builder.addStatement("throw new io.sinistral.proteus.server.exceptions.ServerException($S,javax.ws.rs.core.Response.Status.BAD_REQUEST)",min.message().equals("{javax.validation.constraints.Min.message}") ? "must be greater than or equal to " + minValue : min.message()); + builder.endControlFlow(); + } + } } /** @@ -298,6 +340,7 @@ public static TypeHandler forType(Type type, Boolean isBeanParam) } } + if (isSet && !isOptional) { try { Class erasedType = (Class) HandlerGenerator.extractErasedType(type); diff --git a/core/src/test/java/io/sinistral/proteus/test/controllers/Tests.java b/core/src/test/java/io/sinistral/proteus/test/controllers/Tests.java index 9bc524b..5fadf8d 100644 --- a/core/src/test/java/io/sinistral/proteus/test/controllers/Tests.java +++ b/core/src/test/java/io/sinistral/proteus/test/controllers/Tests.java @@ -19,6 +19,8 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; import javax.ws.rs.BeanParam; import javax.ws.rs.Consumes; import javax.ws.rs.FormParam; @@ -390,6 +392,22 @@ public ServerResponse notFoundError(ServerRequest request, @QueryParam("te } + @GET + @Path("response/max") + public ServerResponse maxValue(ServerRequest request, @QueryParam("param") @Max(100) Integer param ) throws Exception + { + return response().body(param.toString()); + + } + + + @GET + @Path("response/min") + public ServerResponse minValue(ServerRequest request, @QueryParam("param") @Min(10) Integer param ) throws Exception + { + return response().body(param.toString()); + + } @GET @Path("response/error/401") diff --git a/core/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java b/core/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java index ef93def..0efeb4d 100644 --- a/core/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java +++ b/core/src/test/java/io/sinistral/proteus/test/server/TestControllerEndpoints.java @@ -475,6 +475,34 @@ public void unauthorized() given().accept(ContentType.JSON).when().get("tests/response/error/401").then().statusCode(401).log().body().content(containsString("Unauthorized")); } + + @Test + public void maxValueError() + { + given().queryParam("param",105).when().get("tests/response/max").then().statusCode(400).log(); + + } + + @Test + public void minValueError() + { + given().queryParam("param",5).when().get("tests/response/min").then().statusCode(400).log(); + + } + @Test + public void maxValue() + { + given().queryParam("param",50).when().get("tests/response/max").then().statusCode(200).log(); + + } + + @Test + public void minValue() + { + given().queryParam("param",15).when().get("tests/response/min").then().statusCode(200).log(); + + } + @Test public void responseComplexParameters() @@ -485,7 +513,7 @@ public void responseComplexParameters() List integerList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); String stringValue = "TESTSTRING123!#$"; - Map map = given() + Map map = given() diff --git a/openapi/src/main/resources/io/sinistral/proteus/openapi/index.html b/openapi/src/main/resources/io/sinistral/proteus/openapi/index.html index 6d7ae21..d22c169 100644 --- a/openapi/src/main/resources/io/sinistral/proteus/openapi/index.html +++ b/openapi/src/main/resources/io/sinistral/proteus/openapi/index.html @@ -6,6 +6,7 @@ {{ title }} +