Simple content negotiation
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Tue, 4 Oct 2016 16:24:45 +0000 (18:24 +0200)
committerGustavo Martin Morcuende <gu.martinm@gmail.com>
Tue, 4 Oct 2016 16:25:20 +0000 (18:25 +0200)
XML and JSON

pom.xml
src/main/java/com/prueba/controllers/deserializers/AccountResourceDeserializer.java [new file with mode: 0644]
src/main/java/com/prueba/controllers/rest/ApiController.java
src/main/java/com/prueba/controllers/serializers/AccountResourceSerializer.java [new file with mode: 0644]

diff --git a/pom.xml b/pom.xml
index d963145..f194624 100644 (file)
--- a/pom.xml
+++ b/pom.xml
 
 
         <!--
-            Jackson JSON Processor, required by spring-webmvc. See messageConverters
-            in rest-config.xml
+            Jackson JSON Processor.
         -->
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
             <version>2.8.3</version>
         </dependency>
+        <!--
+            Jackson XML Processor.
+        -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-xml</artifactId>
+            <version>2.8.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.woodstox</groupId>
+            <artifactId>woodstox-core-asl</artifactId>
+            <version>4.4.1</version>
+        </dependency>
 
         <dependency>
             <groupId>org.rendersnake</groupId>
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 (file)
index 0000000..90c83a3
--- /dev/null
@@ -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));
+       }
+}
index f003452..a42140f 100644 (file)
@@ -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 (file)
index 0000000..3eac8e0
--- /dev/null
@@ -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));
+       }
+}