Turning JSON list into POJO - java

Here's the JSON:
{
"Want":{
"ABCD-1234-ABCD-1234-ABCD-125A":3,
"ABCD-1234-ABCD-1234-ABCD-129B":5,
"ABCD-1234-ABCD-1234-ABCD-123C":10
},
"EndPoint":"https://example.com/gossip/asff3"
}
And my current POJO:
public class WantMessage {
#JsonProperty("Want")
Map<String, String> wantmap = new HashMap<String, String>();
#JsonProperty("EndPoint")
public String EndPoint;
}
I get the "Endpoint" String in ok but am missing the data in the "Want" section. How would you pull in the want list?

wantmap has keys and values of type String. The map in json has int values. Try putting the numbers in double quotes, and see if it works.

Related

Exclude indentifier of nested json but still take it's data - Spring

I have a post mapping method in my rest controller which takes a json and saves it in mongodb. I map this json in a class but I'm not able to retrieve it successfully after. The json has this format.
{
"*random_generated_string*": {
"field 1": value1,
"field 2": value2,
...
}
}
My understanding is that in order to map a json in to a class in spring I need to map every key of the json to a class property. I don't know how to map this random string. I decided it to exclude it but how? I want to still take it's contents and map them to my class.
P.S My class has these json fields as properties so it should be possible.
The solution was indeed to parse the object manually. Changed the controller to take a Map<String, Object> instead of the class object that I wanted to save and then manipulated the Object (value of the Map after casting it to a String). Then, using the setters I filled up the Object and saved it to the database.
Code
#PostMapping("/location")
public void saveLocation(#RequestBody Map<String, Object> payload) {
System.out.println(payload);
for (Entry<String, Object> entry : payload.entrySet()) {
System.out.println(entry.getValue());
String[] props = String.valueOf(entry.getValue()).substring(1).split("}")[0].split(",");
LocationM locationM = new LocationM();
locationM.setAccuracy(Float.parseFloat(props[0].split("=")[1]));
locationM.setAltitude(Float.parseFloat(props[1].trim().split("=")[1]));
locationM.setCount(Integer.parseInt(props[2].trim().split("=")[1]));
locationM.setLatitude(Float.parseFloat(props[3].trim().split("=")[1]));
locationM.setLongitude(Float.parseFloat(props[4].trim().split("=")[1]));
locationM.setSpeed(Integer.parseInt(props[5].trim().split("=")[1]));
locationM.setTimestamp(Long.parseLong(props[6].trim().split("=")[1]));
locationService.save(locationM);
}
}

Java - JSON output is not expected as what console suggests

I'm new to Java and writing APIs.
I basically have two things: a HashMap called db that should be returned as a JSON and an ArrayList called defaultParameters. Basically what the application does are the following:
db basically contains an array of objects of key-value pairs that should be returned as a JSON when a user makes a GET request to this address.
defaultParameters is basically a list of default key-value pairs. If there is no key-value pair within that object, then that object takes in that default key-value pair.
I was able to get it to display on the console, but for some reason, the updated values are not appearing in the JSON when I do the get request.
Here are the relevant code snippets:
private static ArrayList<Item> DB = new ArrayList<>();
private static HashMap<String, String> defaultValues = new HashMap<>();
private void updateAllItems(){
for(Item item : DB){
for(Map.Entry entry : defaultValues.entrySet()){
String currentField = (String) entry.getKey();
String currentValue = (String) entry.getValue();
item.addField(currentField, currentValue);
}
}
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getAllItems() {
updateAllItems();
for(Item item : DB){
// Test code that I added
item.printItem();
}
return Response.ok(DB).build();
}
Snippets of the Item class
public class Item {
private HashMap<String, String> item = new HashMap<>();
public void addField(String key, String value){
item.put(key, value);
}
public void printItem(){
for(Map.Entry entry : item.entrySet()){
String currentField = (String) entry.getKey();
String currentValue = (String) entry.getValue();
System.out.println(currentField + ": " + currentValue);
}
}
}
Doing the POST request and doing the GET request yields the following:
On the console (Something: notsomething) is new:
seller: Mrs. Fields
price: 49.99
title: Cookies
category: 42
something: notsomething
The JSON response however:
[{"category":"42","seller":"Mrs. Fields","price":"49.99","title":"Cookies"}]
The JSON is missing the new key-value pair that the console has. I'm trying to have the JSON reflect what the console is doing. Anyone have any ideas?
Alright, after some thinking, I figured out what to do.
I changed my code from
public class Item {
to
public class Item extends HashMap<String, String> {
and removed
private HashMap<String, String> item = new HashMap<>();
which means I had to change item to this. I figured since that I'm going to be using each instance as a hashmap, I may as well extend the hashmap that will change the instance of the item too.
Thanks for everyone's help. The comment gave me some more insight of what I was trying to do which led to a solution.

Retrieving values from nested JSON after de-serialization

I am trying to test my REST service by a JSON string from Chrome's Advanced REST Client. I have a nested JSON here. I am taking this as string and mapping it to my POJO class:
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(addressString, AddressPOJO.class);
Here, addressString holds the JSON String given below
{
"location":"[{\"Asia\":[{\"India\":[{\"city\":\"Bengaluru\"}]}], [{\"India\":[{\"city\":\"Mumbai\"}]}]}]
}
My AddressPOJO has variable:
Map<String,?> location = new HashMap();
I am retrieving the values from the POJO by
Map<String, ?> locations = addressPOJO.getLocation();
Iterator iterator1 = locations.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry pair1 = (Map.Entry)iterator1.next();
Map<String,?> cities = (Map<String,?>) pair1.getValue();
Iterator iterator2 = dataSets.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry pair2 = (Map.Entry)iterator2.next();
Map<String,?> city = (Map<String, ?>) pair2.getValue();
}
}
Here, I am only able to retrieve the second entry which is
[{\"India\":[{\"city\":\"Mumbai\"}]}]
I need to retrieve all the entries. I also tried to use MultiMap like this
MultiMap cities = (MultiMap) pair1.getValue();
But this is not accepted by compiler. Please note all the entries are dynamic in nature and the (key, value) pairs change as per user's input. Any suggestions how I can retrieve all the entries in this example.
From my understanding, maybe there are 2 things that you need to look into:
Why the data type of location is Map<String, ?>? Because from your JSON string, the type of location is an Array or a List, right? If you want to make it a Map, please use some strings like: {"location" : "\"key\":\"value\""}. If you want to make it a List, remove the "" around the value.
Another thing is that, it seems that you want a hierarchy to describe the some geography structure. Let's say, in Asia we have India and China, and in India we have Bengaluru and in China we have the city Chengdu. So the value of Asia should also be a List which contains two items India and China. So you should remove the ] and [ here, and I think this is also the reason why you are only able to retrieve the second entry.
Following is my testing code, I modified your JSON string and the data type of location.
Location.java
public class Location {
private List location;
public List getLocation() {
return location;
}
public void setLocation(final List location) {
this.location = location;
}
}
TestJSON.java
public class testJson {
private static ObjectMapper mapper = new ObjectMapper();
public static void main(final String[] args) throws JsonParseException, JsonMappingException, IOException {
final String locationString = "{\"location\":[{\"Asia\":[{\"India\":[{\"city\":\"Bengaluru\"}]}, {\"India\":[{\"city\":\"Mumbai\"}]}]}]}";
final Location location = mapper.readValue(locationString, Location.class);
System.out.println("finish");
}
}
Then all entries and levels are ok. Maybe you can have a try.
Hope this will help.

Parsing dynamic JSON values to Java objects

In my application I have lot of overviews (tables) with sorting and filtering capabilities. And becuase the different column can hold different value type (strings, numbers, dates, sets, etc.) the filter for these columns also can bring different values. Let me show you few examples (converted to JSON already as is sent to server via REST request):
For simple string value it is like:
{"<column_name>":"<value>"}
For number and date column the filter looks like:
{"<column_name>":[{"operator":"eq","value":"<value>"}]}
{"<column_name>":[{"operator":"eq","value":"<value1>"},{"operator":"gt","value":"<value2>"}]}
For set the filter looks like
{"<column_name>":["<value1>","<value2>"(,...)]}
Now I need to parse that JSON within a helper class that will build the WHERE clause of SQL query. In PHP this is not a problem as I can call json_decode and then simply check whether some value is array, string or whatever else... But how to do this simply in Java?
So far I am using Spring's JsonJsonParser (I didn't find any visible difference between different parsers coming with Spring like Jackson, Gson and others).
I was thinking about creating an own data object class with three different constructors or having three data object classes for all of the three possibilities, but yet I have no clue how to deal with the value returned for column_name after the JSON is parsed by parser...
Simply looking on the examples it gives me three possibilities:
Map<String, String>
Map<String, Map<String, String>>
Map<String, String[]>
Any idea or clue?
Jackson's ObjectMapper treeToValue should be able to help you.
http://fasterxml.github.io/jackson-databind/javadoc/2.2.0/com/fasterxml/jackson/databind/ObjectMapper.html#treeToValue%28com.fasterxml.jackson.core.TreeNode,%20java.lang.Class%29
Your main problem is that the first version of you JSON is not the same construction than the two others. Picking the two others you could deserialize your JSON into a Map<String, Map<String, String> as you said but the first version fits a Map.
There are a couple solutions available to you :
You change the JSON format to always match the Map<String, Map<String, String> pattern
You first parse the JSON into a JsonNode, check the type of the value and deserialize the whole thing into the proper Map pattern.
(quick and dirty) You don't change the JSON, but you try with one of the Map patterns, catch JsonProcessingException, then retry with the other Map pattern
You'll have to check the type of the values in runtime. You can work with a Map<String, Object> or with JsonNode.
Map<String, Object>
JsonParser parser = JsonParserFactory.getJsonParser();
Map<String, Object> map = parser.parseMap(str);
Object filterValue = filter.get("<column_name>");
if (filterValue instanceof String) {
// str is like "{\"<column_name>\":\"<value>\"}"
} else if (filterValue instanceof Collection) {
for (Object arrayValue : (Collection<Object>) filterValue) {
if (arrayValue instanceof String) {
// str is like "{\"<column_name>\":[\"<value1>\",\"<value2>\"]}"
} else if (arrayValue instanceof Map) {
// str is like "{\"<column_name>\":[{\"operator\":\"eq\",\"value\":\"<value>\"}]}"
}
}
}
JsonNode
ObjectMapper mapper = new ObjectMapper();
JsonNode filter = mapper.readTree(str);
JsonNode filterValue = filter.get("<column_name>");
if (filterValue.isTextual()) {
// str is like "{\"<column_name>\":\"<value>\"}"
} else if (filterValue.isArray()) {
for (JsonNode arrayValue : filterValue.elements()) {
if (arrayValue.isTextual()) {
// str is like "{\"<column_name>\":[\"<value1>\",\"<value2>\"]}"
} else if (arrayValue.isObject()) {
// str is like "{\"<column_name>\":[{\"operator\":\"eq\",\"value\":\"<value>\"}]}"
}
}
}

Parse json with variable key

I just came up with challenging problem.
Below is json response where key is variable (a GUID)
How can I parse it? I've tried Google Gson, but that didn't work.
{
"87329751-7493-7329-uh83-739823748596": {
"type": "work",
"status": "online",
"icon": "landline",
"number": 102,
"display_number": "+999999999"
}
}
If you use Gson, in order to parse your response you can create a custom class representing your JSON data, and then you can use a Map.
Note that a Map<String, SomeObject> is exactly what your JSON represents, since you have an object, containing a pair of string and some object:
{ "someString": {...} }
So, first your class containing the JSON data (in pseudo-code):
class YourClass
String type
String status
String icon
int number
String display_number
Then parse your JSON response using a Map, like this:
Gson gson = new Gson();
Type type = new TypeToken<Map<String, YourClass>>() {}.getType();
Map<String, YourClass> map = gson.fromJson(jsonString, type);
Now you can access all the values using your Map, for example:
String GUID = map.keySet().get(0);
String type = map.get(GUID).getType();
Note: if you only want to get the GUID value, you don't need to create a class YourClass, and you can use the same parsing code, but using a generic Object in the Map, i.e., Map<String, Object>.

Categories