Reputation: 311
I have the following two Java classes (SensorData, and Visibility) to store dummy sensor data, and their respective visibilities into two objects:
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;
}
}
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);
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&period={{config.timeout}}" />
<camel:to uri="log:hello.world.request?level=INFO&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&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
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