Index: src/main/resources/fxml/mainScene.fxml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/main/resources/fxml/mainScene.fxml	(revision dbc9c10b8a607e7ff939f603db97dae122bcc29b)
+++ src/main/resources/fxml/mainScene.fxml	(date 1544789099034)
@@ -223,7 +223,11 @@
                         </Tab>
                         <Tab text="Value">
                             <content>
-                                <TextArea fx:id="valueTextArea" editable="false" prefHeight="200.0" prefWidth="200.0"/>
+                                <HBox>
+                                    <TreeView fx:id="jsonTreeView" prefHeight="200.0" prefWidth="400.0"/>
+                                    <TextArea fx:id="valueTextArea" editable="false" prefHeight="200.0"
+                                              prefWidth="200.0" HBox.hgrow="ALWAYS"/>
+                                </HBox>
                             </content>
                         </Tab>
                         <Tab text="Header">
Index: src/main/java/com/modulo/kafkaesque/Controller.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/main/java/com/modulo/kafkaesque/Controller.java	(revision dbc9c10b8a607e7ff939f603db97dae122bcc29b)
+++ src/main/java/com/modulo/kafkaesque/Controller.java	(date 1544789994257)
@@ -100,6 +100,8 @@
     @FXML
     private TextArea valueTextArea;
     @FXML
+    public TreeView<String> jsonTreeView;
+    @FXML
     private TableView<Header> headerTableView;
     @FXML
     private TableColumn<Header, String> headerKeyColumn;
@@ -250,24 +252,20 @@
         }
         headerTableView.setItems(selectedMessage.getHeaders());
         if (formatJson) {
-            keyTextArea.setText(formatJson(selectedMessage.getKey()));
-            valueTextArea.setText(formatJson(selectedMessage.getValue()));
+            keyTextArea.setText(JsonUtils.formatJson(selectedMessage.getKey()));
+            valueTextArea.setText(JsonUtils.formatJson(selectedMessage.getValue()));
+            try {
+                TreeItem<String> root = JsonUtils.buildTreeFromJson(selectedMessage.getValue());
+                jsonTreeView.setRoot(root);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
         } else {
             keyTextArea.setText(selectedMessage.getKey());
             valueTextArea.setText(selectedMessage.getValue());
         }
     }
 
-    /* TODO can be extracted to a JsonUtil */
-    private String formatJson(String string) {
-        try {
-            Object jsonObject = string == null ? null : objectMapper.readValue(string, Object.class);
-            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
-        } catch (Exception e) {
-            return String.format("%s%s[Formatting Error: %s]", string, System.lineSeparator(), e.getMessage());
-        }
-    }
-
     private void setupClusterCombobox() {
         ListCell<ClusterConfig> buttonCell = new ListCell<ClusterConfig>() {
             @Override
@@ -952,7 +950,7 @@
             String identifier = matcher.group("identifier");
             String type = matcher.group("type");
 
-            Object replacement;
+            Serializable replacement;
             switch (type) {
                 case "UUID":
                     replacement = UUID.randomUUID();
Index: src/main/java/com/modulo/kafkaesque/JsonUtils.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/main/java/com/modulo/kafkaesque/JsonUtils.java	(revision dbc9c10b8a607e7ff939f603db97dae122bcc29b)
+++ src/main/java/com/modulo/kafkaesque/JsonUtils.java	(date 1544789963178)
@@ -1,24 +1,89 @@
 package com.modulo.kafkaesque;
 
+import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import javafx.scene.control.TreeItem;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Set;
 
-public final class JsonUtils {
+final class JsonUtils {
     private JsonUtils() {
     }
 
-    public static ValidationResult validate(String jsonInString) {
+    private static final ObjectMapper objectMapper;
+
+    static {
+        objectMapper = new ObjectMapper();
+    }
+
+    static String formatJson(String string) {
+        try {
+            Object jsonObject = string == null ? null : objectMapper.readValue(string, Object.class);
+            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject);
+        } catch (Exception e) {
+            return String.format("%s%s[Formatting Error: %s]", string, System.lineSeparator(), e.getMessage());
+        }
+    }
+
+    static ValidationResult validate(String jsonInString) {
         if (jsonInString == null) {
             return new ValidationResult(true);
         }
 
         try {
-            final ObjectMapper mapper = new ObjectMapper();
-            mapper.readTree(jsonInString);
+            objectMapper.readTree(jsonInString);
             return new ValidationResult(true);
         } catch (IOException e) {
             return new ValidationResult(false, e.getMessage());
         }
     }
+
+    static TreeItem<String> buildTreeFromJson(String value) throws IOException {
+        Map<String, Object> json = objectMapper.readValue(value, new TypeReference<Map<String, Object>>() {
+        });
+        TreeItem<String> root = new TreeItem<>("root");
+        root.setExpanded(true);
+        recursivelyAddElements(json, root);
+        return root;
+    }
+
+    private static void recursivelyAddElements(Map<String, Object> jsonNode, TreeItem<String> treeItem) {
+        Set<Map.Entry<String, Object>> entries = jsonNode.entrySet();
+
+        if (!entries.isEmpty()) {
+            for (Map.Entry<String, Object> entry : entries) {
+                TreeItem<String> newItem = new TreeItem<>(entry.getKey());
+                treeItem.getChildren().add(newItem);
+                applyCorrectAdder(entry.getValue(), newItem);
+            }
+        }
+    }
+
+    private static void recursivelyAddElements(ArrayList values, TreeItem<String> treeItem) {
+        int i = 1;
+        for (Object val : values) {
+            TreeItem<String> newItem = new TreeItem<>(i + "");
+            treeItem.getChildren().add(newItem);
+            treeItem.setExpanded(true);
+            applyCorrectAdder(val, newItem);
+            i++;
+        }
+    }
+
+    private static void recursivelyAddElements(String val, TreeItem<String> treeItem) {
+        treeItem.setValue(treeItem.getValue() + ": " + val);
+    }
+
+    private static void applyCorrectAdder(Object value, TreeItem<String> treeItem) {
+        if (value instanceof Map) {
+            recursivelyAddElements((Map<String, Object>) value, treeItem);
+        } else if (value instanceof ArrayList) {
+            recursivelyAddElements((ArrayList) value, treeItem);
+        } else {
+            recursivelyAddElements((String.valueOf(value)), treeItem);
+        }
+    }
 }
