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

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"}}

Related

ObjectMapper using com.jsoniter library

I have a Map<String, Object> map that was deserialized from a simple JSON string {"field1":"val1", "field2":"val2", "isReal":true}. I am trying to construct a Java object MyObject with the above fields.
I can do it using com.fasterxml.jackson.databind.ObjectMapper like so:
public static MyObject load(Map<String, Object> map) throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(new ObjectMapper().writeValueAsString(map), MyObject.class);
}
I was wondering if anyone knows how to do the same using com.jsoniter library?
I have tried to use JsonIterator.deserialize, but that doesn't take a Map as input.
I have also seen ReflectionEncoderFactory usage on the library website, but I don't fully grasp as to how I would use it to construct an object MyObject
As per #Scary Wombat's explanation:
First it is necessary to convert the Map back to JSON string and then convert the JSON string to an object:
public static MyObject load(Map<String, Object> map) throws IOException {
return JsonIterator.deserialize(JsonStream.serialize(map), MyObject.class);
}
JsonStream.serialize(map) is the same new ObjectMapper().writeValueAsString(map)

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.

Conversion between JSON with wrapped structure and pojo with flattended structure

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));

Categories