[NO ISSUE] Refactoring / cleanup

- Use shared ObjectMapper instance where possible for servlets
- Add StringUtil with camel-case conversion utility
- Serialize properties in alphabetical order when using JSONUtil

Change-Id: Idd1b805dfa425dcd87d83e361297a0351c56cc6a
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2033
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ActiveStatsApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ActiveStatsApiServlet.java
index 9e085a3..7e6d54b 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ActiveStatsApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ActiveStatsApiServlet.java
@@ -33,9 +33,7 @@
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-
 import io.netty.handler.codec.http.HttpResponseStatus;
 
 public class ActiveStatsApiServlet extends AbstractServlet {
@@ -67,9 +65,7 @@
         String localPath = localPath(request);
         int expireTime;
         IActiveEntityEventsListener[] listeners = activeNotificationHandler.getEventListeners();
-        ObjectMapper om = new ObjectMapper();
-        om.enable(SerializationFeature.INDENT_OUTPUT);
-        ObjectNode resNode = om.createObjectNode();
+        ObjectNode resNode = OBJECT_MAPPER.createObjectNode();
         PrintWriter responseWriter = response.writer();
         try {
             response.setStatus(HttpResponseStatus.OK);
@@ -81,10 +77,10 @@
             long currentTime = System.currentTimeMillis();
             for (int iter1 = 0; iter1 < listeners.length; iter1++) {
                 resNode.putPOJO(listeners[iter1].getDisplayName(),
-                        constructNode(om, listeners[iter1], currentTime, expireTime));
+                        constructNode(OBJECT_MAPPER, listeners[iter1], currentTime, expireTime));
             }
             // Construct Response
-            responseWriter.write(om.writerWithDefaultPrettyPrinter().writeValueAsString(resNode));
+            responseWriter.write(OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(resNode));
         } catch (Exception e) {
             LOGGER.log(Level.INFO, "exception thrown for " + request, e);
             response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java
index 3e1a16d..3f065ee 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java
@@ -39,7 +39,6 @@
 import org.apache.hyracks.http.server.utils.HttpUtil;
 import org.apache.hyracks.util.JSONUtil;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
@@ -57,7 +56,6 @@
     protected static final String FULL_SHUTDOWN_URI_KEY = "fullShutdownUri";
     protected static final String VERSION_URI_KEY = "versionUri";
     protected static final String DIAGNOSTICS_URI_KEY = "diagnosticsUri";
-    private final ObjectMapper om = new ObjectMapper();
     protected final ICcApplicationContext appCtx;
 
     public ClusterApiServlet(ICcApplicationContext appCtx, ConcurrentMap<String, Object> ctx, String... paths) {
@@ -117,7 +115,7 @@
         if (json.has("cc")) {
             cc = (ObjectNode) json.get("cc");
         } else {
-            cc = om.createObjectNode();
+            cc = OBJECT_MAPPER.createObjectNode();
             json.set("cc", cc);
         }
         cc.put(CONFIG_URI_KEY, clusterURL + "cc/config");
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterControllerDetailsApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterControllerDetailsApiServlet.java
index 15f28a4..1faa316 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterControllerDetailsApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterControllerDetailsApiServlet.java
@@ -32,7 +32,6 @@
 import org.apache.hyracks.http.api.IServletResponse;
 import org.apache.hyracks.http.server.utils.HttpUtil;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
 import io.netty.handler.codec.http.HttpResponseStatus;
@@ -40,7 +39,6 @@
 public class ClusterControllerDetailsApiServlet extends ClusterApiServlet {
 
     private static final Logger LOGGER = Logger.getLogger(ClusterControllerDetailsApiServlet.class.getName());
-    private final ObjectMapper om = new ObjectMapper();
 
     public ClusterControllerDetailsApiServlet(ICcApplicationContext appCtx, ConcurrentMap<String, Object> ctx,
             String... paths) {
@@ -60,7 +58,7 @@
                 json = processNode(request, hcc);
             }
             HttpUtil.setContentType(response, HttpUtil.ContentType.APPLICATION_JSON, HttpUtil.Encoding.UTF8);
-            responseWriter.write(new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(json));
+            responseWriter.write(OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(json));
         } catch (IllegalArgumentException e) { // NOSONAR - exception not logged or rethrown
             response.setStatus(HttpResponseStatus.NOT_FOUND);
         } catch (Exception e) {
@@ -83,9 +81,9 @@
         } else if (parts.length == 1) {
             switch (parts[0]) {
                 case "config":
-                    return om.readValue(hcc.getNodeDetailsJSON(null, false, true), ObjectNode.class);
+                    return OBJECT_MAPPER.readValue(hcc.getNodeDetailsJSON(null, false, true), ObjectNode.class);
                 case "stats":
-                    return om.readValue(hcc.getNodeDetailsJSON(null, true, false), ObjectNode.class);
+                    return OBJECT_MAPPER.readValue(hcc.getNodeDetailsJSON(null, true, false), ObjectNode.class);
                 case "threaddump":
                     return processCCThreadDump(hcc);
 
@@ -103,6 +101,6 @@
         if (dump == null) {
             throw new IllegalArgumentException();
         }
-        return (ObjectNode) om.readTree(dump);
+        return (ObjectNode) OBJECT_MAPPER.readTree(dump);
     }
 }
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ConnectorApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ConnectorApiServlet.java
index 52af643..b51187c 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ConnectorApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ConnectorApiServlet.java
@@ -77,8 +77,7 @@
         }
         PrintWriter out = response.writer();
         try {
-            ObjectMapper om = new ObjectMapper();
-            ObjectNode jsonResponse = om.createObjectNode();
+            ObjectNode jsonResponse = OBJECT_MAPPER.createObjectNode();
             String dataverseName = request.getParameter("dataverseName");
             String datasetName = request.getParameter("datasetName");
             if (dataverseName == null || datasetName == null) {
@@ -140,8 +139,7 @@
 
     private void formResponseObject(ObjectNode jsonResponse, FileSplit[] fileSplits, ARecordType recordType,
             String primaryKeys, boolean temp, Map<String, NodeControllerInfo> nodeMap) {
-        ObjectMapper om = new ObjectMapper();
-        ArrayNode partititons = om.createArrayNode();
+        ArrayNode partititons = OBJECT_MAPPER.createArrayNode();
         // Whether the dataset is temp or not
         jsonResponse.put("temp", temp);
         // Adds a primary key.
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/DiagnosticsApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/DiagnosticsApiServlet.java
index a631db0..3c58f30 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/DiagnosticsApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/DiagnosticsApiServlet.java
@@ -43,22 +43,17 @@
 import org.apache.hyracks.util.JSONUtil;
 
 import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.fasterxml.jackson.databind.node.TextNode;
-
 import io.netty.handler.codec.http.HttpResponseStatus;
 
 public class DiagnosticsApiServlet extends NodeControllerDetailsApiServlet {
     private static final Logger LOGGER = Logger.getLogger(DiagnosticsApiServlet.class.getName());
-    protected final ObjectMapper om;
     protected final IHyracksClientConnection hcc;
     protected final ExecutorService executor;
 
     public DiagnosticsApiServlet(ICcApplicationContext appCtx, ConcurrentMap<String, Object> ctx, String... paths) {
         super(appCtx, ctx, paths);
-        this.om = new ObjectMapper();
         this.hcc = (IHyracksClientConnection) ctx.get(HYRACKS_CONNECTION_ATTR);
         this.executor = (ExecutorService) ctx.get(ServletConstants.EXECUTOR_SERVICE_ATTR);
     }
@@ -68,7 +63,6 @@
         HttpUtil.setContentType(response, HttpUtil.ContentType.APPLICATION_JSON, HttpUtil.Encoding.UTF8);
         PrintWriter responseWriter = response.writer();
         response.setStatus(HttpResponseStatus.OK);
-        om.enable(SerializationFeature.INDENT_OUTPUT);
         try {
             if (!"".equals(localPath(request))) {
                 throw new IllegalArgumentException();
@@ -94,7 +88,7 @@
         for (String nc : csm.getParticipantNodes()) {
             ncDataMap.put(nc, getNcDiagnosticFutures(nc));
         }
-        ObjectNode result = om.createObjectNode();
+        ObjectNode result = OBJECT_MAPPER.createObjectNode();
         result.putPOJO("cc", resolveFutures(ccFutureData));
         List<Map<String, ?>> ncList = new ArrayList<>();
         for (Map.Entry<String, Map<String, Future<JsonNode>>> entry : ncDataMap.entrySet()) {
@@ -110,9 +104,11 @@
     protected Map<String, Future<JsonNode>> getNcDiagnosticFutures(String nc) {
         Map<String, Future<JsonNode>> ncData;
         ncData = new HashMap<>();
-        ncData.put("threaddump", executor.submit(() -> fixupKeys((ObjectNode) om.readTree(hcc.getThreadDump(nc)))));
+        ncData.put("threaddump",
+                executor.submit(() -> fixupKeys((ObjectNode) OBJECT_MAPPER.readTree(hcc.getThreadDump(nc)))));
         ncData.put("config",
-                executor.submit(() -> fixupKeys((ObjectNode) om.readTree(hcc.getNodeDetailsJSON(nc, false, true)))));
+                executor.submit(
+                        () -> fixupKeys((ObjectNode) OBJECT_MAPPER.readTree(hcc.getNodeDetailsJSON(nc, false, true)))));
         ncData.put("stats", executor.submit(() -> fixupKeys(processNodeStats(hcc, nc))));
         return ncData;
     }
@@ -121,11 +117,13 @@
         Map<String, Future<JsonNode>> ccFutureData;
         ccFutureData = new HashMap<>();
         ccFutureData.put("threaddump",
-                executor.submit(() -> fixupKeys((ObjectNode) om.readTree(hcc.getThreadDump(null)))));
+                executor.submit(() -> fixupKeys((ObjectNode) OBJECT_MAPPER.readTree(hcc.getThreadDump(null)))));
         ccFutureData.put("config",
-                executor.submit(() -> fixupKeys((ObjectNode) om.readTree(hcc.getNodeDetailsJSON(null, false, true)))));
+                executor.submit(() -> fixupKeys(
+                        (ObjectNode) OBJECT_MAPPER.readTree(hcc.getNodeDetailsJSON(null, false, true)))));
         ccFutureData.put("stats",
-                executor.submit(() -> fixupKeys((ObjectNode) om.readTree(hcc.getNodeDetailsJSON(null, true, false)))));
+                executor.submit(() -> fixupKeys(
+                        (ObjectNode) OBJECT_MAPPER.readTree(hcc.getNodeDetailsJSON(null, true, false)))));
         return ccFutureData;
     }
 
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NodeControllerDetailsApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NodeControllerDetailsApiServlet.java
index ee4812a..2c94f86 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NodeControllerDetailsApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/NodeControllerDetailsApiServlet.java
@@ -38,22 +38,17 @@
 import org.apache.hyracks.http.server.utils.HttpUtil;
 
 import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-
 import io.netty.handler.codec.http.HttpResponseStatus;
 
 public class NodeControllerDetailsApiServlet extends ClusterApiServlet {
 
     private static final Logger LOGGER = Logger.getLogger(NodeControllerDetailsApiServlet.class.getName());
-    private final ObjectMapper om = new ObjectMapper();
 
     public NodeControllerDetailsApiServlet(ICcApplicationContext appCtx, ConcurrentMap<String, Object> ctx,
             String... paths) {
         super(appCtx, ctx, paths);
-        om.enable(SerializationFeature.INDENT_OUTPUT);
     }
 
     @Override
@@ -64,13 +59,13 @@
             ObjectNode json;
             response.setStatus(HttpResponseStatus.OK);
             if ("".equals(localPath(request))) {
-                json = om.createObjectNode();
+                json = OBJECT_MAPPER.createObjectNode();
                 json.set("ncs", getClusterStateJSON(request, "../").get("ncs"));
             } else {
                 json = processNode(request, hcc);
             }
             HttpUtil.setContentType(response, HttpUtil.ContentType.APPLICATION_JSON, HttpUtil.Encoding.UTF8);
-            responseWriter.write(om.writerWithDefaultPrettyPrinter().writeValueAsString(json));
+            responseWriter.write(OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(json));
         } catch (IllegalStateException e) { // NOSONAR - exception not logged or rethrown
             response.setStatus(HttpResponseStatus.SERVICE_UNAVAILABLE);
         } catch (IllegalArgumentException e) { // NOSONAR - exception not logged or rethrown
@@ -99,7 +94,7 @@
                 }
             }
             if ("cc".equals(node)) {
-                return om.createObjectNode();
+                return OBJECT_MAPPER.createObjectNode();
             }
             throw new IllegalArgumentException();
         } else if (parts.length == 2) {
@@ -148,7 +143,7 @@
         if (details == null) {
             throw new IllegalArgumentException();
         }
-        ObjectNode json = (ObjectNode) om.readTree(details);
+        ObjectNode json = (ObjectNode) OBJECT_MAPPER.readTree(details);
         int index = json.get("rrd-ptr").asInt() - 1;
         json.remove("rrd-ptr");
 
@@ -178,10 +173,10 @@
                 }
             }
         }
-        ArrayNode gcs = om.createArrayNode();
+        ArrayNode gcs = OBJECT_MAPPER.createArrayNode();
 
         for (int i = 0; i < gcNames.size(); i++) {
-            ObjectNode gc = om.createObjectNode();
+            ObjectNode gc = OBJECT_MAPPER.createObjectNode();
             gc.set("name", gcNames.get(i));
             gc.set("collection-time", gcCollectionTimes.get(i).get(index));
             gc.set("collection-count", gcCollectionCounts.get(i).get(index));
@@ -198,12 +193,12 @@
         if (config == null) {
             throw new IllegalArgumentException();
         }
-        return (ObjectNode) om.readTree(config);
+        return (ObjectNode) OBJECT_MAPPER.readTree(config);
     }
 
     private ObjectNode processNodeThreadDump(IHyracksClientConnection hcc, String node) throws Exception {
         if ("cc".equals(node)) {
-            return om.createObjectNode();
+            return OBJECT_MAPPER.createObjectNode();
         }
         String dump = hcc.getThreadDump(node);
         if (dump == null) {
@@ -212,6 +207,6 @@
             ClusterPartition[] cp = csm.getNodePartitions(node);
             throw cp != null ? new IllegalStateException() : new IllegalArgumentException();
         }
-        return (ObjectNode) om.readTree(dump);
+        return (ObjectNode) OBJECT_MAPPER.readTree(dump);
     }
 }
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
index ad34d96..c4f58f6 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
@@ -308,7 +308,7 @@
         param.path = servletPath(request);
         if (HttpUtil.ContentType.APPLICATION_JSON.equals(contentType)) {
             try {
-                JsonNode jsonRequest = new ObjectMapper().readTree(HttpUtil.getRequestBody(request));
+                JsonNode jsonRequest = OBJECT_MAPPER.readTree(HttpUtil.getRequestBody(request));
                 param.statement = jsonRequest.get(Parameter.STATEMENT.str()).asText();
                 param.format = toLower(getOptText(jsonRequest, Parameter.FORMAT.str()));
                 param.pretty = getOptBoolean(jsonRequest, Parameter.PRETTY.str(), false);
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryWebInterfaceServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryWebInterfaceServlet.java
index c798a7c..db39c5e 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryWebInterfaceServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryWebInterfaceServlet.java
@@ -31,7 +31,6 @@
 import org.apache.hyracks.http.server.StaticResourceServlet;
 import org.apache.hyracks.http.server.utils.HttpUtil;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
 import io.netty.handler.codec.http.HttpResponseStatus;
@@ -61,8 +60,7 @@
         HttpUtil.setContentType(response, HttpUtil.ContentType.APPLICATION_JSON, HttpUtil.Encoding.UTF8);
         ExternalProperties externalProperties = appCtx.getExternalProperties();
         response.setStatus(HttpResponseStatus.OK);
-        ObjectMapper om = new ObjectMapper();
-        ObjectNode obj = om.createObjectNode();
+        ObjectNode obj = OBJECT_MAPPER.createObjectNode();
         try {
             PrintWriter out = response.writer();
             obj.put("api_port", String.valueOf(externalProperties.getAPIServerPort()));
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RebalanceApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RebalanceApiServlet.java
index 8536571..5bd3d3c 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RebalanceApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RebalanceApiServlet.java
@@ -53,7 +53,6 @@
 import org.apache.hyracks.http.server.AbstractServlet;
 import org.apache.hyracks.http.server.utils.HttpUtil;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
 import io.netty.handler.codec.http.HttpResponseStatus;
@@ -273,8 +272,7 @@
             }
         }
         PrintWriter out = response.writer();
-        ObjectMapper om = new ObjectMapper();
-        ObjectNode jsonResponse = om.createObjectNode();
+        ObjectNode jsonResponse = OBJECT_MAPPER.createObjectNode();
         jsonResponse.put("results", message);
         response.setStatus(status);
         out.write(jsonResponse.toString());
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
index ae5479d..3d00d88 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/RestApiServlet.java
@@ -56,7 +56,6 @@
 import org.apache.hyracks.http.server.utils.HttpUtil;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
 import io.netty.handler.codec.http.HttpMethod;
@@ -214,7 +213,7 @@
             String errorMessage = ResultUtil.buildParseExceptionMessage(pe, query);
             ObjectNode errorResp =
                     ResultUtil.getErrorResponse(2, errorMessage, "", ResultUtil.extractFullStackTrace(pe));
-            sessionOutput.out().write(new ObjectMapper().writeValueAsString(errorResp));
+            sessionOutput.out().write(OBJECT_MAPPER.writeValueAsString(errorResp));
         } catch (Exception e) {
             GlobalConfig.ASTERIX_LOGGER.log(Level.SEVERE, e.getMessage(), e);
             response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ShutdownApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ShutdownApiServlet.java
index 0fe6863..1731697 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ShutdownApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ShutdownApiServlet.java
@@ -38,7 +38,6 @@
 import org.apache.hyracks.http.server.utils.HttpUtil;
 import org.apache.hyracks.util.JSONUtil;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
@@ -78,8 +77,7 @@
             return;
         }
         response.setStatus(HttpResponseStatus.ACCEPTED);
-        ObjectMapper om = new ObjectMapper();
-        ObjectNode jsonObject = om.createObjectNode();
+        ObjectNode jsonObject = OBJECT_MAPPER.createObjectNode();
         try {
             jsonObject.put("status", "SHUTTING_DOWN");
             jsonObject.put("date", new Date().toString());
@@ -88,7 +86,7 @@
             for (int i = 0; i < ncs.size(); i++) {
                 ObjectNode nc = (ObjectNode) ncs.get(i);
                 String node = nc.get(NODE_ID_KEY).asText();
-                ObjectNode details = (ObjectNode) om.readTree(hcc.getNodeDetailsJSON(node, false, true));
+                ObjectNode details = (ObjectNode) OBJECT_MAPPER.readTree(hcc.getNodeDetailsJSON(node, false, true));
                 nc.set(PID, details.get(PID));
                 if (details.has(INI) && details.get(INI).has(NCSERVICE_PID)) {
                     nc.put(NCSERVICE_PID, details.get(INI).get(NCSERVICE_PID).asInt());
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/VersionApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/VersionApiServlet.java
index eeef8e8..81e0cfd 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/VersionApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/VersionApiServlet.java
@@ -33,7 +33,6 @@
 import org.apache.hyracks.http.server.AbstractServlet;
 import org.apache.hyracks.http.server.utils.HttpUtil;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
 import io.netty.handler.codec.http.HttpResponseStatus;
@@ -50,8 +49,7 @@
         response.setStatus(HttpResponseStatus.OK);
         ICcApplicationContext props = (ICcApplicationContext) ctx.get(ASTERIX_APP_CONTEXT_INFO_ATTR);
         Map<String, String> buildProperties = props.getBuildProperties().getAllProps();
-        ObjectMapper om = new ObjectMapper();
-        ObjectNode responseObject = om.createObjectNode();
+        ObjectNode responseObject = OBJECT_MAPPER.createObjectNode();
         for (Map.Entry<String, String> e : buildProperties.entrySet()) {
             responseObject.put(e.getKey(), e.getValue());
         }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_3/cluster_state_3.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_3/cluster_state_3.1.adm
index 14a00d0..a5f098f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_3/cluster_state_3.1.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_3/cluster_state_3.1.adm
@@ -3,11 +3,11 @@
     "node_id" : "asterix_nc1",
     "state" : "ACTIVE",
     "partitions" : [ {
-      "partition_id" : "partition_0",
-      "active" : true
+      "active" : true,
+      "partition_id" : "partition_0"
     }, {
-      "partition_id" : "partition_1",
-      "active" : true
+      "active" : true,
+      "partition_id" : "partition_1"
     } ],
     "configUri" : "http://127.0.0.1:19002/admin/cluster/node/asterix_nc1/config",
     "statsUri" : "http://127.0.0.1:19002/admin/cluster/node/asterix_nc1/stats",
@@ -16,11 +16,11 @@
     "node_id" : "asterix_nc2",
     "state" : "ACTIVE",
     "partitions" : [ {
-      "partition_id" : "partition_2",
-      "active" : true
+      "active" : true,
+      "partition_id" : "partition_2"
     }, {
-      "partition_id" : "partition_3",
-      "active" : true
+      "active" : true,
+      "partition_id" : "partition_3"
     } ],
     "configUri" : "http://127.0.0.1:19002/admin/cluster/node/asterix_nc2/config",
     "statsUri" : "http://127.0.0.1:19002/admin/cluster/node/asterix_nc2/stats",
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_4/cluster_state_4.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_4/cluster_state_4.1.adm
index 5e88f5c..1c555b3 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_4/cluster_state_4.1.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/api/cluster_state_4/cluster_state_4.1.adm
@@ -2,11 +2,11 @@
   "node_id" : "asterix_nc1",
   "state" : "ACTIVE",
   "partitions" : [ {
-    "partition_id" : "partition_0",
-    "active" : true
+    "active" : true,
+    "partition_id" : "partition_0"
   }, {
-    "partition_id" : "partition_1",
-    "active" : true
+    "active" : true,
+    "partition_id" : "partition_1"
   } ],
   "configUri" : "http://127.0.0.1:19002/admin/cluster/node/asterix_nc1/config",
   "statsUri" : "http://127.0.0.1:19002/admin/cluster/node/asterix_nc1/stats",
diff --git a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/MetadataReplicationIT.java b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/MetadataReplicationIT.java
index 7fe156a..809e815 100644
--- a/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/MetadataReplicationIT.java
+++ b/asterixdb/asterix-installer/src/test/java/org/apache/asterix/installer/test/MetadataReplicationIT.java
@@ -83,7 +83,7 @@
     public void before() throws Exception {
         LOGGER.info("Creating new instance...");
         AsterixInstallerIntegrationUtil.init(AsterixInstallerIntegrationUtil.LOCAL_CLUSTER_METADATA_ONLY_REP_PATH);
-        LOGGER.info("Instacne created.");
+        LOGGER.info("Instance created.");
         AsterixInstallerIntegrationUtil.transformIntoRequiredState(State.ACTIVE);
         LOGGER.info("Instance is in ACTIVE state.");
     }
diff --git a/asterixdb/asterix-installer/src/test/resources/integrationts/metadata_only_replication/results/metadata_recovery/metadata_node_recovery/metadata_node_recovery.cluster_state.4.adm b/asterixdb/asterix-installer/src/test/resources/integrationts/metadata_only_replication/results/metadata_recovery/metadata_node_recovery/metadata_node_recovery.cluster_state.4.adm
index 06e4d80..c327ecf 100644
--- a/asterixdb/asterix-installer/src/test/resources/integrationts/metadata_only_replication/results/metadata_recovery/metadata_node_recovery/metadata_node_recovery.cluster_state.4.adm
+++ b/asterixdb/asterix-installer/src/test/resources/integrationts/metadata_only_replication/results/metadata_recovery/metadata_node_recovery/metadata_node_recovery.cluster_state.4.adm
@@ -2,36 +2,36 @@
   "metadata_node" : "asterix_nc1",
   "partitions" : {
     "0" : {
-      "partitionId" : 0,
-      "nodeId" : "asterix_nc1",
-      "activeNodeId" : "asterix_nc1",
       "active" : false,
-      "pendingActivation" : false,
-      "iodeviceNum" : 0
+      "activeNodeId" : "asterix_nc1",
+      "iodeviceNum" : 0,
+      "nodeId" : "asterix_nc1",
+      "partitionId" : 0,
+      "pendingActivation" : false
     },
     "1" : {
-      "partitionId" : 1,
-      "nodeId" : "asterix_nc1",
-      "activeNodeId" : "asterix_nc1",
       "active" : false,
-      "pendingActivation" : false,
-      "iodeviceNum" : 1
+      "activeNodeId" : "asterix_nc1",
+      "iodeviceNum" : 1,
+      "nodeId" : "asterix_nc1",
+      "partitionId" : 1,
+      "pendingActivation" : false
     },
     "2" : {
-      "partitionId" : 2,
-      "nodeId" : "asterix_nc2",
-      "activeNodeId" : "asterix_nc2",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 0
+      "activeNodeId" : "asterix_nc2",
+      "iodeviceNum" : 0,
+      "nodeId" : "asterix_nc2",
+      "partitionId" : 2,
+      "pendingActivation" : false
     },
     "3" : {
-      "partitionId" : 3,
-      "nodeId" : "asterix_nc2",
-      "activeNodeId" : "asterix_nc2",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 1
+      "activeNodeId" : "asterix_nc2",
+      "iodeviceNum" : 1,
+      "nodeId" : "asterix_nc2",
+      "partitionId" : 3,
+      "pendingActivation" : false
     }
   },
   "state" : "UNUSABLE"
diff --git a/asterixdb/asterix-installer/src/test/resources/integrationts/metadata_only_replication/results/metadata_recovery/metadata_node_recovery/metadata_node_recovery.cluster_state.7.adm b/asterixdb/asterix-installer/src/test/resources/integrationts/metadata_only_replication/results/metadata_recovery/metadata_node_recovery/metadata_node_recovery.cluster_state.7.adm
index e0ec010..c0697b7 100644
--- a/asterixdb/asterix-installer/src/test/resources/integrationts/metadata_only_replication/results/metadata_recovery/metadata_node_recovery/metadata_node_recovery.cluster_state.7.adm
+++ b/asterixdb/asterix-installer/src/test/resources/integrationts/metadata_only_replication/results/metadata_recovery/metadata_node_recovery/metadata_node_recovery.cluster_state.7.adm
@@ -2,36 +2,36 @@
   "metadata_node" : "asterix_nc1",
   "partitions" : {
     "0" : {
-      "partitionId" : 0,
-      "nodeId" : "asterix_nc1",
-      "activeNodeId" : "asterix_nc1",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 0
+      "activeNodeId" : "asterix_nc1",
+      "iodeviceNum" : 0,
+      "nodeId" : "asterix_nc1",
+      "partitionId" : 0,
+      "pendingActivation" : false
     },
     "1" : {
-      "partitionId" : 1,
-      "nodeId" : "asterix_nc1",
-      "activeNodeId" : "asterix_nc1",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 1
+      "activeNodeId" : "asterix_nc1",
+      "iodeviceNum" : 1,
+      "nodeId" : "asterix_nc1",
+      "partitionId" : 1,
+      "pendingActivation" : false
     },
     "2" : {
-      "partitionId" : 2,
-      "nodeId" : "asterix_nc2",
-      "activeNodeId" : "asterix_nc2",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 0
+      "activeNodeId" : "asterix_nc2",
+      "iodeviceNum" : 0,
+      "nodeId" : "asterix_nc2",
+      "partitionId" : 2,
+      "pendingActivation" : false
     },
     "3" : {
-      "partitionId" : 3,
-      "nodeId" : "asterix_nc2",
-      "activeNodeId" : "asterix_nc2",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 1
+      "activeNodeId" : "asterix_nc2",
+      "iodeviceNum" : 1,
+      "nodeId" : "asterix_nc2",
+      "partitionId" : 3,
+      "pendingActivation" : false
     }
   },
   "state" : "ACTIVE"
diff --git a/asterixdb/asterix-installer/src/test/resources/integrationts/replication/results/failback/node_failback/node_failback.cluster_state.10.adm b/asterixdb/asterix-installer/src/test/resources/integrationts/replication/results/failback/node_failback/node_failback.cluster_state.10.adm
index e0ec010..c0697b7 100644
--- a/asterixdb/asterix-installer/src/test/resources/integrationts/replication/results/failback/node_failback/node_failback.cluster_state.10.adm
+++ b/asterixdb/asterix-installer/src/test/resources/integrationts/replication/results/failback/node_failback/node_failback.cluster_state.10.adm
@@ -2,36 +2,36 @@
   "metadata_node" : "asterix_nc1",
   "partitions" : {
     "0" : {
-      "partitionId" : 0,
-      "nodeId" : "asterix_nc1",
-      "activeNodeId" : "asterix_nc1",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 0
+      "activeNodeId" : "asterix_nc1",
+      "iodeviceNum" : 0,
+      "nodeId" : "asterix_nc1",
+      "partitionId" : 0,
+      "pendingActivation" : false
     },
     "1" : {
-      "partitionId" : 1,
-      "nodeId" : "asterix_nc1",
-      "activeNodeId" : "asterix_nc1",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 1
+      "activeNodeId" : "asterix_nc1",
+      "iodeviceNum" : 1,
+      "nodeId" : "asterix_nc1",
+      "partitionId" : 1,
+      "pendingActivation" : false
     },
     "2" : {
-      "partitionId" : 2,
-      "nodeId" : "asterix_nc2",
-      "activeNodeId" : "asterix_nc2",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 0
+      "activeNodeId" : "asterix_nc2",
+      "iodeviceNum" : 0,
+      "nodeId" : "asterix_nc2",
+      "partitionId" : 2,
+      "pendingActivation" : false
     },
     "3" : {
-      "partitionId" : 3,
-      "nodeId" : "asterix_nc2",
-      "activeNodeId" : "asterix_nc2",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 1
+      "activeNodeId" : "asterix_nc2",
+      "iodeviceNum" : 1,
+      "nodeId" : "asterix_nc2",
+      "partitionId" : 3,
+      "pendingActivation" : false
     }
   },
   "state" : "ACTIVE"
diff --git a/asterixdb/asterix-installer/src/test/resources/integrationts/replication/results/failback/node_failback/node_failback.cluster_state.5.adm b/asterixdb/asterix-installer/src/test/resources/integrationts/replication/results/failback/node_failback/node_failback.cluster_state.5.adm
index 2de5a55..15c200c 100644
--- a/asterixdb/asterix-installer/src/test/resources/integrationts/replication/results/failback/node_failback/node_failback.cluster_state.5.adm
+++ b/asterixdb/asterix-installer/src/test/resources/integrationts/replication/results/failback/node_failback/node_failback.cluster_state.5.adm
@@ -2,36 +2,36 @@
   "metadata_node" : "asterix_nc2",
   "partitions" : {
     "0" : {
-      "partitionId" : 0,
-      "nodeId" : "asterix_nc1",
-      "activeNodeId" : "asterix_nc2",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 0
+      "activeNodeId" : "asterix_nc2",
+      "iodeviceNum" : 0,
+      "nodeId" : "asterix_nc1",
+      "partitionId" : 0,
+      "pendingActivation" : false
     },
     "1" : {
-      "partitionId" : 1,
-      "nodeId" : "asterix_nc1",
-      "activeNodeId" : "asterix_nc2",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 1
+      "activeNodeId" : "asterix_nc2",
+      "iodeviceNum" : 1,
+      "nodeId" : "asterix_nc1",
+      "partitionId" : 1,
+      "pendingActivation" : false
     },
     "2" : {
-      "partitionId" : 2,
-      "nodeId" : "asterix_nc2",
-      "activeNodeId" : "asterix_nc2",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 0
+      "activeNodeId" : "asterix_nc2",
+      "iodeviceNum" : 0,
+      "nodeId" : "asterix_nc2",
+      "partitionId" : 2,
+      "pendingActivation" : false
     },
     "3" : {
-      "partitionId" : 3,
-      "nodeId" : "asterix_nc2",
-      "activeNodeId" : "asterix_nc2",
       "active" : true,
-      "pendingActivation" : false,
-      "iodeviceNum" : 1
+      "activeNodeId" : "asterix_nc2",
+      "iodeviceNum" : 1,
+      "nodeId" : "asterix_nc2",
+      "partitionId" : 3,
+      "pendingActivation" : false
     }
   },
   "state" : "ACTIVE"
diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOption.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOption.java
index b8e7635..ed6dcd0 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOption.java
+++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/config/IOption.java
@@ -20,8 +20,7 @@
 
 import java.util.function.Function;
 
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.text.WordUtils;
+import org.apache.hyracks.util.StringUtil;
 
 public interface IOption {
 
@@ -67,8 +66,8 @@
         return name().toLowerCase().replace("_", ".");
     }
 
-    default String json() {
-        return StringUtils.remove(WordUtils.capitalize("z" + name().toLowerCase(), '_').substring(1), '_');
+    default String camelCase() {
+        return StringUtil.toCamelCase(name());
     }
 
     default String toIniString() {
diff --git a/hyracks-fullstack/hyracks/hyracks-http/pom.xml b/hyracks-fullstack/hyracks/hyracks-http/pom.xml
index 09bf513..7d0ddb2 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/pom.xml
+++ b/hyracks-fullstack/hyracks/hyracks-http/pom.xml
@@ -71,5 +71,9 @@
       <artifactId>hyracks-util</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+    </dependency>
   </dependencies>
 </project>
\ No newline at end of file
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/AbstractServlet.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/AbstractServlet.java
index 30d599d..baba540 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/AbstractServlet.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/AbstractServlet.java
@@ -18,6 +18,9 @@
  */
 package org.apache.hyracks.http.server;
 
+import static com.fasterxml.jackson.databind.MapperFeature.SORT_PROPERTIES_ALPHABETICALLY;
+import static com.fasterxml.jackson.databind.SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS;
+
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.concurrent.ConcurrentMap;
@@ -29,12 +32,21 @@
 import org.apache.hyracks.http.api.IServletResponse;
 import org.apache.hyracks.http.server.utils.HttpUtil;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
 import io.netty.handler.codec.http.HttpHeaderNames;
 import io.netty.handler.codec.http.HttpMethod;
 import io.netty.handler.codec.http.HttpResponseStatus;
 
 public abstract class AbstractServlet implements IServlet {
     private static final Logger LOGGER = Logger.getLogger(AbstractServlet.class.getName());
+    protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+    static {
+        OBJECT_MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
+        OBJECT_MAPPER.configure(SORT_PROPERTIES_ALPHABETICALLY, true);
+        OBJECT_MAPPER.configure(ORDER_MAP_ENTRIES_BY_KEYS, true);
+    }
 
     protected final String[] paths;
     protected final ConcurrentMap<String, Object> ctx;
diff --git a/hyracks-fullstack/hyracks/hyracks-util/pom.xml b/hyracks-fullstack/hyracks/hyracks-util/pom.xml
index ea7779f..f728de9 100644
--- a/hyracks-fullstack/hyracks/hyracks-util/pom.xml
+++ b/hyracks-fullstack/hyracks/hyracks-util/pom.xml
@@ -68,6 +68,10 @@
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-lang3</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-collections4</artifactId>
+    </dependency>
   </dependencies>
 
 </project>
diff --git a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/JSONUtil.java b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/JSONUtil.java
index 0cb87dd..51855c6 100644
--- a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/JSONUtil.java
+++ b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/JSONUtil.java
@@ -26,6 +26,7 @@
 
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.MapperFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 
@@ -42,6 +43,7 @@
 
     static {
         SORTED_MAPPER.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
+        SORTED_MAPPER.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
     }
 
     public static String convertNode(final JsonNode node) throws JsonProcessingException {
diff --git a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/StringUtil.java b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/StringUtil.java
new file mode 100644
index 0000000..b457c79
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/StringUtil.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.hyracks.util;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.apache.commons.collections4.map.LRUMap;
+import org.apache.commons.lang3.text.WordUtils;
+
+public class StringUtil {
+    private static final Map<String, String> CAMEL_CACHE = Collections.synchronizedMap(new LRUMap<>(1024));
+    private static final Pattern SEPARATORS_PATTERN = Pattern.compile("[_\\-\\s]");
+
+    private StringUtil() {
+    }
+
+    public static String toCamelCase(String input) {
+        return CAMEL_CACHE.computeIfAbsent(input, s -> SEPARATORS_PATTERN
+                .matcher(WordUtils.capitalize("z" + s.toLowerCase(), '_', '-', ' ').substring(1)).replaceAll(""));
+    }
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ThreadDumpUtil.java b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ThreadDumpUtil.java
index ec1a0b2..221d4b0 100644
--- a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ThreadDumpUtil.java
+++ b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/ThreadDumpUtil.java
@@ -37,10 +37,13 @@
     private static final ObjectMapper om = new ObjectMapper();
     private static final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
 
-    private ThreadDumpUtil() {
+    static {
         om.enable(SerializationFeature.INDENT_OUTPUT);
     }
 
+    private ThreadDumpUtil() {
+    }
+
     public static String takeDumpJSONString() throws IOException {
         ObjectNode json = takeDumpJSON();
         return om.writerWithDefaultPrettyPrinter().writeValueAsString(json);
diff --git a/hyracks-fullstack/hyracks/hyracks-util/src/test/java/org/apache/hyracks/util/StringUtilTest.java b/hyracks-fullstack/hyracks/hyracks-util/src/test/java/org/apache/hyracks/util/StringUtilTest.java
new file mode 100644
index 0000000..e279968
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-util/src/test/java/org/apache/hyracks/util/StringUtilTest.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.hyracks.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class StringUtilTest {
+
+    @Test
+    public void camelCaseTest() {
+        testCamelCase("FOO_BAR", "fooBar");
+        testCamelCase("FOO BAr", "fooBar");
+        testCamelCase("FOO_Bar", "fooBar");
+        testCamelCase("FOO_Bar baz", "fooBarBaz");
+    }
+
+    private void testCamelCase(String input, String expected) {
+        Assert.assertEquals(expected, StringUtil.toCamelCase(input));
+        Assert.assertEquals(expected, StringUtil.toCamelCase(input));
+    }
+}