Match JSON String to new POJO Object - java

I am using Spring RestTemplate to communicate with an provided REST service that delivers JSON. To Map the response I am using Jaxon, but I will gladly switch to anything else that works.
I would like to create an POJO that contains sub-content of the delivered data but in a different Structure.
It boils down to this:
Source: { "a": "val_a", "b" : {"c" : "val_c", "d": "val_d"}}
#JsonIgnoreProperties(ignoreUnknown = true)
class Foo {
// should contains the content of `"a": "val_a"`
// but contains null
private Baa;
// getter and setter
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Baa {
private String a;
// getter and setter
}
// This should be the operation that is done internally by Spring when calling
// ResponseEntity<Foo>response = restTemplate.exchange(url, HttpMethod.GET, entity, Foo.class);
// response.getBody();
private Foo read(String s) {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
return mapper.readValue(s, Foo.class);
}
The result of the deserialization is an empty Baa object. The actual JSON and POJO Object structure is more complex but this sums it up.
Any Technology that achieves this would be welcome.
The only possibility I came up with is deserializing the JSON in the provided structure and write a Converter class that generates the desired Object but I was hoping to avoid this.
----- Update/clarification ------
The problem is, that the property a should be mapped within class Baa, which lies within Foo but is provided in the root path (is this the right term?) of the provided JSON objekt

public class Foo {
private String a;
private B b;
// getters setters
}
public class B {
private String c;
private String d;
// getters setters
}
Should map with no additional annotations with your code. If you're having a particular code with a non trivial example then post your actual code in whole.
Update on your clarification: no you can't do that with annotations as I said in my comment. You will have to write the custom deserialiser. Check out this answer: Jackson: is it possible to include property of parent object into nested object?

If you don't want to write the java bean that rappresent the JSON structure, you have to use a different library. Jackson forces you to create a java structure that reflects the JSON structure. In my opinion Jackson works great and i suggest you to use it, but the alternative could be JSON library.
With this one you can select only the element you want from the json, and map it to the bean you want.
Little example:
JSONObject response = new JSONObject("{\"a\": \"val_a\", \"b\" : {\"c\" : \"val_c\", \"d\": \"val_d\"}}");
JSONObject bObject = response.getJSONObject("b");
String cElement = (String) elenco.get("c");
The value of bObject is {"d":"val_d","c":"val_c"}, and the value of cElement is val_c
This libray uses JSONObject and JSONArray generic objects, to map the content of the json to a java object.

Related

In Java, how can I map a string that is either JSON or XML to the same POJO, but with the XML having one different field/attribute name from the JSON?

I am currently using Jackson's XmlMapper and ObjectMapper. I want to map the string to a POJO (I think I'm using that term correctly) that has a private field with the same name as the JSON string's field. The XML string has a different name for the same field/attribute, and I want to use the JSON field name.
I also want to essentially "ignore" that field (while keeping it) and store it as something like a JsonNode, as the value of that field can be some complex, nested value without a known shape.
Example:
public static class OuterClass {
private String firstValue;
private InnerClass innerValue;
// ... getters/setters
}
public static class InnerClass {
private JsonNode data; // complex, nested, so no POJO to map to
private String otherValue;
// ... getters/setters
}
The JSON might look like this:
{
"innerValue": {
"data": {
... complex stuff
},
"otherValue": "more stuff"
},
"firstValue": "thingy"
}
The XML might look like this:
<result>
<innerValue>
<incorrectName>
... complex stuff
</incorrectName>
<otherValue>more stuff</otherValue>
</innerValue>
<firstValue>thingy</firstValue>
</result>
So the goal is to get the XML to work with that class, including both mapping incorrectName to the class' data, as well as storing the complex inner part as something like a JsonNode since I don't have a class to model it.
I have the JSON working with new ObjectMapper().readValue(jsonString, OuterClass.class), and I think the XML should work with new XmlMapper().readValue(xmlString, OuterClass.class), but I don't know where to go with annotations. I've looked at the different annotations available and I don't think I've found the right one. I've also read that I shouldn't convert XML to a JsonNode, as there can be problems with that. I don't need to convert it back to XML after, though, and can treat it as JSON once I receive the JSON/XML string. So, I'd appreciate some help, thanks!
#XmlAccessorType(XmlAccessType.PROPERTY)
public static class InnerClass {
private JsonNode data; // complex, nested, so no POJO to map to
private String otherValue;
// ... getters/setters
#XmlElement(name = "incorrectName")
protected JsonNode getData() {return data;}
}

How to deserialize fields into object using jackson?

I tried deserialize following json to POJO.
{
"foo": {
"key1":"dummy",
"key2":"dummy"
},
"bar": {
"key1":"dummy",
"key2":"dummy",
"key3":"dummy"
},
"bazKey1":"dummy",
"bazKey2":"dummy",
"bazKey3":"dummy",
"bazKey4":"dummy"
// Many others....
}
You can see above strange baz properties...
But I want to treat baz as an object like foo and bar.
public class Pojo {
private Foo foo;
private Bar bar;
private Baz baz;
// Many others....
}
However, I just found poor solution which uses custom deserializer.
Poor solution
#Override
public Pojo deserialize(JsonParser p, DeserializationContext ctxt) throws Exception {
ObjectCodec codec = p.getCodec();
JsonNode node = codec.readTree(p);
Baz baz = new Baz.Builder()
.key1(node.get("bazKey1").textValue())
.key2(node.get("bazKey2").textValue())
.key3(node.get("bazKey3").textValue())
.key4(node.get("bazKey4").textValue())
.build();
// We have to write annoying (setter/constructor/builder) instead of below method.
// return codec.treeToValue(node, Pojo.class);
return new Pojo.Builder()
.foo(foo)
.bar(bar)
.baz(baz)
.other(other)
.other(other)
.other(other) // Many others...
.build();
}
This solution forces us to use annoying (setter/constructor/builder).
How to deserialize fields into object using jackson?
Additionally, this POJO is Immutable object.
The point of Jackson is that you're not in this situation. The very reason why you use Jackson at all is because when you have a Baz Java object, it's represented with a baz JSON property that contains an object, and when you have several string JSON properties, they are represented in Java with several String fields of the same name.
If that's not the situation you're in, then there is no reason to consider Jackson. Use any JSON parsing library, and build your Java objects from the JSON tree. You can use Java reflection to discover the Java class' fields/methods and set/call them based on the JSON properties' names.

deserialization with Jackson: get list of fields set by Json object

I would like to know after the deserialization with Jackson what fields where set by the Json input (even null), so I can than distinguish the null fields than where set on null from the one that where not specified in Json.
This question comes after my previous one about BeanDeserializerModifier.
public class Dto {
public Collection<String> deserializedFields;
// or even better a collection of reflection fields of the object.
}
public MyFooDto extends Dto {
public Integer myField1;
#PossiblySomeJacksonAnnotation (include, exclude, map on other name, special deserializer, etc...)
public SomeDatatype myField2;
}
Example: by deserializing {"myField1": null} I would like to have deserializedFields = ["myField1"], and by deserializing {} I would like to have deserializedFields = [].
I already tried within a custom deserializer and a BeanDeserializerModifier, but still I cant intercept the list of fields inside the Json object (or if I do so it already consumates the JsonParser and it can't be deserialized then).
In the best case I would also get the reflection list of the MyFooDto Fields that have been set...
Do you see how I could proceed?
Thank you Community!
The most straightforward way is to add code in each setter to add the currently set variable name to a List. E.g. :
public class Dto {
public List<String> deserializedFields = new ArrayList<>();
}
and inside MyFooDto setters like:
public void setMyField1(Integer myField1) {
deserializedFields.add("myField1");
this.myField1 = myField1;
}
That's a lot of work if there are hundreds of such setters. An alternative for such a case is to parse JSON into a tree first, traverse it to get JSON property names to add in a collection and then convert the tree to MyFooDto. E.g. (assuming you have a ObjectMapper mapper and json below is a String with your example JSON):
ObjectNode tree = (ObjectNode) mapper.readTree(json);
ArrayNode deserializedFields = mapper.createArrayNode();
tree.fields().forEachRemaining(e -> deserializedFields.add(e.getKey()));
tree.put("deserializedFields", deserializedFields);
MyFooDto dto = mapper.treeToValue(tree, MyFooDto.class);

Jackson Custom Property-Name to Type Mapping for Polymorphic Properties

I am trying to deserialize a rather complex POJOs JSON, where I would need to define a specific property-name to type resolution, but yet faild fininding this rather simple feature.
assume a class like:
class Example {
int id;
Map<String,Object> extras;
}
and Jackson is serializing the POJO correctly to JSON where the map is serialized to a key-value map just like expected:
{...
id:5,
extras:{object1:{...}, object2:{...}}
...}
now I would like to tell Jackson to explicitly deserialize the extras objects by their actual type. So I need to tell Jackson somehow to map "object1" to Type A and "object2" to type B.
Is this possible? Thanks.
There is nice guide how to deal with it: http://www.cowtowncoder.com/blog/archives/2010/03/entry_372.html
And another tutorial:
http://programmerbruce.blogspot.de/2011/05/deserialize-json-with-jackson-into.html
The 6th example from the second tutorial could be modified and deserializer would have loop with something similar to:
Map<String, Class> types = ...// map of supported types
JsonToken token = jsonParser.nextToken();
if(token == JsonToken.FIELD_NAME){ // "object1" etc.
String name = jsonParser.getCurrentName();
Class type = types.get(name);
Object object = jsonParser.readValueAs(type);
}
The easiest way is to enable so-called "default typing" -- it does roughly equivalent of adding #JsonTypeInfo annotation (which enables support polymorphic type handling) -- and this adds type information in values. So:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
If the Extras map contains only those 2 objects (object1 and object2) you can do the following
class TypeA {
// TypeA body
}
class TypeB {
// TypeB body
}
class Extras {
private TypeA object1;
private TypeB object2;
// Getters and setters
}
class Example {
int id;
Extras extras;
}
This is possible using a custom deserializer; see this link, for examples. In a nut shell, you need to tell Jackson what type a field should be unmarshalled to; although, this might be error prone if your serialized data (JSON) is dynamically changing.
You can then easily annotate your field's setter like so:
ObjectA value;
#JsonDeserialize(using=ObjectADeserializer.class)
public void setValue(ObjectA objectAValue) {
this.value = objectAValue;
}

Jackson Data-Binding with Heterogeneous Json Object

I'm calling a rest service that returns a json object. I'm trying to deserialize the responses to my Java Beans using Jackson and data-binding.
The example Json is something like this:
{
detail1: { property1:value1, property2:value2},
detail2: { property1:value1, property2:value2},
otherObject: {prop3:value1, prop4:[val1, val2, val3]}
}
Essentially, detail1 and detail2 are of the same structure, and thus can be represented by a single class type, whereas OtherObject is of another type.
Currently, I've set up my classes as follows (this is the structure I would prefer):
class ServiceResponse {
private Map<String, Detail> detailMap;
private OtherObject otherObject;
// getters and setters
}
class Detail {
private String property1;
private String property2;
// getters and setters
}
class OtherObject {
private String prop3;
private List<String> prop4;
// getters and setters
}
Then, just do:
String response = <call service and get json response>
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(response, ServiceResponse.class)
The problem is I'm getting lost reading through the documentation about how to configure the mappings and annotations correctly to get the structure that I want. I'd like detail1, detail2 to create Detail classes, and otherObject to create an OtherObject class.
However, I also want the detail classes to be stored in a map, so that they can be easily distinguished and retrieved, and also the fact that the service in in the future will return detail3, detail4, etc. (i.e., the Map in ServiceResponse would look like
"{detail1:Detail object, detail2:Detail object, ...}).
How should these classes be annotated? Or, perhaps there's a better way to structure my classes to fit this JSON model? Appreciate any help.
Simply use #JsonAnySetter on a 2-args method in ServiceResponse, like so:
#JsonAnySetter
public void anySet(String key, Detail value) {
detailMap.put(key, value);
}
Mind you that you can only have one "property" with #JsonAnySetter as it's a fallback for unknown properties. Note that the javadocs of JsonAnySetter is incorrect, as it states that it should be applied to 1-arg methods; you can always open a minor bug in Jackson ;)

Categories