How to translate the Json in to POJO - java

I have the following JSON I need to be able to present in POJO, how could I
do this ?
The JSON has one key per day and the value for each key is two separate logical arrays, I am using Jackson library.
{
"2014/01/02": [
{"ABC": 2.25, "XYZ": 4.05},
{"amazon.com": 3}
],
"2014/01/03": [
{"ABC": 13.02},
{"amazon.com": 3}
]
}

You don't have much option. That's an ugly looking JSON. There is no consistent format, where you can create POJO.
Things you need to consider. This {} is a JSON object. Im Java mapping terms, it can either map to a POJO, or a Map. In order to map to a POJO, you need to common property names and formatting, of which it doesn't seem like you have. It all seems to be varying. So you may need to use a Map. Here's how I look at it
{ // Start Map
"2014/01/02": [ // Map key: start Array ( List<Map> )
{"ABC": 2.25, "XYZ": 4.05}, // Start another Map
{"amazon.com": 3} // another Map
You can use #JsonAnySetter to simplify, using a POJO wrapper, but you will still have, in the end a Map<String, List<Map<String, Object>> as I pointed out in my comment. If you want POJOs, there needs to be some common formatting.
Here's an example of one way to make it work
POJO
public class Dynamic {
private Map<String, Object> map = new HashMap<>();
public Object get(String key) {
return map.get(key);
}
public Map<String, Object> getMap() {
return map;
}
#JsonAnySetter
public void set(String name, Object value) {
map.put(name, value);
}
}
Test (using your exact JSON in simple.json file)
public class Test {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Dynamic dynamic = mapper.readValue(new File("simple.json"), Dynamic.class);
for (String key : dynamic.getMap().keySet()) {
System.out.println("key: " + key);
System.out.println("--------");
List<Map<String, Object>> list = (List<Map<String, Object>>) dynamic.get(key);
for (Map<String, Object> map : list) {
for (Map.Entry<String, Object> entry: map.entrySet()) {
System.out.println("key: " + entry.getKey() + ", value: " + entry.getValue());
}
}
System.out.println("========");
}
}
}
Result
key: 2014/01/03
--------
key: ABC, value: 13.02
key: amazon.com, value: 3
========
key: 2014/01/02
--------
key: ABC, value: 2.25
key: XYZ, value: 4.05
key: amazon.com, value: 3
========

{
"2014/01/02": [
{"ABC": 2.25, "XYZ": 4.05},
{}
],
"2014/01/03": [
{"ABC": 13.02},
{"amazon.com": 3}
]
}
This is even JSON, but not useful. I would make JSON for this like below.
{
[
{date: '2014/01/01',data:[{abc: 13.02, "amazonCom": 3},{abc: 13.02, "amazonCom": 3}},
{date: '2014/01/02',data:[{abc: 13.02, "amazonCom": 3},{abc: 13.02, "amazonCom": 3}},
]
}
Java
public jsonObj {
private String date;
private List<DateData> data;
.... setter//getter
}
public class DateData {
private double abc;
private int amazoneCom;
//constructor and getter/setter
}
You can use JSON libraries like below.
1. Jackson - http://jackson.codehaus.org/
2. Gson - https://code.google.com/p/google-gson/
Those libraries helps you to convert json into Java Object and vise versa as well.
Hope it can help you with solving your problem.

There are many ways to transform json to pojo. Here I am sharing few URL to achieve the same
Google Gson Tutorial : Convert Java Object to / from JSON http://howtodoinjava.com/2014/06/17/google-gson-tutorial-convert-java-object-to-from-json/
Generate Plain Old Java Objects from JSON or JSON-Schema. http://www.jsonschema2pojo.org/

Related

org.json.simple. get unique nested value

I have a json with complex nested. values. But there is one unique key value pair in the json.. without traversing , I need to retrieve the value .
for example:
name : "xyz". In the entire complex nested json , I need to return a json with all the values of name key.
I am currently using org.simple.json. but its very complex as I have to traverse through the entire nested json and build JSONArray etc.
maybe you can use java8 stream,the way is very easy to solve your problem.
example:
[
{
"name":"xyz",
"value":"1"
},
{
"name":"xyz",
"value":"2"
},
{
"name":"xyz",
"value":"3"
}
]
and then,you can create a class:
import lombok.Data;
#Data
public class JsonTest {
private String name;
private String value;
}
finally, like this. btw, I am currently using other json package.
List<JsonTest> jsonArray = JSON.parseArray(json, JsonTest.class);
List<String> valueList = jsonArray.stream()
.filter(e -> "xyz".equals(e.getName()))
.map(JsonTest::getValue)
.collect(Collectors.toList());

java jsonobject "value" and "num"

when using the javax json ObjectBuilder to build json, the output json string contains "value" and "num" in the json string. my web service is throw serialization error when the json contains "value" and "num". any one know why the output have "value" and "num"?
example:
JsonObject addProductRequest = Json.createObjectBuilder()
.add("OrderID", orderId)
.add("Product", productId)
.add("Quantity", qty)
.add("access_token", access_token)
.build();
output:
{
"OrderID": {
"num": 15498
},
"ProductID": {
"num": 20
},
"Quantity": {
"num": 1
},
"access_token": {
"value": "1f6c689d-6956-4f8e-b259-9030d57bec4b"
}
}
when I switch to using google.gson.JsonObject, the output dont have the "value" and "num" string, which my web service accepts and every thing seems to work fine.
example
com.google.gson.JsonObject addProductRequest = new com.google.gson.JsonObject();
addProductRequest.addProperty("OrderID", orderId);
addProductRequest.addProperty("Product", productId);
addProductRequest.addProperty("Quantity", qty);
addProductRequest.addProperty("access_token", access_token);
output:
{ "OrderID": 15499, "Product": 20, "Quantity": 1, "access_token": "3241cfd4-7b6c-4eac-b2bb-9b2b0c780831"}
Rest Assured seems to use Gson to serialize POJOs (which is what you should be using as response entities) to the response body.
Gson doesn't know anything about javax.json. The implementation of javax.json that you are using basically has this format for its JsonObject:
private static final class JsonObjectImpl extends AbstractMap<String, JsonValue> implements JsonObject {
private final Map<String, JsonValue> valueMap; // unmodifiable
Since this is a Map, Gson uses special serializing, iterating through its entrySet and using each Entry as a JSON key-value pair (within a JSON object).
In this case, the entrySet returns
#Override
public Set<Entry<String, JsonValue>> entrySet() {
return valueMap.entrySet();
}
where the valueMap contains all the values you added with add in your builder. For example, for
.add("OrderID", 1)
it will have added an entry with the String key OrderID and the JsonValue value of
// Optimized JsonNumber impl for int numbers.
private static final class JsonIntNumber extends JsonNumberImpl {
private final int num;
Notice the num field.
So Gson will now see a value of this JsonIntNumber type. It considers it a POJO and so serializes it as a JSON object with its fields as key-value pairs. It therefore produces
{
"num": 15498
}
com.google.gson.JsonObject is a known type to Gson. It knows that it is special and not a custom POJO type. It can therefore write it directly, instead of having to serialize it further.
This is similar to a question which I answered here:
Returning JsonObject using #ResponseBody in SpringMVC

What is the reasoning on modelling a class to represent JSON data and do I need to?

I have come across this question on StackOverflow which asks about converting JSON to Java. The answer shows that another class is modelled to represent the JSON data as well as an object being created and I don't understand why.
Does that object now contain all the information after Gson reads the content or only one key/value pair? If it only contains 1 key/value pair, I'm assuming I would need to create multiple objects for the JSON that I have below which I can the use a loop to iterate over and add the values to a drop down menu?
{
"1": "Annie",
"2": "Olaf",
"3": "Galio",
"4": "TwistedFate",
"5": "XinZhao",
"6": "Urgot",
"7": "Leblanc",
"8": "Vladimir",
"9": "FiddleSticks",
"10": "Kayle",
"11": "MasterYi",
"12": "Alistar",
"13": "Ryze",
"14": "Sion",
"15": "Sivir",
"16": "Soraka",
"17": "Teemo",
"18": "Tristana",
"19": "Warwick",
"20": "Nunu"
}
Essentially what I am aiming to do is:
1) Create a list of names with the Values.
2) Sort the list of names (as it comes unsorted) in alphabetical order
3) Loop through the list and add each name to a drop down menu
4) When a name in the drop down menu is selected, the key associated with that value is passed to another url which receives more data.
Sorry if this is unclear. I've spent a couple of hours trying to understand how to get elements from JSON and display it, as well as trying to create a list where I can use the key to display information the name but have had no luck except for using a for-each loop.
Let's use Jackson's feature that allows you to map any property to a single method (you don't really need a getter here I believe). Just swap the key and value in this universal setter, and add to a TreeMap, which is already sorted by key (name). Then you can output the keys (names) in the alphabetical order and get an ID by name easily.
public static void main(String[] args) throws IOException {
String json = "....."; // your JSON string here
com.fasterxml.jackson.databind.ObjectMapper mapper =
new com.fasterxml.jackson.databind.ObjectMapper();
ReverseMap pairs = mapper.readValue(json, ReverseMap.class);
for (Map.Entry<Object, String> entry : pairs.getValues().entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
public class ReverseMap {
private TreeMap<Object, String> mapping = new TreeMap<>();
#com.fasterxml.jackson.annotation.JsonAnySetter
public void add(String name, Object value) {
mapping.put(value, name);
}
public Map<Object, String> getValues() {
return mapping;
}
}
Gson Bean Mapping Solution
Okay, what you have is a bit unusual for a JSON object; the keys (the numbers in your case) essentially represent properties of their contained object. That's workable, but you have to understand that, for example, when looking for "Annie" in the JSON object, if you use Gson to map to a "bean" class, which we'll call Data (as in the linked example), then you'd have to create a data object like so:
class Data {
private String _1;
// ...
private String _20;
public String get1() { return _1; }
public void set1(String _1) { this._1 = _1; }
// ...
public String get20() { return _20; }
public void set20(String _20) { this._20 = _20; }
}
And by using Data data = new Gson().fromJson(myJsonString, Data.class); on the given string, you'd be able to find "Annie" by calling... uh... data.get1()?
Clearly, this isn't a good solution.
Better Solutions
Since your data doesn't follow the typical format for a JSON object, you have two options:
If you can, refactor your JSON representation to a more verbose, but better representation for parsing.
Use a different approach to parse the existing JSON.
Solution 1: Changing the JSON representation
Refactoring the JSON would result in an object that (preferably) would look like this:
{
"champions" : [
{
"index" : 1,
"name" : "Annie"
},
{
"index" : 2,
"name" : "Olaf"
},
// ...
]
}
This could map easily to a couple of beans that look like this:
class Data {
private List<Champion> champions;
// TODO getters and setters
}
class Champion {
private int index;
private String name;
// TODO getters and setters
}
However, this adds a lot of unnecessary clutter to the JSON object, and isn't really necessary with only two fields per champion (the name, and their index).
You could simplify that further like so:
{
"champions" : [
"Annie",
"Olaf",
// ...
]
}
The bean class for that would then be:
class Data {
private List<String> champions;
// TODO getters and setters
}
Much simpler, but still requires a change to the JSON you're getting, which in some situations isn't possible. If you used this, though, you could also get rid of the "bean" class entirely, via:
List<String> champions = (List<String>) new Gson().fromJson(myJsonString, new TypeToken<List<String>>(){}.getType());
Solution 2: Changing how the JSON is parsed
The arguably better and cleaner solution is just to change how the JSON is parsed.
The goal here (if I understand you correctly) is to parse the JSON and spit out a collection of strings representing each champion's name, accessible by the numeric index of the champion in the JSON representation.
As such, and because of the way the JSON object is laid out as a simple mapping of strings to strings, we can use Gson to pipe directly into a Map<String, Object>, like so:
Map<String, String> mappedValues = new Gson().fromJson(myJsonString, Map.class);
String anniesName = mappedValues.get("1"); // "Annie"
String olafsName = mappedValues.get("2"); // "Olaf"
boolean hasTwentyOneElements = mappedValues.containsKey("21"); // false
This is shorter, requires no "bean" classes, and keeps the original JSON representation. The downside is that you can't easily tell whether the indices of each entry are correct and consistent; ie. if someone types in the wrong number, or deletes one of the entries.
To get a container of all keys, you just use mappedValues.keySet(), and to get a container of all key-value pairs, you use mappedValues.entrySet(), which gives you a Set<Map.Entry<String, String>>. Both of those can be iterated over, and may be in random order (I'm not sure whether the underlying Map implementation preserves insertion order or not).
To get the index for a given name (ie. champ), you'd use something similar to the following:
String index = null;
for (Map.Entry<String, String> entry : mappedValues.entrySet()) {
if (champ.equals(entry.getValue())) {
index = entry.getKey();
break;
}
}
Of course, you'd have to check to see if index is null after this, and handle that appropriately, but it's easily doable.
EDIT: #vempo's answer provides a cleaner, more efficient lookup strategy by means of inverting the map (although the answer is written for Jackson, instead of Gson); an adaptation of this for Gson is as follows (and yes, there is a vastly superior version in java-8, left out for sake of availability):
public Map<String, String> invertMap(Map<String, String> input) {
Map<String, String> newMap = new LinkedTreeMap<String, String>(); // TODO Pick optimal storage class
for (Map.Entry<String, String> entry : input.entrySet()) {
newMap.put(entry.getValue(), entry.getKey());
}
return newMap;
}
// ...
Map<String, String> mappedValues = invertMap(new Gson().fromJson(myJsonString, Map.class));
String annieIndex = mappedValues.get("Annie"); // "1"
String olafIndex = mappedValues.get("Olaf"); // "2"
It's worth noting that this sacrifices efficiency of constructing the map by effectively building it twice (once by Gson and once more to invert), but it makes value lookup much more efficient.

Java : Json with duplicate keys to map using Jackson

I have a json file with same key but different values as follows,
{
"domains" : {
"A" : {
"name" : "a",
"type" : "a1"
},
"B" :{
"name" : "r",
"type" : "g1"
},
"A" : {
"name" : "b",
"type" : "b1"
}
}
}
which is coming from external system.
How to convert the json to java map object and access the different values of the key: A
I am using something like below,
map = mapper.readValue(json, new TypeReference<HashMap<String,String>>(){});
which returns a map with unique keys. But I need a map object to hold all the data from json file.
Anyway to achieve this?
I agree with comments by #fge.
But if you really insists on solving this, you could sub-class HashMap (or any other Map), override its put method, and handle duplicates using whatever mechanism you want. Just make sure your Map has a no-arguments constructor.
Guava may also have a datatype that would allow retaining duplicates (Multimap?). If so, you will want to use Jackson's Guava module: https://github.com/FasterXML/jackson-datatype-guava
Answering since a related question was marked duplicate but seems to address the reverse problem where JSON with duplicate keys needs to be created. So that is Java Model -> JSON with duplicate keys.
Simplest way I found was to implement a custom serializer.
public class CustomSerializer extends StdSerializer<ModelToSerialize> {
public CustomSerializer(Class<ModelToSerialize> t) {
super(t);
}
#Override
public void serialize(ModelToSerialize value, com.fasterxml.jackson.core.JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
gen.writeStringField("DuplicateJsonKey", value.getDup1());
gen.writeStringField("DuplicateJsonKey", value.getDup2());
// Map all other values on value that you want to be present in the JSON
gen.writeEndObject();
}
}
And then when you go to serialize:
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(ModelToSerialize.class, new CustomSerializer(ModelToSerialize.class));
objectMapper.registerModule(simpleModule);
String sr = objectMapper.writeValueAsString(modelToSerialize);

Creating a Java Object from JSON Object containing JSON Maps using GSON

So, I've been doing GSON for a while, but I just now ran into the issue of using JSON Maps, which as I understand it are basically just Key Value pairs where he value is a JSON object.
To give you an idea where I'm coming from, here's my JSON
{
"configs":[
{
"com.hp.sdn.adm.alert.impl.AlertManager":{
"trim.alert.age":{
"def_val":"14",
"desc":"Days an alert remains in storage (1 - 31)",
"val":"14"
},
"trim.enabled":{
"def_val":"true",
"desc":"Allow trim operation (true/false)",
"val":"true"
},
"trim.frequency":{
"def_val":"24",
"desc":"Frequency in hours of trim operations (8 - 168)",
"val":"24"
}
}
},
{
"com.hp.sdn.adm.auditlog.impl.AuditLogManager":{
"trim.auditlog.age":{
"def_val":"365",
"desc":"Days an audit log remains in storage (31 - 1870)",
"val":"365"
},
"trim.enabled":{
"def_val":"true",
"desc":"Allow trim operation (true/false)",
"val":"true"
},
"trim.frequency":{
"def_val":"24",
"desc":"Frequency in hours of trim operations (8 - 168)",
"val":"24"
}
}
}
]
}
All of those com.hp.sdn... things are dynamic, as in I won't know the key names until Runtime. I figured I can just use a HashMap for this and GSON would figure it out, but I'm not sure what I would name the field...
Here are my classes that I have so far
package com.wicomb.sdn.models.configs;
import java.util.HashMap;
import com.wicomb.sdn.types.Model;
public class ConfigResponse extends Model {
private ConfigGroup[] configs;
}
package com.wicomb.sdn.models.configs;
import com.wicomb.sdn.types.Model;
public class ConfigGroup extends Model {
private HashMap<String,Config> ????;
}
TL;DR How should I write the Java Class to let Gson know how to handle a Json property that I don't know the name of.. And lots of them.
You can feed Gson with a HashMap (or if children order is important a LinkedHashMap) than you iterate over the entries or the keys normally as you would do to any other map.
In the code below I use the following json as input:
{
"test": 123,
"nested":{
"nested-1": 1,
"nested-2": 2
}
}
And the code looks like these:
public void testGson() {
String input = "{\"test\": 123, \"nested\": {\"nested-1\": 1, \"nested-2\": 2}}";
LinkedHashMap<String, Object> json = new Gson().fromJson(input, LinkedHashMap.class);
// iterating
for(Map.Entry<String, Object> entry : json.entrySet()){
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
// testing values
System.out.println(json.get("test")); // should be 123
Map<String, Object> nested = (Map<String, Object>) json.get("nested");
System.out.println(nested.get("nested-1")); // should be 1
System.out.println(nested.get("nested-2")); // should be 2
}

Categories

Resources