From fa44e86503828d4d0d0f673e0d6fbda3c10ec5ac Mon Sep 17 00:00:00 2001 From: Gustavo Martin Morcuende Date: Tue, 4 Oct 2016 18:24:45 +0200 Subject: [PATCH] Simple content negotiation XML and JSON --- pom.xml | 16 ++++- .../deserializers/AccountResourceDeserializer.java | 74 +++++++++++++++++++++ .../com/prueba/controllers/rest/ApiController.java | 77 ++++++---------------- .../serializers/AccountResourceSerializer.java | 67 +++++++++++++++++++ 4 files changed, 175 insertions(+), 59 deletions(-) create mode 100644 src/main/java/com/prueba/controllers/deserializers/AccountResourceDeserializer.java create mode 100644 src/main/java/com/prueba/controllers/serializers/AccountResourceSerializer.java diff --git a/pom.xml b/pom.xml index d963145..f194624 100644 --- a/pom.xml +++ b/pom.xml @@ -93,14 +93,26 @@ com.fasterxml.jackson.core jackson-databind 2.8.3 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.8.3 + + + org.codehaus.woodstox + woodstox-core-asl + 4.4.1 + org.rendersnake diff --git a/src/main/java/com/prueba/controllers/deserializers/AccountResourceDeserializer.java b/src/main/java/com/prueba/controllers/deserializers/AccountResourceDeserializer.java new file mode 100644 index 0000000..90c83a3 --- /dev/null +++ b/src/main/java/com/prueba/controllers/deserializers/AccountResourceDeserializer.java @@ -0,0 +1,74 @@ +package com.prueba.controllers.deserializers; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.prueba.model.domain.AccountResource; +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpExchange; + +public class AccountResourceDeserializer { + private static final String CONTENT_TYPE_HEADER = "Content-Type"; + private static final String CONTENT_TYPE_JSON = "application/json"; + private static final String CONTENT_TYPE_XML = "application/xml"; + + private final ObjectMapper jsonMapper = new ObjectMapper(); + private final ObjectMapper xmlMapper = new XmlMapper(); + + + public AccountResource deserializer(HttpExchange httpExchange) throws IOException { + final Headers headers = httpExchange.getRequestHeaders(); + final String contentType = headers.getFirst(CONTENT_TYPE_HEADER); + + AccountResource account = null; + if (contentType.equals(AccountResourceDeserializer.CONTENT_TYPE_JSON)) { + account = this.jsonDeserializer(httpExchange); + } + + if (contentType.equals(AccountResourceDeserializer.CONTENT_TYPE_XML)) { + account = this.xmlDeserializer(httpExchange); + } + + return account; + } + + protected AccountResource xmlDeserializer(HttpExchange httpExchange) throws IOException { + final String body = this.getBody(httpExchange); + + return xmlMapper.readValue(body, AccountResource.class); + } + + protected AccountResource jsonDeserializer(HttpExchange httpExchange) throws IOException { + final String body = this.getBody(httpExchange); + + return jsonMapper.readValue(body, AccountResource.class); + } + + protected String getBody (HttpExchange httpExchange) throws IOException { + try(final InputStream inputStream = httpExchange.getRequestBody(); + final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream()) { + + final int bufferSize = 1024; + final byte[] buffer = new byte[bufferSize]; + + int len = 0; + while ((len = inputStream.read(buffer)) != -1) { + byteBuffer.write(buffer, 0, len); + } + + return new String(byteBuffer.toByteArray(), Charset.forName("UTF-8")); + } + } + + public boolean isValidContentType(HttpExchange httpExchange) { + final Headers headers = httpExchange.getRequestHeaders(); + final String contentType = headers.getFirst(CONTENT_TYPE_HEADER); + + return null != contentType && (contentType.equals(CONTENT_TYPE_JSON) || + contentType.equals(CONTENT_TYPE_XML)); + } +} diff --git a/src/main/java/com/prueba/controllers/rest/ApiController.java b/src/main/java/com/prueba/controllers/rest/ApiController.java index f003452..a42140f 100644 --- a/src/main/java/com/prueba/controllers/rest/ApiController.java +++ b/src/main/java/com/prueba/controllers/rest/ApiController.java @@ -1,32 +1,28 @@ package com.prueba.controllers.rest; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; -import java.nio.charset.Charset; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.prueba.controllers.deserializers.AccountResourceDeserializer; +import com.prueba.controllers.serializers.AccountResourceSerializer; import com.prueba.core.context.util.AntPathMatcher; import com.prueba.model.domain.AccountResource; import com.prueba.services.impl.ApiServiceImpl; -import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; public class ApiController implements RestController { - private static final String CONTENT_TYPE_JSON = "application/json"; - private static final String CONTENT_TYPE_HEADER = "Content-Type"; private static final Logger LOGGER = LoggerFactory.getLogger(ApiController.class); private static final String USER_NAME_PARAM = "username"; private static final String API_URL_PATTERN = "/app/api/users/{" + USER_NAME_PARAM + "}"; - // Both are thread safe :) + // They are thread safe :) private final ApiServiceImpl apiService = new ApiServiceImpl(); - private final ObjectMapper mapper = new ObjectMapper(); + private final AccountResourceDeserializer accountDeserializer = new AccountResourceDeserializer(); + private final AccountResourceSerializer accountSerializer = new AccountResourceSerializer(); @Override public void handle(HttpExchange httpExchange) throws IOException { @@ -39,7 +35,7 @@ public class ApiController implements RestController { break; case "POST": - if (this.isJSONContentType(httpExchange)) { + if (accountDeserializer.isValidContentType(httpExchange)) { this.processPost(httpExchange); } else { httpExchange.sendResponseHeaders(415, 0); @@ -56,54 +52,35 @@ public class ApiController implements RestController { break; } } - - protected String getBody (HttpExchange httpExchange) throws IOException { - try(final InputStream inputStream = httpExchange.getRequestBody(); - final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream()) { - - final int bufferSize = 1024; - final byte[] buffer = new byte[bufferSize]; - - int len = 0; - while ((len = inputStream.read(buffer)) != -1) { - byteBuffer.write(buffer, 0, len); - } - - return new String(byteBuffer.toByteArray(), Charset.forName("UTF-8")); - } - } protected void processGet(HttpExchange httpExchange) throws IOException { - int statusCode = 404; - final String userNameParam = this.getSafeUserNameParam(httpExchange); + final String userNameParam = this.getSafeUserNameParam(httpExchange); + final AccountResource accountResource = apiService.findAccountByCode(userNameParam); - AccountResource account = apiService.findAccountByCode(userNameParam); - String bodyResponse = ""; - if (account != null) { + int statusCode = 404; + String serializedAccountResource = ""; + if (accountResource != null) { statusCode = 200; - bodyResponse = mapper.writeValueAsString(account); + serializedAccountResource = this.accountSerializer.serializer(httpExchange, accountResource); } - this.setJSONContentType(httpExchange); - httpExchange.sendResponseHeaders(statusCode, bodyResponse.length()); - + httpExchange.sendResponseHeaders(statusCode, serializedAccountResource.length()); try (final OutputStream os = httpExchange.getResponseBody()) { - os.write(bodyResponse.getBytes()); + os.write(serializedAccountResource.getBytes()); } } protected void processPost(HttpExchange httpExchange) throws IOException { - final String bodyRequest = getBody(httpExchange); - final AccountResource accountRequest = mapper.readValue(bodyRequest, AccountResource.class); + final AccountResource accountResource = accountDeserializer.deserializer(httpExchange); - apiService.createAccount(accountRequest); + apiService.createAccount(accountResource); - this.setJSONContentType(httpExchange); - - httpExchange.sendResponseHeaders(200, 0); + final String serializedAccountResource = + this.accountSerializer.serializer(httpExchange, accountResource); + httpExchange.sendResponseHeaders(200, 0); try (final OutputStream os = httpExchange.getResponseBody()) { - os.write(bodyRequest.getBytes()); + os.write(serializedAccountResource.getBytes()); } } @@ -115,20 +92,6 @@ public class ApiController implements RestController { httpExchange.sendResponseHeaders(204, 0); } - protected void setJSONContentType(HttpExchange httpExchange) { - final Headers headers = httpExchange.getResponseHeaders(); - - headers.remove(CONTENT_TYPE_HEADER); - headers.set(CONTENT_TYPE_HEADER, CONTENT_TYPE_JSON); - } - - protected boolean isJSONContentType(HttpExchange httpExchange) { - final Headers headers = httpExchange.getRequestHeaders(); - final String contentType = headers.getFirst(CONTENT_TYPE_HEADER); - - return null != contentType && contentType.equals(CONTENT_TYPE_JSON); - } - protected String getSafeUserNameParam(HttpExchange httpExchange) { final String uri = httpExchange.getRequestURI().toString(); final AntPathMatcher pathMatcher = new AntPathMatcher(); diff --git a/src/main/java/com/prueba/controllers/serializers/AccountResourceSerializer.java b/src/main/java/com/prueba/controllers/serializers/AccountResourceSerializer.java new file mode 100644 index 0000000..3eac8e0 --- /dev/null +++ b/src/main/java/com/prueba/controllers/serializers/AccountResourceSerializer.java @@ -0,0 +1,67 @@ +package com.prueba.controllers.serializers; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.prueba.model.domain.AccountResource; +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpExchange; + +public class AccountResourceSerializer { + private static final String CONTENT_TYPE_HEADER = "Content-Type"; + private static final String ACCEPT_HEADER = "Accept"; + private static final String CONTENT_TYPE_JSON = "application/json"; + private static final String CONTENT_TYPE_XML = "application/xml"; + + + private final ObjectMapper jsonMapper = new ObjectMapper(); + private final ObjectMapper xmlMapper = new XmlMapper(); + + + public String serializer(HttpExchange httpExchange, AccountResource accountResource) throws IOException { + final Headers headers = httpExchange.getRequestHeaders(); + final String accept = headers.getFirst(ACCEPT_HEADER); + + String serializedAccount = ""; + if (accept.equals(AccountResourceSerializer.CONTENT_TYPE_JSON)) { + serializedAccount = this.jsonSerializer(accountResource); + + this.setJSONContentType(httpExchange, CONTENT_TYPE_JSON); + } + + if (accept.equals(AccountResourceSerializer.CONTENT_TYPE_XML)) { + serializedAccount = this.xmlSerializer(accountResource); + + this.setJSONContentType(httpExchange, CONTENT_TYPE_XML); + } + + return serializedAccount; + } + + protected String xmlSerializer(AccountResource accountResource) throws IOException { + + return xmlMapper.writeValueAsString(accountResource); + } + + protected String jsonSerializer(AccountResource accountResource) throws JsonProcessingException { + + return jsonMapper.writeValueAsString(accountResource); + } + + protected void setJSONContentType(HttpExchange httpExchange, String contentType) { + final Headers headers = httpExchange.getResponseHeaders(); + + headers.remove(CONTENT_TYPE_HEADER); + headers.set(CONTENT_TYPE_HEADER, contentType); + } + + public boolean isValidContentType(HttpExchange httpExchange) { + final Headers headers = httpExchange.getRequestHeaders(); + final String contentType = headers.getFirst(CONTENT_TYPE_HEADER); + + return null != contentType && (contentType.equals(CONTENT_TYPE_JSON) || + contentType.equals(CONTENT_TYPE_XML)); + } +} -- 2.1.4