erj2code
erj2code

Reputation: 311

Does camel-jackson 2.12.1 support marshalling of nested objects into nested JSON?

I have the following two Java classes (SensorData, and Visibility) to store dummy sensor data, and their respective visibilities into two objects:

SensorData.java

package com.data.world2; 

import java.util.Map; 
import java.util.TreeMap; 

import com.fasterxml.jackson.annotation.JsonAnyGetter; 
import com.fasterxml.jackson.annotation.JsonAnySetter; 
import com.fasterxml.jackson.annotation.JsonProperty; 

public class SensorData { 

    private final Map<String, Object> keyvalues = new TreeMap<String, Object>(); 

    @JsonProperty 
    private Visibility visibility; 

    // getters and setters 
    @JsonAnyGetter 
    public Map<String, Object> getKeyvalues() { 
      return keyvalues; 
    } 

    @JsonAnySetter 
    public void setKeyvalues(final String key, final Object value) { 
      this.keyvalues.put(key, value); 
    } 

    // getters and setters 
    public Visibility getVisibility() { 
       return visibility; 
    } 

    public void setVisibility(Visibility visibility) { 
       this.visibility = visibility; 
    } 

} 

Visibility.java

package com.data.world2; 

import java.util.Map; 
import java.util.TreeMap; 

import com.fasterxml.jackson.annotation.JsonAnyGetter; 
import com.fasterxml.jackson.annotation.JsonAnySetter; 

public class Visibility { 

    private final Map<String, Object> keyvalues = new TreeMap<String, Object>(); 

    // getters and setters 

    @JsonAnyGetter 
    public Map<String, Object> getKeyvalues() { 
       return keyvalues; 
    } 

    @JsonAnySetter 
    public void setKeyvalues(final String key, final Object value) { 
       this.keyvalues.put(key, value); 
    } 

} 

And in my SensorGenerator class I store SensorData and Visibility keyvalue objects. For example, suppose I have two keyvalue pairs from a sensor (make and model), and only the "make" keyvalue pair has a visibility specified; the "model" keyvalue pair uses the default visibility:

    // create a sensorData object, and a visibility object 
    SensorData sensorData = new SensorData(); 
    Visibility visibility = new Visibility(); 

    sensorData.setKeyValues("s1make", "Apple"); // set sensor 1 make 
    visibility.setKeyValues("s1make", "public"); // set sensor 1 make visibility 
    sensorData.setKeyValues("s1model", "iPhone5"); // set sensor 1 model 
    // sensor 1 model visibility not specified 

    // set default visibility 
    visibility.setKeyValues("_default", "private"); // set default visibility for sensor keyvalue pairs 

Then I added the Visibility object to the SensorData object to get nested visibilities:

    // add the visibility to the SensorData object 
    sensorData.setVisibility(visibility); 

UPDATED:

The issue was that I was not returning the list back to Camel correctly for marshalling to JSON.

When I changed my code to the following I had the full nested JSON marshalled:

 List<SensorData> sensorDataList = new ArrayList<SensorData>();
 sensorDataList.add(sensorData);

The following is the previous way I had which was incorrect (just here for historical info)

And then I return a List of SensorData objects to my Camel thread for marshalling to JSON with the Jackson library (camel-jackson):

    // Build a sensorDataList based on the keyvalues stored in the SensorData object 
    List<SensorData> sensorDataList = new ArrayList(sensorData.getKeyvalues().entrySet()); 

When I run my Java program I'd expect to see the following nested JSON from my Camel route:

[{"key":"s1make","value":Apple"}, 
 {"key":"s1model","value":"iPhone5"}, 
 {"visibility": {"key":"s1make","value":"public", 
                 "key":"_default","value":"private"} 
}] 

But instead, I only see are the SensorData keyvalues marshalled into JSON i.e.,:

[{"key":"s1make","value":Apple"}, 
 {"key":"s1model","value":"iPhone5"}] 

How come I don't see the "s1make" and "_default" visibilities as nested JSON? Does camel-jackson 2.12.1 not support marshalling of nested objects into nested JSON?

Btw, here is a snippet of my applicationContext.xml where I specify the marshalling to JSON:

      <camel:dataFormats>
         <camel:json id="jack" library="Jackson"/>
      </camel:dataFormats>

      <camel:route>

             <camel:from 
                     uri="timer://hello.world.request.timer?fixedRate=true&amp;period={{config.timeout}}" />
             <camel:to uri="log:hello.world.request?level=INFO&amp;showAll=true" />
             <camel:bean ref="helloWorld" />


             <camel:marshal ref ="jack"/>
             <camel:convertBodyTo type="java.lang.String" />
             <camel:log message="${body}"/>  


             <camel:log message="printing values read from config.properties file"/>
             <camel:log message="config.timeout= {{config.timeout}}"/>  
             <camel:log message="config.numSamples= {{config.numSamples}}"/>
             <camel:log message="config.defaultViz= {{config.defaultViz}}"/>


             <camel:to uri="log:hello.world.response?level=INFO&amp;showAll=true" />

       </camel:route>

 </camel:camelContext>

Last week I posted a similar question on SO, but realized after I posted it that I had to change my implementation to return a list to Camel instead of a map. How do I marshall nested key,value pairs into JSON with Camel and Jackson library?

Upvotes: 0

Views: 1731

Answers (1)

Vidya
Vidya

Reputation: 30310

I am not sure why you need to use @JsonAnySetter/@JsonAnyGetter, but if you must, try this in both classes

@JsonAnySetter 
public void add(String key, String value) {
      keyValues.put(key, value);
}

Meanwhile, your setKeyValues should take a Map parameter. As you have it now, you have stretched JavaBean conventions.

Also, take Camel out of the equation. Write unit tests to test your configuration and make sure your objects are serialized/deserialized as you expect before integrating them into Camel and waiting until runtime for things to blow up.

Upvotes: 2

Related Questions