From d07ad9fbb821aed1b6e8227241e09b95006cae4c Mon Sep 17 00:00:00 2001 From: tommelo Date: Sat, 19 Aug 2017 10:25:31 -0300 Subject: [PATCH 1/7] Changed the request body attribute type from Map to Object. Fixes gh-11 --- .../com/tdsis/lambda/forest/domain/LambdaRequestSpec.java | 6 +++--- .../java/br/com/tdsis/lambda/forest/util/LambdaRunner.java | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/br/com/tdsis/lambda/forest/domain/LambdaRequestSpec.java b/src/main/java/br/com/tdsis/lambda/forest/domain/LambdaRequestSpec.java index 2f456dd..eefa3b6 100644 --- a/src/main/java/br/com/tdsis/lambda/forest/domain/LambdaRequestSpec.java +++ b/src/main/java/br/com/tdsis/lambda/forest/domain/LambdaRequestSpec.java @@ -26,7 +26,7 @@ public class LambdaRequestSpec { private String path; private String method; private Map headers; - private Map body; + private Object body; private Map pathParameters; private Map queryStringParameters; private Map stageVariables; @@ -111,7 +111,7 @@ public void setHeaders(Map headers) { * * @return body The request body */ - public Map getBody() { + public Object getBody() { return body; } @@ -120,7 +120,7 @@ public Map getBody() { * * @param body The request body */ - public void setBody(Map body) { + public void setBody(Object body) { this.body = body; } diff --git a/src/main/java/br/com/tdsis/lambda/forest/util/LambdaRunner.java b/src/main/java/br/com/tdsis/lambda/forest/util/LambdaRunner.java index 48e8d72..383cd8e 100644 --- a/src/main/java/br/com/tdsis/lambda/forest/util/LambdaRunner.java +++ b/src/main/java/br/com/tdsis/lambda/forest/util/LambdaRunner.java @@ -155,8 +155,11 @@ private static HttpRequest buildHttpRequest(LambdaRequestSpec requestSpec) throw String resource = requestSpec.getResource(); String path = requestSpec.getPath(); - String method = requestSpec.getMethod(); - String json = MAPPER.writeValueAsString(requestSpec.getBody()); + String method = requestSpec.getMethod(); + + Object body = requestSpec.getBody(); + String json = body instanceof String ? body.toString() : MAPPER.writeValueAsString(body); + Map headers = requestSpec.getHeaders(); Map pathParameters = requestSpec.getPathParameters(); Map queryStringParameters = requestSpec.getQueryStringParameters(); From 12598ba7680e47443788a567c9a9686fe873a140 Mon Sep 17 00:00:00 2001 From: tommelo Date: Sat, 19 Aug 2017 10:48:47 -0300 Subject: [PATCH 2/7] Added a XML Deserializer/Serializer. Fixes gh-12 --- pom.xml | 6 +++ .../forest/http/DeserializerStrategy.java | 11 +++- .../forest/http/SerializerStrategy.java | 10 +++- .../XmlRequestBodyDeserializerStrategy.java | 52 +++++++++++++++++++ .../XmlResponseBodySerializerStrategy.java | 38 ++++++++++++++ ...mlRequestBodyDeserializerStrategyTest.java | 51 ++++++++++++++++++ 6 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 src/main/java/br/com/tdsis/lambda/forest/xml/XmlRequestBodyDeserializerStrategy.java create mode 100644 src/main/java/br/com/tdsis/lambda/forest/xml/XmlResponseBodySerializerStrategy.java create mode 100644 src/test/java/br/com/tdsis/lambda/forest/xml/XmlRequestBodyDeserializerStrategyTest.java diff --git a/pom.xml b/pom.xml index acb25b2..409baf9 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,7 @@ 5.2.1.Final 2.2.4 2.2.4 + 2.9.0 4.12 1.10.19 1.6.7 @@ -116,6 +117,11 @@ javax.el ${javax.el.version} + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + ${jackson.dataformat.xm.version} + junit junit diff --git a/src/main/java/br/com/tdsis/lambda/forest/http/DeserializerStrategy.java b/src/main/java/br/com/tdsis/lambda/forest/http/DeserializerStrategy.java index 883f217..21564e6 100644 --- a/src/main/java/br/com/tdsis/lambda/forest/http/DeserializerStrategy.java +++ b/src/main/java/br/com/tdsis/lambda/forest/http/DeserializerStrategy.java @@ -7,6 +7,7 @@ import br.com.tdsis.lambda.forest.http.handler.AbstractRequestHandler; import br.com.tdsis.lambda.forest.json.JsonRequestBodyDeserializerStrategy; +import br.com.tdsis.lambda.forest.xml.XmlRequestBodyDeserializerStrategy; /** * The DeserializerStrategy enum @@ -16,6 +17,7 @@ * The current supported content type deserializers are: *
    *
  • {@code JsonRequestBodyDeserializerStrategy} for application/json
  • + *
  • {@code XmlRequestBodyDeserializerStrategy} for text/xml
  • *
*

* If a specific content type deserializer is not registered in this enum the @@ -28,9 +30,14 @@ public enum DeserializerStrategy { /** - * The Request body deserializer for content type application/json + * The request body deserializer for content type application/json */ - APPLICATION_JSON(ContentType.APPLICATION_JSON.getMimeType(), new JsonRequestBodyDeserializerStrategy()); + APPLICATION_JSON(ContentType.APPLICATION_JSON.getMimeType(), new JsonRequestBodyDeserializerStrategy()), + + /** + * The request body deserializer for contente type text/xml + */ + TEXT_XML(ContentType.TEXT_XML.getMimeType(), new XmlRequestBodyDeserializerStrategy()); private String contentType; private RequestBodyDeserializerStrategy deserializer; diff --git a/src/main/java/br/com/tdsis/lambda/forest/http/SerializerStrategy.java b/src/main/java/br/com/tdsis/lambda/forest/http/SerializerStrategy.java index bb6bce7..4bf13d7 100644 --- a/src/main/java/br/com/tdsis/lambda/forest/http/SerializerStrategy.java +++ b/src/main/java/br/com/tdsis/lambda/forest/http/SerializerStrategy.java @@ -7,6 +7,7 @@ import br.com.tdsis.lambda.forest.http.handler.AbstractRequestHandler; import br.com.tdsis.lambda.forest.json.JsonResponseBodySerializerStrategy; +import br.com.tdsis.lambda.forest.xml.XmlResponseBodySerializerStrategy; /** * The SerializerStrategy enum @@ -16,6 +17,7 @@ * The current supported serializers are: *

    *
  • {@code JsonResponseBodySerializerStrategy} for application/json
  • + *
  • {@code XmlResponseBodySerializerStrategy} for text/xml
  • *
*

* If a specific serializer is not registered in this enum the @@ -30,9 +32,13 @@ public enum SerializerStrategy { /** * The response body serializer for application/json */ - APPLICATION_JSON(ContentType.APPLICATION_JSON.getMimeType(), new JsonResponseBodySerializerStrategy()); - + APPLICATION_JSON(ContentType.APPLICATION_JSON.getMimeType(), new JsonResponseBodySerializerStrategy()), + /** + * The response body serializer for text/xml + */ + TEXT_XML(ContentType.TEXT_XML.getMimeType(), new XmlResponseBodySerializerStrategy()); + private String contentType; private ResponseBodySerializerStrategy serializer; diff --git a/src/main/java/br/com/tdsis/lambda/forest/xml/XmlRequestBodyDeserializerStrategy.java b/src/main/java/br/com/tdsis/lambda/forest/xml/XmlRequestBodyDeserializerStrategy.java new file mode 100644 index 0000000..3231f75 --- /dev/null +++ b/src/main/java/br/com/tdsis/lambda/forest/xml/XmlRequestBodyDeserializerStrategy.java @@ -0,0 +1,52 @@ +package br.com.tdsis.lambda.forest.xml; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +import br.com.tdsis.lambda.forest.domain.DefaultResponseError; +import br.com.tdsis.lambda.forest.http.RequestBodyDeserializerStrategy; +import br.com.tdsis.lambda.forest.http.exception.BadRequestException; +import br.com.tdsis.lambda.forest.http.exception.HttpException; +import br.com.tdsis.lambda.forest.http.exception.InternalServerErrorException; + +/** + * The XML request body deserializer strategy + * + * @author nmelo + */ +public class XmlRequestBodyDeserializerStrategy implements RequestBodyDeserializerStrategy { + + public static final String INVALID_XML_MESSAGE = "Invalid XML"; + public static final String INVALID_XML_ATTRIBUTE = "Invalid XML attribute: %s"; + + @Override + @SuppressWarnings("unchecked") + public T deserialize(String body, Class entityClass) throws HttpException { + XmlMapper mapper = new XmlMapper(); + + try { + + return (T) mapper.readValue(body, entityClass); + + } catch (JsonParseException e) { + throw new BadRequestException(new DefaultResponseError(INVALID_XML_MESSAGE)); + + } catch (JsonMappingException e) { + String message = INVALID_XML_MESSAGE; + + if (e instanceof UnrecognizedPropertyException){ + message = String.format(INVALID_XML_ATTRIBUTE, + ((UnrecognizedPropertyException) e).getPropertyName()); + } + + throw new BadRequestException(new DefaultResponseError(message)); + + } catch (Exception e) { + throw new InternalServerErrorException(e.getMessage(), e); + } + + } + +} diff --git a/src/main/java/br/com/tdsis/lambda/forest/xml/XmlResponseBodySerializerStrategy.java b/src/main/java/br/com/tdsis/lambda/forest/xml/XmlResponseBodySerializerStrategy.java new file mode 100644 index 0000000..fb1b935 --- /dev/null +++ b/src/main/java/br/com/tdsis/lambda/forest/xml/XmlResponseBodySerializerStrategy.java @@ -0,0 +1,38 @@ +package br.com.tdsis.lambda.forest.xml; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +import br.com.tdsis.lambda.forest.http.ResponseBodySerializerStrategy; +import br.com.tdsis.lambda.forest.http.exception.HttpException; +import br.com.tdsis.lambda.forest.http.exception.InternalServerErrorException; + +/** + * The XML response body serializer strategy + * + * @author nmelo + */ +public class XmlResponseBodySerializerStrategy implements ResponseBodySerializerStrategy { + + @Override + public String serialize(Object entity) throws HttpException { + String xml = null; + + try { + + XmlMapper mapper = new XmlMapper(); + mapper.setSerializationInclusion(Include.NON_NULL); + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + + xml = mapper.writeValueAsString(entity); + + } catch (JsonProcessingException e) { + throw new InternalServerErrorException(e.getMessage(), e); + } + + return xml; + } + +} diff --git a/src/test/java/br/com/tdsis/lambda/forest/xml/XmlRequestBodyDeserializerStrategyTest.java b/src/test/java/br/com/tdsis/lambda/forest/xml/XmlRequestBodyDeserializerStrategyTest.java new file mode 100644 index 0000000..9747695 --- /dev/null +++ b/src/test/java/br/com/tdsis/lambda/forest/xml/XmlRequestBodyDeserializerStrategyTest.java @@ -0,0 +1,51 @@ +package br.com.tdsis.lambda.forest.xml; + +import org.junit.Assert; +import org.junit.Test; + +import br.com.tdsis.lambda.forest.http.exception.BadRequestException; +import br.com.tdsis.lambda.forest.http.exception.HttpException; +import br.com.tdsis.lambda.forest.http.exception.InternalServerErrorException; +import br.com.tdsis.lambda.forest.http.handler.UserRequestTest; +import br.com.tdsis.lambda.forest.json.JsonRequestBodyDeserializerStrategy; + +public class XmlRequestBodyDeserializerStrategyTest { + + @Test(expected = BadRequestException.class) + public void shouldThrowBadRequestException() throws HttpException { + XmlRequestBodyDeserializerStrategy deserializer = new XmlRequestBodyDeserializerStrategy(); + deserializer.deserialize("any", UserRequestTest.class); + } + + @Test(expected = BadRequestException.class) + public void shouldThrowBadRequestExceptionWithUnrecognizedAttribute() throws HttpException { + XmlRequestBodyDeserializerStrategy deserializer = new XmlRequestBodyDeserializerStrategy(); + deserializer.deserialize("any", UserRequestTest.class); + } + + @Test(expected = BadRequestException.class) + public void shouldThrowBadRequestExceptionWithUnknownAttribute() throws HttpException { + JsonRequestBodyDeserializerStrategy deserializer = new JsonRequestBodyDeserializerStrategy(); + deserializer.deserialize("any", UserRequestTest.class); + } + + @Test(expected = InternalServerErrorException.class) + public void shouldThrowInternalServerErrorException() throws HttpException { + XmlRequestBodyDeserializerStrategy deserializer = new XmlRequestBodyDeserializerStrategy(); + deserializer.deserialize(null, UserRequestTest.class); + } + + @Test + public void shouldDeserializeBean() throws HttpException { + XmlRequestBodyDeserializerStrategy deserializer = new XmlRequestBodyDeserializerStrategy(); + UserRequestTest bean = deserializer + .deserialize("Any Name

Any Address
", + UserRequestTest.class); + + Assert.assertNotNull(bean); + Assert.assertEquals("Any Name", bean.getName()); + Assert.assertEquals("Any Address", bean.getAddress()); + } + + +} From a71df718c01e34f3d1e7e99ce2a13acbdb03ad3f Mon Sep 17 00:00:00 2001 From: Tom Melo Date: Sat, 19 Aug 2017 11:04:10 -0300 Subject: [PATCH 3/7] Update README.md --- README.md | 88 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 6784db1..453da75 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,16 @@ The deserialization and serialization strategies are based on two http headers: - **Content-Type** for deserialization - **Accept** for serialization +The current deserializers support: + + - **JSON** request body deserialization for **Content-Type: application/json** + - **XML** request body deserialization for **Content-Type: text/xml** + + and the current serializers support: + + - **JSON** response body serializer for **Accept: application/json** + - **XML** response body serializer for **Accept: text/xml** + If you want to provide your own request body deserializer, the method *resolveDeserializerStrategy* should be overridden: ```java @Override @@ -314,54 +324,54 @@ project ```json { - "context": { - "awsRequestId": "", - "logGroupName": "", - "logStreamName": "", - "functionName": "", - "functionVersion": "", - "invokedFunctionArn": "", - "identity": null, - "clientContext": { - "client": { - "installationId": "", - "appTitle": "", - "appVersionName": "", - "appVersionCode": "", - "appPackageName": "" - }, - "custom": { - - }, - "environment": { + "context": { + "awsRequestId": "", + "logGroupName": "", + "logStreamName": "", + "functionName": "", + "functionVersion": "", + "invokedFunctionArn": "", + "identity": null, + "clientContext": { + "client": { + "installationId": "", + "appTitle": "", + "appVersionName": "", + "appVersionCode": "", + "appPackageName": "" + }, + "custom": { - } }, - "remainingTimeInMillis": 30, - "memoryLimitInMB": 128, - "logger": null + "environment": { + + } + }, + "remainingTimeInMillis": 30, + "memoryLimitInMB": 128, + "logger": null }, "request":{ - "path": "/users", - "pathParameters": { + "path": "/users", + "pathParameters": { - }, - "queryStringParameters": { + }, + "queryStringParameters": { - }, - "resource": "users", - "stageVariables": { + }, + "resource": "users", + "stageVariables": { - }, - "method":"POST", - "headers": { + }, + "method":"POST", + "headers": { - }, - "body": { - "name": "my name", - "message": "This is my message" - } + }, + "body": { + "name": "my name", + "message": "This is my message" } + } } ``` From 34fa185785de5f19f4c5e438c8ab689b3d9fcd4d Mon Sep 17 00:00:00 2001 From: Tom Melo Date: Sat, 19 Aug 2017 11:05:35 -0300 Subject: [PATCH 4/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 453da75..988c5ee 100644 --- a/README.md +++ b/README.md @@ -349,7 +349,7 @@ project }, "remainingTimeInMillis": 30, "memoryLimitInMB": 128, - "logger": null + "logger": null }, "request":{ "path": "/users", From d281d5e3d282b3c2d7bb89cb99a105d5325a27e6 Mon Sep 17 00:00:00 2001 From: Filipe Santana Date: Mon, 21 Aug 2017 11:06:47 -0300 Subject: [PATCH 5/7] #2 Better pretty print in LambdaRunner --- .../lambda/forest/util/LambdaRunner.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/java/br/com/tdsis/lambda/forest/util/LambdaRunner.java b/src/main/java/br/com/tdsis/lambda/forest/util/LambdaRunner.java index 48e8d72..c55c1d8 100644 --- a/src/main/java/br/com/tdsis/lambda/forest/util/LambdaRunner.java +++ b/src/main/java/br/com/tdsis/lambda/forest/util/LambdaRunner.java @@ -2,10 +2,12 @@ import java.io.IOException; import java.io.InputStream; +import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -73,6 +75,32 @@ public RunnerResult printHeader(){ return this; } + /** + * + * Prints the execution response entity (headers, status code and response body). Pretty print body + * + * @return {@link RunnerResult} + * + * + */ + public RunnerResult prettyPrint(){ + try { + if(response == null){ + print(null); + return this; + } + Map resp = MAPPER.readValue(MAPPER.writeValueAsString(response), new TypeReference>() {}); + if(response.getBody() != null){ + Object body = MAPPER.readValue(response.getBody(), Object.class); + resp.put("body", body); + } + print(resp); + } catch (IOException e) { + e.printStackTrace(System.out); + } + return this; + } + /** * * Prints the execution response body From 01fe22e7f21b1b40c049a07647086d25f44a65f5 Mon Sep 17 00:00:00 2001 From: Filipe Date: Mon, 8 Oct 2018 16:03:05 -0300 Subject: [PATCH 6/7] 1.1.0-SNAPSHOT --- README.md | 10 +++++----- pom.xml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 988c5ee..ce48eb9 100644 --- a/README.md +++ b/README.md @@ -316,10 +316,10 @@ Eg.: ``` project -└───src -│ └───main -│ └───resources -│ lambda-spec.json +????????????src +??? ????????????main +??? ????????????resources +??? lambda-spec.json ``` ```json @@ -397,7 +397,7 @@ public class LambdaHandler extends AbstractRequestHandlerbr.com.tdsis lambda-forest - 1.0.0 + 1.1.0-SNAPSHOT jar lambda-forest From b8e9c1028ecc8b4b7c6d1708e737f11d630554f1 Mon Sep 17 00:00:00 2001 From: Filipe Date: Mon, 8 Oct 2018 16:10:50 -0300 Subject: [PATCH 7/7] 1.1.0-SNAPSHOT --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 1e58acc..64a3f1c 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,4 @@ - + 4.0.0 br.com.tdsis @@ -63,7 +62,8 @@ scm:git:git://github.com/tdsis/lambda-forest.git scm:git:ssh://github.com:tdsis/lambda-forest.git http://github.com/tdsis/lambda-forest/tree/master - + 1.1.0 +