Conversion between JSON with wrapped structure and pojo with flattended structure - java

I have a JSON structure that incorporates a wrapping level that I don't have in my POJOs. Like so:
JSON:
{
"category1": {
"cat1Prop1": "c1p1",
"cat1Prop2": "c1p2",
"cat1Prop3": "c1p3"
},
"category2": {
"cat2Prop1": "c2p1",
"cat2Prop2": "c2p2"
},
"category3": {
"cat3Prop1": "c3p1",
"cat3Prop2": "c3p2",
"cat3Prop3": "c3p3"
},
"category4": {
"cat4Prop1": "c4p1"
}
}
POJO:
public class MyPojo {
private String cat1Prop1;
private String cat1Prop2;
private String cat1Prop3;
private String cat2Prop1;
private String cat2Prop2;
private String cat3Prop1;
private String cat3Prop2;
private String cat3Prop3;
private String cat4Prop1;
// Getters / setters, etc...
}
As you can see, the JSON have a "category" level (that for different reasons I don't want to have in my Pojo).
I'm looking for a way to use Jackson for serializaion/deserialization to handle this in a smooth way.
I'm aware that Jackson has a #JsonUnwrapped annotation that kind of handles the opposite. I'm also aware that there is a feature request for a "#JsonWrapped" annotation that I think would solve my case.
Thankful for any input or help regarding this, as I have been looking around quite a bit. Also, any suggestions on how this could be accomplished using any other library (like gson, flexjson, etc) is also interesting.

You can try with this algorithm:
Read JSON as Map.
Flatten map
Use ObjectMapper to convert Map into POJO.
Implementation could looks like this:
ObjectMapper mapper = new ObjectMapper();
Map<String, Map<String, String>> map = mapper.readValue(new File("X:/test.json"), Map.class);
Map<String, String> result = new HashMap<String, String>();
for (Entry<String, Map<String, String>> entry : map.entrySet()) {
result.putAll(entry.getValue());
}
System.out.println(mapper.convertValue(result, MyPojo.class));

Related

Creating map based on json given

JSON
{
"type": {
"type1": {
"sub1": [
"sub1A": {
}
]
}
}
"type2": {
"type1": {
"sub1": [
"sub1A": {
}
]
}
}
}
I have Json like this , I am not getting how to create map for this, like
Map<String, Object> requestMap = new HashMap<>();
requestMap.get("type");
Inside type again create map containing sub data.
I didn't understand your question completely. But, from your statement, if you are trying to fetch json data into your class and that JSON data has recursive mapping, i.e., one object contains itself under its body. Then, I don't think you need HashMap to map this json into your class. You can use single Entity with a field of type of itself like employee-manager relationship. e.g.,
class Type {
private Type type;
private String otherField;
// constructors, setters, getters
}
Now, you can read values from type using the recursive functions.
According to what you have shared you can use:
Map <String, Map<String, Map<String, Set<Map<String, String>>>>>
Or to get more details concerning working with json objects you can look at: Query a JSONObject in java

Add a parent node to Json output in java

I have converted some info to Json format using Jackson in Java. Below is the output I get
[{"lat":45.9,"lon":10.9,"title":"Title A1","html":"<h3>Content A1</h3>","icon":"http://maps.google.com/mapfiles/markerA.png"},{"lat":44.8,"lon":1.7,"title":"Title B1","html":"<h3>Content B1</h3>","icon":"http://maps.google.com/mapfiles/markerB.png","show_infowindow":false},{"lat":51.5,"lon":-1.1,"title":"Title C1","html":"<h3>Content C1</h3><p>Lorem Ipsum..</p>","zoom":8,"icon":"http://maps.google.com/mapfiles/markerC.png"}]
My question is how can I get it in the below format, basically adding the Json to a root node which called locations
{"locations":[{"lat":45.9,"lon":10.9,"title":"Title A1","html":"<h3>Content A1</h3>","icon":"http://maps.google.com/mapfiles/markerA.png"},{"lat":44.8,"lon":1.7,"title":"Title B1","html":"<h3>Content B1</h3>","icon":"http://maps.google.com/mapfiles/markerB.png","show_infowindow":false},{"lat":51.5,"lon":-1.1,"title":"Title C1","html":"<h3>Content C1</h3><p>Lorem Ipsum..</p>","zoom":8,"icon":"http://maps.google.com/mapfiles/markerC.png"}]}
You may wrap the array into a JSONObject like so
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = new HashMap<String, Object>();
String json = jsonArray.toString();
map.put("locations", json);
json = mapper.writeValueAsString(map);
you can achieve this by following changes.
Let's Assume, your JSON will be created based upon Bean.java class likewise,
[{"lat":45.9,"lon":10.9,"title":"Title A1","html":"<h3>Content A1</h3>","icon":"http://maps.google.com/mapfiles/markerA.png"},{"lat":44.8,"lon":1.7,"title":"Title B1","html":"<h3>Content B1</h3>","icon":"http://maps.google.com/mapfiles/markerB.png","show_infowindow":false},{"lat":51.5,"lon":-1.1,"title":"Title C1","html":"<h3>Content C1</h3><p>Lorem Ipsum..</p>","zoom":8,"icon":"http://maps.google.com/mapfiles/markerC.png"}]
Now, As per your new requirement, you want something likewise,
{"locations":[{"lat":45.9,"lon":10.9,"title":"Title A1","html":"<h3>Content A1</h3>","icon":"http://maps.google.com/mapfiles/markerA.png"},{"lat":44.8,"lon":1.7,"title":"Title B1","html":"<h3>Content B1</h3>","icon":"http://maps.google.com/mapfiles/markerB.png","show_infowindow":false},{"lat":51.5,"lon":-1.1,"title":"Title C1","html":"<h3>Content C1</h3><p>Lorem Ipsum..</p>","zoom":8,"icon":"http://maps.google.com/mapfiles/markerC.png"}]}
So, in this case you need to create one more class, let's say it's SuperBean.java then it should be likewise,
public class SuperBean {
private Bean [] locations;
public Bean[] getBean() {
return locations;
}
public void setBean(Bean[] locations) {
this.locations = locations;
}
}
So, your JSON will be created likewise,
{"locations":[......]} // as per your requirement.

How to parse following json using Gson?

I have seen similar questions about parsing json with dynamic keys, but could not figure out how to parse the following json:
{
"unknown":
{
"id":3980715,
"name":"namename",
"profileIconId":28,
"revisionDate":1451936993000
}
}
Here, the "unknown" key is dynamic, it can be anything. We do not know what it is.
I tried the following class:
public class MyResponseClass {
private Map<String, Object> myResponse;
//Getter and setter
}
But myResponse becomes null after using gson like the following:
return gson.fromJson(response, MyResponseClass.class);
So, how can i do this?
Thanks.
I could manage to parse it like the following:
Type mapType = new TypeToken<Map<String, MyResponseClass>>() {}.getType();
Map<String, MyResponseClass> map = gson.fromJson(response, mapType);
and then iterated over map to get what I want.
Add an annotation to the field myResponse.
public class MyResponseClass {
#SerializedName("unknown")
private Map<String, Object> myResponse;
//Getter and setter
}
Try this:
// String jsonStr = ...;
Gson gson = new Gson();
Map<String, Object> jsonData = new HashMap<String, Object>();
jsonData = (Map<String, Object>)gson.fromJson(jsonStr, Object.class);
Your JSON data will be stored in Map<String, Object> (which is the simpliest way to store JSON data in Java).
So in this map at unknown key you will have another map with id, name etc.

Serialize HashMap to a JSON string while avoiding certain fields in Java

I have a map as below:
Map map = new HashMap<String, String>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
I need to convert this map into a JSON string. I know that this can be done using Jackson as below:
new ObjectMapper().writeValueAsString(map);
The problem is, I do not want to map key3 to the String. The output String should be as below:
{"key1":"value1","key2":"value2"}
Is there any way to avoid certain fields from the HashMap while serializing it to a String? Moreover, I want to add certain fields to the String while serializing. For instance, I need to add a field called "key4" with a value "value4". Thus, the final String should be:
{"key1":"value1","key2":"value2","key4":"value4"}
How do I do this using Jackson? Or is there any other way to do this in Java?
If you want to serialize a HashMap like this, you should implement a custom serializer. Here is one example:
public class CustomSerializer extends StdSerializer<Map> {
protected CustomSerializer() {
super(Map.class);
}
#Override
public void serialize(Map map, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeStartObject();
for (Object key : map.keySet()) {
if(!"key3".equals(key)){
jsonGenerator.writeStringField((String) key, (String) map.get(key));
}
}
jsonGenerator.writeStringField("key4","value4");
jsonGenerator.writeEndObject();
}
}
public class Main {
public static void main(String[] args) throws Exception{
Map<String, String> map = new HashMap<>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
ObjectMapper mapper = new ObjectMapper();
SimpleModule serializerModule = new SimpleModule("SerializerModule", new Version(1, 0, 0, null, "mt", "customSerializerTest"));
serializerModule.addSerializer(new CustomSerializer());
mapper.registerModule(serializerModule);
System.out.println(mapper.writeValueAsString(map));
}
}
Output:
{"key1":"value1","key2":"value2","key4":"value4"}
If you are serializing a POJO, you can use the #JsonIgnore annotation, but in this case, this is not an option, so you should make a copy of the HashMap, and do whatever operations on it, what you need.
The simplest way really is to modify the Map.
However, if you want, you can actually use #JsonIgnoreProperties on Map type as well. So, something like:
#JsonIgnoreProperties({ "key3" })
public class MyFilteringMap extends HashMap<String,String> { }
It is not possible to add properties via annotations.
But it is possible to use #JsonAnySetter and #JsonAnyGetter annotations to make a POJO look like a Map. This would allow combining of approaches for filtering, as well as some "standard" properties and other misc properties. See this -- http://www.cowtowncoder.com/blog/archives/2011/07/entry_458.html -- for details.
You can try Jackson Custom Serializers - http://wiki.fasterxml.com/JacksonHowToCustomSerializers. I think it's convenient option for your use case. Using own serializer you can make transparent object processing in serialize method - for example you can copy map to another avoiding certain fields etc.

Sending JSON with arbitrary key values using REST service (Jersey/Jackson)

I want to send something like this from the client to the rest service
jsonObj =
{
"info" : {
"field1" : "val1"..
.....
"fieldN" : "valN"..
}
}
And I am not sure how can I handle this using a rest service using Jersey and Jackson in Java
I do not want to create a new info class with using Jackson properties with N field as they are going to change always. I just want to grab the jsonObject which is inside the jsonObject and operate on that as JsonObject.
Any thoughts ?
Assuming you have a root object that you are reading the result into, you could define docInfo as a Map<String, Object> within your jsonObj. This will probably work, but I can't give it a go presently.
If you don't have a root object you can just use a Map<String, Object> as your root object and play with it from there. That Map could contain other maps for nested json objects.
Yes, use a wrapper object with an embedded map, as #digitialjoel suggested. This is a concrete example:
class DocInfo {
private Map<String, Object> docInfo;
public DocInfo() {
super();
}
public DocInfo(final Map<String, Object> docInfo) {
super();
this.docInfo = docInfo;
}
// Getters, setters
}
final Map<String, Object> data = new LinkedHashMap<String, Object>(4);
data.put("field1", "value1");
data.put("field2", "value2");
data.put("field3", "value3");
data.put("field4", "value4");
final DocInfo info = new DocInfo(data);
final ObjectMapper mapper = new ObjectMapper();
final String json = mapper.writeValueAsString(info);
System.out.println(json);
Output:
{"docInfo":{"field1":"value1","field2":"value2","field3":"value3","field4":"value4"}}

Categories