JSON to Object Mapping - java

"statValues": {
"c__TL_gattooi": {
"value": 90.0
},
"c_cwc_gattooi": {
"value": 3462.0
},
"c_gaw__oxcgattooi": {
"value": 11.0
},
"c_odesb__ox_gattooi": {
"value": 6.0
},
"c_odesb_cwdc_gattooi": {
"value": 205472.0
},
"c_ach38_sax_gattooi": {
"value": 1.0
},
}
Want to convert this JSON to a POJO to be mapped with jackson

To deserialize given json from string jsonSource use something like
ObjectMapper mapper = new ObjectMapper();
Root root = mapper.readValue(jsonSource, Root.class);
I generated POJOs for you
import java.util.HashMap;
class Root {
private HashMap<String, Value> statValues = new HashMap<>();
public HashMap<String, Value> getStatValues() {
return statValues;
}
public void setStatValues(HashMap<String, Value> statValues) {
this.statValues = statValues;
}
}
class Value {
double value;
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
}
If can give better names it's possible by remapping properties using #JsonProperty
To access value use something like root.get("c__TL_gattooi").getValue(), to get list of keys - root.keys()

Related

how to map #JsonProperty for an attribute having chance of multiple data types

Im using jsonProperty annonation to map json values to variables in pojo object.
{
"valueSet": [
{
"name": "Type_int",
"value": 123
},
{
"name": "Type_String",
"value": "ABC"
}
]
}
For this above json, I am using Object class object to capture "value" attribute value.
like
#JsonProperty("value")
private Object value;
This working fine to capture both "Integer" and "String" value.
But for below scenario
{
"valueSet": [
{
"name": "Type_int",
"value": 123
},
{
"name": "Type_String",
"value": "ABC"
},
{
"name": "Type_array",
"value": [
{
"x": 0,
"y": 0
},
{
"x": 10,
"y": 10
},
{
"x": 20,
"y": 20
}
]
}
]
}
There are three different data types for "value" attribute.I cannot use Object to capture value. So, is there any way to capture all values in "value" attribute.
Just trying my luck, with below code,
The Value class
public class Value {
#JsonProperty("name")
private String name;
#JsonProperty("value")
private Object value;
#JsonProperty("value")
private ValueObject valueObject;
//setters and getters
}
ValueSet class
public class ValueSet {
#JsonProperty("valueSet")
private List<Value> l;
//setters & getters
}
ValueObject class
public class ValueObject {
#JsonProperty("x")
private int x;
#JsonProperty("y")
private int y;
//setters & getters
}
And the test method
#Test
public void test() {
String input = "{\"valueSet\":[{\"name\":\"Type_int\",\"value\":123},{\"name\":\"Type_String\",\"value\":\"ABC\"},{\"name\":\"Type_array\",\"value\":[{\"x\":0,\"y\":0},{\"x\":10,\"y\":10},{\"x\":20,\"y\":20}]}]}";
//String input = "{\"valueSet\":[{\"name\":\"Type_int\",\"value\":123},{\"name\":\"Type_String\",\"value\":\"ABC\"}]}";
ObjectMapper mapper = new ObjectMapper();
try {
ValueSet v = mapper.readValue(input, ValueSet.class);
System.out.println(v);
} catch (IOException e) {
e.printStackTrace();
}
}
Output, in reverse order.
ValueSet [l=[Value [name=Type_int, value=123], Value [name=Type_String, value=ABC]]]
ValueSet [l=[Value [name=Type_int, value=123], Value [name=Type_String, value=ABC], Value [name=Type_array, value=[{x=0, y=0}, {x=10, y=10}, {x=20, y=20}]]]]
Add toString() methods to see output in log or console. And somehow this works for me. Not sure if it would work for you.
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray jsonArray = jsonObject.getJSONArray("valueSet");
for(int i=0; i<jsonArray.length(); i++) {
System.out.println(jsonArray.optJSONObject(i).get("value").toString());
}

Custom Marshalling of HashMap<String,Object> in JAXB

I have a small problem regarding the marshalling via JAXB.
Currently I have a HashMap of Objects
#XmlJavaTypeAdapter(HashMapAdapter.class)
private Map<String, Object> data;
beeing marshalled by the Custom HashMapAdapter
public class HashMapAdapter extends XmlAdapter<HashMapAdapter.AdaptedMap,
Map<String, Object>> {
#XmlRootElement
public static class AdaptedMap {
#XmlVariableNode("key")
List<Data> entries = new ArrayList<>();
}
public static class Data {
#XmlTransient
public String key;
#XmlValue
public Object value;
}
#Override
public Map<String, Object> unmarshal(AdaptedMap v) throws Exception {
throw new NotImplementedException();
}
#Override
public AdaptedMap marshal(Map<String, Object> map) throws Exception {
AdaptedMap adaptedMap = new AdaptedMap();
for (Map.Entry<String, Object> entry : map.entrySet()) {
Data data = new Data();
data.key = entry.getKey();
data.value = entry.getValue();
adaptedMap.entries.add(data);
}
return adaptedMap;
}
}
The Marshalling is based on the following Post: http://blog.bdoughan.com/2013/06/moxys-xmlvariablenode-using-maps-key-as.html
The HashMap is filled with either Boolean, Long or String Values.
So regarding the Blog the expected JSON Output should be:
"data": {
"booleanValue": true,
"stringValue": "test",
"longValue": 1234
}
But the real outcome is:
"data": {
"longValue": {
"type": "long",
"value": 1234
},
"stringValue": {
"type": "string",
"value": "test"
},
"booleanValue": {
"type": "boolean",
"value": true
}
}
Im running on Payara Micro 174 and therefore on MOXy as JAXB provider.
Is it possible to get rid of the "type"/"value" nesting?
Best Regards
Simon
I do not have an MOxY implementation handy, could you try this and tell me if it works ?
public static class Data {
#XmlTransient
public String key;
#XmlElements({
#XmlElement(type=Long.class),
#XmlElement(type=String.class),
#XmlElement(type=Boolean.class)
})
#XmlPath(".")
public Object value;
}
EDIT :
The Output you get when using this Approach is:
"data": {
"stringValue": {
"value": test
},
"booleanValue": {
"value": true
},
"longValue": {
"value": 1234
}
}
Sadly this differs a little from the expected.

Jackson: Serialize an EER specialization

I'm using spring boot with jackson to provide an API.
In my DB there is a generalization/specialization field. That means, I have two fields: a value and a field that defines the data type of the value.
So my entity looks like this:
public class Example{
private String value;
private String type;
// getters and setters
}
For example with these three entries:
"1234";"Integer"
"example string";"String"
"true";"Boolean"
Jackson serialize this as follows:
[{
"value": "1234",
"type": "Integer"
},
{
"value": "example string",
"type": "String"
},
{
"value": "true",
"type": "Boolean"
}]
This is what I expteced, but, I need this:
[{
"value": 1234,
"type": "Integer"
},
{
"value": "example string",
"type": "String"
},
{
"value": true,
"type": "Boolean"
}]
So, the values should be serialized according to the value of the "type" field.
I know that I can attach a serializer to the "value" field, but I cannot access the "type" field there to know how to serialize the value.
One option is to change your Example class like this if you can :
public static class Example {
private String value;
private String type;
#JsonIgnore
public String getValue() {
return value;
}
#JsonProperty("value")
#JsonRawValue
public Object getRawValue() {
if("String" .equals(type)){
return '"'+ value +'"';
}
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Or you could use deserializer on Example class
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Example.class, new MySerializer());
mapper.registerModule(module);
System.out.println(mapper.writeValueAsString(list));
}
private static class MySerializer extends JsonSerializer<Example> {
#Override
public void serialize(Example value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeFieldName("value");
if (value.getType().equals("String")) {
gen.writeString( value.getValue());
} else {
gen.writeRawValue(value.getValue());
}
gen.writeStringField("type", value.getType());
gen.writeEndObject();
}
}
Result:
[{"value":1234,"type":"Integer"},{"value":"example string","type":"String"},{"value":true,"type":"Boolean"}]
Update
Here is one way how you could use custom deserializer and default one for every other field:
private static class MySerializer extends JsonSerializer<Example> {
private static final ObjectMapper internalMapper = new ObjectMapper();
#Override
public void serialize(Example value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
ObjectNode node = internalMapper.valueToTree(value);
if (value.getType().equals("String")) {
node.put("value", value.getValue());
} else {
node.putRawValue("value", new RawValue(value.getValue()));
}
gen.writeObject(node);
}
}
Will need to have #JsonIgnore in your public String getValue()

how to parse json array value using json node

I have a JsonNode which contains the following JSON. Inside that JsonNode object is an array. In that array there are three fields, one of which, slaid, is a list. The other two are strings. Here is the JSON.
{
"SLA": [
{
"slaid": [
"53637cc144ae8b607e089701"
],
"ragindicator": "Red",
"name": "r1"
},
{
"slaid": [
"53637d1844ae8b607e089704"
],
"ragindicator": "Amber",
"name": "a1"
},
{
"slaid": [
"53637eac44ae8b607e089706"
],
"ragindicator": "Green",
"name": "g1"
}
]
}
I want to parse this value. How can I parse it , where slaid's type is List<String>? I have tried some ways but I am still unable to find the solution.
The easiest way I can see is creating POJO classes which fit to your JSON:
class Slaids {
#JsonProperty("SLA")
private List<Slaid> slaids;
public List<Slaid> getSlaids() {
return slaids;
}
public void setSlaids(List<Slaid> slaids) {
this.slaids = slaids;
}
#Override
public String toString() {
return slaids.toString();
}
}
class Slaid {
private List<String> slaid;
private String ragindicator;
private String name;
public List<String> getSlaid() {
return slaid;
}
public void setSlaid(List<String> slaid) {
this.slaid = slaid;
}
public String getRagindicator() {
return ragindicator;
}
public void setRagindicator(String ragindicator) {
this.ragindicator = ragindicator;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Slaid [slaid=" + slaid + ", ragindicator=" + ragindicator + ", name=" + name + "]";
}
}
Simple usage:
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(json, Slaids.class));
Above program prints:
[Slaid [slaid=[53637cc144ae8b607e089701], ragindicator=Red, name=r1], Slaid [slaid=[53637d1844ae8b607e089704], ragindicator=Amber, name=a1], Slaid [slaid=[53637eac44ae8b607e089706], ragindicator=Green, name=g1]]
If you want to use JsonNode you can do it in this way:
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(json);
ArrayNode slaidsNode = (ArrayNode) rootNode.get("SLA");
Iterator<JsonNode> slaidsIterator = slaidsNode.elements();
while (slaidsIterator.hasNext()) {
JsonNode slaidNode = slaidsIterator.next();
System.out.println(slaidNode.get("slaid"));
System.out.println(slaidNode.get("ragindicator"));
System.out.println(slaidNode.get("name"));
}
Above program prints:
["53637cc144ae8b607e089701"]
"Red"
"r1"
["53637d1844ae8b607e089704"]
"Amber"
"a1"
["53637eac44ae8b607e089706"]
"Green"
"g1"

Jackson json arraylist of unknown fields

I have a JSON string like this:
{
"123": {
"hi": {
"name": "John",
"phone": "12345"
}
},
"124": {
"hi": {
"name": "James",
"phone": "12345"
}
},
"125": {
"hi": {
"name": "Leo",
"phone": "12347"
}
}
}
The JSON is ordered externally: 123, 124, 125 I just want to get the value of the last field ("125" : {...}) but I don't know its name, is auto-generated. What's the best way?
I'm trying mapping to an arrayList of JsonNodes, but I don't find the right way.
You can also do it using #JsonAnySetter annotation. Please, see below example. POJO class:
class Node {
private Integer key = Integer.MIN_VALUE;
private JsonNode value;
#JsonAnySetter
public void set(String newKey, JsonNode newValue) {
if (Integer.valueOf(newKey) > key) {
value = newValue;
}
}
public JsonNode getValue() {
return value;
}
#Override
public String toString() {
return String.valueOf(value);
}
}
Example usage:
ObjectMapper mapper = new ObjectMapper();
Node node = mapper.readValue(json), Node.class);
System.out.println(node);
Prints:
{"hi":{"name":"Leo","phone":"12347"}}
I did it putting the JSON string in a JsonNode, data and mapping to a NavigableMap.
NavigableMap<String, JsonNode> updates = mapper.readValue(data.traverse(), new TypeReference<TreeMap<String, JsonNode>>() {});
Entry<String, JsonNode> lastEntry = updates.lastEntry();
String lastUpdate = lastEntry.getValue().toString();

Categories

Resources