title: How do I marshall nested key,value pairs into JSON with Camel and Jackson library?
body: <p>I have a Java project that currently returns a map to Camel without any nested key,value pairs, and the Jackson library marshalls it just fine into JSON using the Jackson library.</p>
  
  <p>For example if I put the following two key,values into a demoMap:</p>
  
  <pre><code>Map&lt;String,String&gt; demoMap = new TreeMap&lt;String,String&gt;
  demoMap.put("key1","5");
  demoMap.put("key2","10");
  </code></pre>
  
  <p>I get the following JSON:</p>
  
  <pre><code>{"key1":"5","key2":"10"}
  </code></pre>
  
  <p>However, now some of my key,value entries will have an optional visibility that I need to put as a nested key value in my map.  Any key,values that don't have an optional visibility will use the default.  So, for example if I specify visibilities for key1, and key2, but not key3 I want to get JSON out that looks like this:</p>
  
  <pre><code>{"key1":"5",
   "key2":"10",
   "key3":"17",
   "visibility" : { "key1": "a&amp;b&amp;!c", "key2": "a&amp;b", "_default": "a" }
  }
  </code></pre>
  
  <p>How can I get Camel to marshall a Java object with nested key,value pairs?  I'm a visual learner, so a simple example would be helpful.</p>
  
  <p>I tried changing my Map to have a value as an object i.e.,:</p>
  
  <pre><code>Map&lt;String,Object&gt; demoMap = new TreeMap&lt;String,Object&gt;
  </code></pre>
  
  <p>and then tried adding nested key,values for some keys with an ArrayList using <a href="http://examples.javacodegeeks.com/core-java/json/jackson/convert-java-map-to-from-json-using-jackson-example/" rel="nofollow">http://examples.javacodegeeks.com/core-java/json/jackson/convert-java-map-to-from-json-using-jackson-example/</a> for reference, but realized that this just gives me a bunch of nested values under a key, not a bunch of nested key,value pairs.</p>
  
  <p>Even when I tried it for grins, I got an error from the Camel processor with a java.lang.ClassCastException stating java.util.ArrayList cannot be cast to java.lang.String</p>
  
  <p>And similarly when I tried to nest a Map inside my demoMap I got this ClassCastException:</p>
  
  <pre><code>3244 [hello.world.request.timer] ERROR org.apache.camel.processor.DefaultErrorHandler  - Failed delivery for exchangeId: e6518e39-89b7-435e-96d9-ce26811ac67e. Exhausted after delivery attempt: 1 caught: java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.String
  </code></pre>
  
  <p>So I know how NOT to do it. :-/</p>
  
  <p>I re-read the Camel JSON documentation at <a href="http://camel.apache.org/json.html" rel="nofollow">http://camel.apache.org/json.html</a> but as of this writing it doesn't specify an example with nested key,value pairs.  </p>
  
  <p>UPDATE: Based on feedback from Tom I created two Maps i.e.,</p>
  
  <pre><code>Map&lt;String,String&gt; keyvalues = new TreeMap&lt;String,String&gt;();
  Map&lt;String,String&gt; visibility = new TreeMap&lt;String,String&gt;();
  </code></pre>
  
  <p>Here is my class which I call SensorGenerator that loads a properties file into a Map:</p>
  
  <pre><code>package sample;
  
  import java.util.Map;
  import java.util.Properties;
  import java.util.TreeMap;
  
  import org.codehaus.jackson.annotate.JsonAnyGetter;
  import org.codehaus.jackson.annotate.JsonProperty;
  
  public class SensorGenerator {
  
      private Properties sourceProperties;
  
      // create a map of sensor keyvalues, and a map of sensor visibility
      Map&lt;String,String&gt; keyvalues = new TreeMap&lt;String,String&gt;();
      @JsonProperty
      Map&lt;String,String&gt; visibility = new TreeMap&lt;String,String&gt;();
  
      @JsonAnyGetter
      public Map&lt;String, String&gt; getKeyvalues() { 
  
          for (Object key : sourceProperties.keySet()) {
  
              // Separate out each of the field:datatype:visibility tuples as an entry in the
              // values array
              String[] values = sourceProperties.getProperty((String) key).split(
                      ",");
              // split the key between 'sensor' and the 'number' Ex: sensor1 -&gt; sensor,1
              String[] keyArray = key.toString().split("(?&lt;=([a-zA-Z]++))");
              String keyNumber = keyArray[1]; // grab the number to append for each sensor
  
              // define string buffer that appends sensor number for each sensor's
              // keys.  Ex: sensor1 would have s1make, s1makeDataType, etc.
              StringBuffer sensorNumberStringBuffer = new StringBuffer();
              sensorNumberStringBuffer.append("s");
              sensorNumberStringBuffer.append(keyNumber);
  
              // make, its data type, and visibility (with s# prefix)
              StringBuffer makeStringBuffer = new StringBuffer();
              makeStringBuffer.append(sensorNumberStringBuffer);
              makeStringBuffer.append("make");
              StringBuffer makeDataTypeStringBuffer = new StringBuffer();
              makeDataTypeStringBuffer.append(sensorNumberStringBuffer);
              makeDataTypeStringBuffer.append("makeDataType");
              StringBuffer makeVizStringBuffer = new StringBuffer();
              makeVizStringBuffer.append(sensorNumberStringBuffer);
              makeVizStringBuffer.append("makeViz");
  
              // model, its data type, and visibility (with s# prefix)
              StringBuffer modelStringBuffer = new StringBuffer();
              modelStringBuffer.append(sensorNumberStringBuffer);
              modelStringBuffer.append("model");
              StringBuffer modelDataTypeStringBuffer = new StringBuffer();
              modelDataTypeStringBuffer.append(sensorNumberStringBuffer);
              modelDataTypeStringBuffer.append("modelDataType");
              StringBuffer modelVizStringBuffer = new StringBuffer();
              modelVizStringBuffer.append(sensorNumberStringBuffer);
              modelVizStringBuffer.append("modelViz");
  
              // serialNumber, its data type, and visibility (with s# prefix)
              StringBuffer serialNumberStringBuffer = new StringBuffer();
              serialNumberStringBuffer.append(sensorNumberStringBuffer);
              serialNumberStringBuffer.append("serialNumber");
              StringBuffer serialNumberDataTypeStringBuffer = new StringBuffer();
              serialNumberDataTypeStringBuffer.append(sensorNumberStringBuffer);
              serialNumberDataTypeStringBuffer.append("serialNumberDataType");
              StringBuffer serialNumberVizStringBuffer = new StringBuffer();
              serialNumberVizStringBuffer.append(sensorNumberStringBuffer);
              serialNumberVizStringBuffer.append("serialNumberViz");
  
              // sensorType, its data type, and visibility (with s# prefix)
              StringBuffer sensorTypeStringBuffer = new StringBuffer();
              sensorTypeStringBuffer.append(sensorNumberStringBuffer);
              sensorTypeStringBuffer.append("sensorType");
              StringBuffer sensorTypeDataTypeStringBuffer = new StringBuffer();
              sensorTypeDataTypeStringBuffer.append(sensorNumberStringBuffer);
              sensorTypeDataTypeStringBuffer.append("sensorTypeDataType");
              StringBuffer sensorTypeVizStringBuffer = new StringBuffer();
              sensorTypeVizStringBuffer.append(sensorNumberStringBuffer);
              sensorTypeVizStringBuffer.append("sensorTypeViz");
  
              //  put all the field:datatype keyvalues for this sensor in the keyvalues map
              //  and visibilities in the visibility map
  
              // make, data type, and visibility
              keyvalues.put(makeStringBuffer.toString(), values[0].split(":")[0]);
              keyvalues.put(makeDataTypeStringBuffer.toString(), values[0].split(":")[1]);
              visibility.put(makeVizStringBuffer.toString(), values[0].split(":")[2]);
  
              // model, data type, and visibility
              keyvalues.put(modelStringBuffer.toString(), values[1].split(":")[0]);
              keyvalues.put(modelDataTypeStringBuffer.toString(), values[1].split(":")[1]);
              visibility.put(modelVizStringBuffer.toString(), values[1].split(":")[2]);
  
              // serialNumber, data type, and visibility
              keyvalues.put(serialNumberStringBuffer.toString(), values[2].split(":")[0]);
              keyvalues.put(serialNumberDataTypeStringBuffer.toString(), values[2].split(":")[1]);
              visibility.put(serialNumberVizStringBuffer.toString(), values[2].split(":")[2]);
  
              // sensorType, data type, and visibility
              keyvalues.put(sensorTypeStringBuffer.toString(), values[3].split(":")[0]);
              keyvalues.put(sensorTypeDataTypeStringBuffer.toString(), values[3].split(":")[1]);
              visibility.put(sensorTypeVizStringBuffer.toString(), values[3].split(":")[2]);
  
              // add in default visibility
              visibility.put("_default", "a");
  
          }
          return keyvalues;
      }
  
      public void setSourceProperties(Properties properties) {
          this.sourceProperties = properties;
      }
  
  }
  </code></pre>
  
  <p>Right now I just hardcoded the default visibility to "a", but will change that later to also be pulled from a properties file.</p>