how to update the json with map values using java? - java

I have below json:
{
"type":Flowers,
"input_data": [
{
"id": 35742,
"Request_ID": 8383,
"data_line": "*****Sample text here*****",
"variety": {
"Rose": 0,
"Jasmine": 0,
"Lily": 1,
"Sunflower": 1,
},
"responded": 1
},
{
"id": 35992,
"Request_ID": 8983,
"data_line": "*****Sample text here*****",
"variety": {
"Rose": 1,
"Jasmine": 0,
"Lily": 0,
"Sunflower": 1,
},
"responded": 1
}
],
"token": "F9500930C-15A6-4111-AD7F-7D0DF0CEE4D8"
}
How do I map the values in "variety" with "id"?
Note: id is coming from the response of a different API which should be replaced in this json and mapped with variety.

It's not a good idea to have a field like 'input_data' in your json.
Try to redo your json that's aligned to your data model and something that can be mapped to Java objects.
GSON is a great library for dealing with JSONs in Java - https://github.com/google/gson
I can give you a utility method to get a list of Java objects from a json reprenstation like this:
private static Type typeOfT = TypeToken.getParameterized(List.class, <<your-class>>.class).getType();
public static <T> List<T> loadListFromFile(String fileName, Class<T> clazz) throws Exception{
File file = new File(fileName);
String json = new String(Files.readAllBytes(file.toPath()));
return gson().fromJson(json, typeOfT);
}

First, your JSON string is invalid (e.g. Flowers should be quoted by double quotes). Second, I am confused about what you really want. Therefore, according to the comment under your question, you said that you need a mapping between id and variety. Here comes one way to achieve that by following steps with Jackson (One of the most popular JSON libraries.).
Step 1
Create nested POJOs for deserialization.
class Result {
#JsonProperty("input_data")
private List<InputData> inputData;
//general getter and setter
}
class InputData {
private int id;
private Variety variety;
//general getters and setters
}
class Variety {
#JsonProperty("Rose")
private int rose;
#JsonProperty("Jasmine")
private int jasmine;
#JsonProperty("Lily")
private int lily;
#JsonProperty("Sunflower")
private int sunflower;
//general getters, setters and toString()
}
Step 2
Deserialize JSON response to Result and transform the InputData into Map<Integer, Variety> with Java 8.
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Result result = mapper.readValue(jsonStr, Result.class);
Map<Integer, Variety> idVarietyMap = result.getInputData().stream()
.collect(Collectors.toMap(InputData::getId, InputData::getVariety));
System.out.println(idVarietyMap.toString());
Console output
{35992=Variety [rose=1, jasmine=0, lily=0, sunflower=1], 35742=Variety [rose=0, jasmine=0, lily=1, sunflower=1]}

Related

Simplest way to convert this array in to the specified one using Java

I have this String Json Payload
[
"key1":{
"atr1":"key1",
"atr2":"value1",
"atr3":"value2",
"atr4":"value3,
"atr5":"value4"
},
"key2":{
"atr1":"key2",
"atr2":"value5",
"atr3":"value6",
"atr4":value7,
"atr5":"value8"
}
]
and I want it to be converted in to the following format using Java
[
{
"atr2":"value1",
"atr3":"value2",
"atr4":"value3,
"atr5":"value4"
},
{
"atr2":"value5",
"atr3":"value6",
"atr4": "value7",
"atr5":"value8"
}
]
What would be the simplest way of transforming this ?
You cannot, because the example below is not valid json.
Check it out using this JSON validator.
If you paste this in (I've fixed some basic errors with lack of quotes)
{
{
"atr2":"value1",
"atr3":"value2",
"atr4":"value3",
"atr5":"value4"
},
{
"atr2":"value5",
"atr3":"value6",
"atr4":"value7",
"atr5":"value8"
}
}
You will get these errors ...
It can work if you change the target schema to something like this by using a json-array to contain your data.
[
{
"atr2":"value1",
"atr3":"value2",
"atr4":"value3",
"atr5":"value4"
},
{
"atr2":"value5",
"atr3":"value6",
"atr4":"value7",
"atr5":"value8"
}
]
If this works for you, then this problem can easily be solved by using the ObjectMapper class.
You use it to deserealize the original JSON into a class, which has two fields "key1" and "key2"
Extract the values of these fields and then just store them in an array ...
Serialize the array using the ObjectMapper.
Here a link, which explains how to use the ObjectMapper class to achieve the goals above.
EDIT:
So you'll need the following classes to solve the problem ...
Stores the object data
class MyClass {
String atr2;
String art3;
}
Then you have a container class, which is used to store the initial json.
class MyClassContainer {
MyClass key1;
MyClass key2;
}
Here's how you do the parse from the original json to MyClassContainer
var mapper = new ObjectMapper()
var json = //Get the json String somehow
var myClassContainer = mapper.readValue(json,MyClassContainer.class)
var mc1 = myClassContainer.getKey1();
var mc2 = myClassContainer.getKey2();
var myArray = {key1, key2}
var resultJson = mapper.writeValueAsString(myArray)
Assuming that you will correct the JSON into a valid one (which involves replacing the surrounding square braces with curly ones, and correct enclosure of attribute values within quotes), here's a simpler way which involves only a few lines of core logic.
try{
ObjectMapper mapper = new ObjectMapper();
mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
HashMap<String, Data> map = mapper.readValue( jsonString, new TypeReference<HashMap<String, Data>>(){} );
String json = mapper.writeValueAsString( map.values() );
System.out.println( json );
}
catch( JsonProcessingException e ){
e.printStackTrace();
}
jsonString above is your original JSON corrected and valid JSON input.
Also notice the setting of FAIL_ON_UNKNOWN_PROPERTIES to false to allow atr1 to be ignored while deserializing into Data.
Since we are completely throwing away attr1 and its value, the Data class will represent all fields apart from that.
private static class Data{
private String atr2;
private String atr3;
private String atr4;
private String atr5;
}

How to get json value with jackson?

String url = "https://ko.wikipedia.org/w/api.php?action=query&format=json&list=search&srprop=sectiontitle&srlimit=1&srsearch=grand-theft-auto-v";
String test = restTemplate.getForObject(url, String.class);
Map<String, String> testToJson = objectMapper.readValue(test, Map.class);
testToJson is:
{
batchcomplete: "",
continue: {
sroffset: 1,
continue: "-||",
},
query: {
searchinfo: {
totalhits: 12
},
search: [
{
ns: 0,
title: "그랜드 테프트 오토 V",
pageid: 797633,
}
],
},
}
I want to get title value.
I try
testToJson.get("title")
but it returns null.
How to get title value with jackson?
You can deserialise it to a JsonNode and use JSON Pointer to get required field:
JsonNode node = mapper.readValue(jsonFile, JsonNode.class);
String title = node.at("/query/search/0/title").asText();
you could build a class for this json result then read from it.
public class Result {
private JsonNode searchinfo;
private JsonNode[] searches;
}
// then read:
Result testToJson = objectMapper.readValue(test, Result.class);
System.out.println(testToJson.getSearches(0).get("title"));
refer
It is impossible to read JSON into an instance of a generic class like that because the info about generics are used in compile time and already lost when program is running.
Jackson captures the data about generics using a sub-classed instance of TypeReference<T>.
Map<String, String> testToJson = objectMapper.readValue(test, new TypeReference<Map<String, String>>(){});
The problem with this approach is that Map<String, String> almost never describes complex data (like in the example) correctly. The example contains not only string values, there are numbers and even nested objects.
In situations like that, when you don't want or cannot write a class that describes the structure of the JSON, the better choice is parsing the JSON into a tree structure and traverse it. For example:
JsonNode node = objectMapper.readTree(test);
String title = node.get("query").get("search").get(0).get("title").asText();
Integer offset = node.get("continue").get("strOffset").asInt()

Parsing JSON double brackets with Java

I'm having some trouble as I've hit a roadblock in learning how to parse JSON with json simple.
To make myself concise;
I am trying to parse this bit of JSON from a url
"hourly": {
"summary": "Clear throughout the day.",
"icon": "clear-day",
"data": [
{
"time": 1550379600,
"summary": "Clear",
"icon": "clear-day",
"precipIntensity": 0,
"precipProbability": 0,
"temperature": 20.18,
"apparentTemperature": 14.31,
"dewPoint": 13.79,
"humidity": 0.76,
"pressure": 1024.47,
"windSpeed": 4.08,
"windGust": 5.25,
"windBearing": 30,
"cloudCover": 0.07,
"uvIndex": 0,
"visibility": 10,
"ozone": 342.67
}
so, in using json simple, this is how I am parsing this JSON
try{
String genreJson = IOUtils.toString(new URL(url));
JSONObject genreJsonObject = (JSONObject) JSONValue.parseWithException(genreJson);
//get the title
System.out.println(genreJsonObject.get("hourly")); //THIS WORKS
//System.out.println(genreJsonObject.get("visibility"));
//get the data
JSONArray genreArray = (JSONArray) genreJsonObject.get(0);
//get the first genre
//JSONObject firstGenre = (JSONObject) genreArray.get(0);
//System.out.println(firstGenre.get("data"));
}
catch (IOException | ParseException e){
e.printStackTrace();
}
So, in calling System.out.println(genreJsonObject.get("hourly")); I get everything within the brackets titled "hourly". My intent is to parse for the data within the "hourly" bracket, although I can't figure out how to parse for a title within a titled bracket. Specifically, I need the time, the precipProbability, precipIntensity, and precipProbability (this attribute is not in the example).
I apologize for any lack of detail as I'm doing this as part my first hackathon, and I'm trying not to fall asleep right now.
I greatly appreciate anyone's help.
This is object to describe your json "data" part:
class Data {
private Long time;
private String summary;
private String icon;
private Double dewPoint;
// add all the fields you need
// add empty constructor + getters and setters
}
if you want to skip some of the fields in "data" which you don't care about use
#JsonIgnoreProperties(ignoreUnknown = true)
class Data{
...
}
Your parent object is "hourly", so:
class Hourly {
private String summary;
private String icon;
private List<Data> data;
// add all the fields you need
// add empty constructor + getters and setters
}
At this point the Java POJO classes describe the Json data, so you're ready to map the JSON to the Java classes.
To read this with Jackson, you will need the String representation of the Json (without any URL parts), so let's assume you can do that in a string called "inputJsonString".
Reading this with Jackson will be as simple as:
ObjectMapper mapper = new ObjectMapper();
Hourly hourly = mapper.readValue(inputJsonString, Hourly.class);

How to iterate JSON Array and extract each JSON Object from it using GSON?

Below is my JSON String which I am getting back by calling from a service API. I have shorten it down by having only three reportRecords for the understanding purpose. In general, it might have ~500 reportRecords
{
   "aggRecords": {
      "reportRecords": [
         {
            "min": 0,
            "max": 12,
            "avg": 0.3699187,
            "count": 246,
            "sumSq": 571,
            "stddev": 1.4779372,
            "median": 0,
            "percentileMap": {
               "95": 4
            },
            "metricName": "TransactionDuration",
            "dimensions": {
               "env": "dev",
               "pool": "titan",
               "Name": "PostProcessing",
               "Type": "PostProcessing"
            },
            "value": 91
         },
         {
            "min": 0,
            "max": 23,
            "avg": 2.3991289E-4,
            "count": 1463031,
            "sumSq": 3071,
            "stddev": 0.045814946,
            "median": 0,
            "percentileMap": {
               "95": 0
            },
            "metricName": "TransactionDuration",
            "dimensions": {
               "env": "dev",
               "pool": "titan",
               "Name": "ResourceContext",
               "Type": "ResourceContext"
            },
            "value": 351
         },
         {
            "min": 0,
            "max": 1209,
            "avg": 1.9203402,
            "count": 7344636,
            "sumSq": 71832774,
            "stddev": 2.4683187,
            "median": 2,
            "percentileMap": {
               "95": 4
            },
            "metricName": "TransactionDuration",
            "dimensions": {
               "env": "dev",
               "pool": "titan",
               "Name": "Client::Sync",
               "Type": "Client::Sync"
            },
            "value": 14104200
         }
      ]
   },
   "minRecordsMap": {}
}
Now From the above JSON response, I need to extract reportRecords whose Name is Client::Sync. Meaning, I need to extract below reportRecords from the above JSON response only.
         {
            "min": 0,
            "max": 1209,
            "avg": 1.9203402,
            "count": 7344636,
            "sumSq": 71832774,
            "stddev": 2.4683187,
            "median": 2,
            "percentileMap": {
               "95": 4
            },
            "metricName": "TransactionDuration",
            "dimensions": {
               "env": "dev",
               "pool": "titan",
               "Name": "Client::Sync",
               "Type": "Client::Sync"
            },
            "value": 14104200
         }
And now I need to parse the above reportRecords for Client::Sync to below object -
public class DataMetrics {
private String pool;
private String name;
private String type;
private String env;
private String metricName;
private String percentile;
private String median;
private String stdDev;
private String sumSq;
private String count;
private String avg;
private String max;
private String min;
// getters and setters here
}
Above variable, maps like this -
pool is titan
name is Client::Sync
type is Client::Sync
env is dev
metricNname is TransactionDuration
95th percentile is 4
median is 2
stdDev is 2.4683187
sumSq is 71832774
count is 7344636
avg is 1.9203402
max is 1209
min is 0
I am using GSON library here and below is what I have tried so far -
private static RestTemplate restTemplate = new RestTemplate();
public static void main(String[] args) {
String jsonLine = restTemplate.getForObject("some_url", String.class);
System.out.println(jsonLine); // here jsonLine will give me above big JSON String
JsonElement jelement = new JsonParser().parse(jsonLine);
JsonObject jobject = jelement.getAsJsonObject();
jobject = jobject.getAsJsonObject("aggRecords");
JsonArray jarray = jobject.getAsJsonArray("reportRecords");
// now how do I iterate JsonArray and get each JSON object
// and then check "name" property of each object, if "Client::Sync" found, read that object for all properties
// and set it using setters.
}
Now I am not able to understand how do I iterate JsonArray and extract each JSON object from it?
So you have the JsonArray object with your records, here's what you do to get your functional objects:
Type type = new TypeToken<List<DataMetrics>>() {}.getType();
List<DataMetrics> records = gson.fromJson(jsonArrayThatYouHave, type);
Then you iterate through you objects and filter the ones you need.
In java 8 you can do this:
List<DataMetrics> result = records.stream().filter(record -> record.name.equals("Client::Sync")).collect(toList());
This approach is converting all objects and iterating after, if exactly this part of code is performance critical, you can still iterate through json and convert only necessary objects (but i doubt that this will be actually faster than described above).
Anyway this is more maintainable and understandable code.
UPDATE:
the same for java 7 will be:
List<DataMetrics> result = new LinkedList<>();
for(DataMetrics record : records){
if(record.name.equals("Client::Sync")){
result.add(record);
}
}
Or if you want to iterate json and parse only required ones heres what you can do:
Type type = new TypeToken<List<DataMetrics>>() {}.getType();
for(JsonElement elem : jsonArrayThatYouHave) {
if (elem.getAsJsonObject().get("name").getAsString().equals("Client::Sync")) {
result.add(gson.fromJson(elem, type));
}
}
but I dont think this is actually faster than the first one because in both cases you are converting json to java functional object with parser and getting JsonArray or anything else. Taking into consideration the fact that both are Googles libs, i assume that parsing from JsonObject to some specific type with gson is way faster than from String (raw json) to the same specific type...
You may want to parse all the objects, and then filter the ones you're interested in.
After you've obtained jArray, try:
//get json array from json string
JsonArray jarray = jobject.getAsJsonArray("reportRecords");
//get a list of reportRecords using Gson
Gson mGson = new Gson();
Type listType = new TypeToken<List<DataMetrics>>(){}.getType();
List<DataMetrics> dataMetricsList = mGson.fromJson(reportRecordsJsonArray, listType);
//Filter only the ones with a specific name
List<DataMetrics> dataMetricsFilteredList = dataMetricsList.stream().filter(dataMetric -> dateMetric.getName.equals("Client::Sync"));
i didn't try it but it may work.
public void getFromJson(JSONObject json)
{
JSONArray jarray = (JSONArray) json.get("reportRecords");
List<DataMetrics> myList = new ArrayList();
for(int i = 0; i < jarray.size(); i++)
{
myList.add((DataMetrics) getClassFromJsonObject((JSONObject) jarray.get(i),
DataMetrics.class));
}
}
////
public Object getClassFromJsonObject(JSONObject json, Class myClass){
Object object = new Object();
ObjectMapper obj = JSONMapperFactory.createMapper();
obj.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
object = obj.readValue(json.toString(), myClass);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return myClass.cast(object);
}

Mapping between JSON formats in Java

I'm coming to Java from JavaScript/Ruby. Let's say I've got the following JSON object for an animal:
{
name: {
common: "Tiger",
latin: "Panthera tigris"
}
legs: 4
}
I'm dealing with lots of animal APIs, and I want to normalize them all into my own common format, like:
{
common_name: "Tiger",
latin_name: "Panthera tigris",
limbs: {
legs: 4,
arms: 0
}
}
In, say, JavaScript, this would be straightforward:
normalizeAnimal = function(original){
return {
common_name: original.name.common,
latin_name: original.name.latin,
limbs: {
legs: original.legs || 0,
arms: original.arms || 0
}
}
}
But what about in Java? Using the JSONObject class from org.json, I could go down the road of doing something like this:
public JSONObject normalizeAnimal(JSONObject original) throws JSONException{
JSONObject name = original.getJSONObject("name");
JSONObject limbs = new JSONObject();
JSONObject normalized = new JSONObject();
normalized.put("name_name", name.get("common"));
normalized.put("latin_name", name.get("latin"));
try{
limbs.put("legs", original.get("legs");
}catch(e){
limbs.put("legs", 0);
};
try{
limbs.put("arms", original.get("arms");
}catch(e){
limbs.put("arms", 0);
};
normalized.put("limbs", limbs);
return normalized;
}
This gets worse as the JSON objects I'm dealing with get longer and deeper. In addition to all of this, I'm dealing with many providers for animal objects and I'll eventually be looking to have some succinct configuration format for describing the transformations (like, maybe, "common_name": "name.common", "limbs.legs": "legs").
How would I go about making this suck less in Java?
Use a library like Gson or Jackson and map the JSON to a Java Object.
So you're going to have a bean like
public class JsonAnima {
private JsonName name;
private int legs;
}
public class JsonName {
private String commonName;
private String latinName;
}
which can be easily converted with any library with something like (with Jackson)
ObjectMapper mapper = new ObjectMapper();
JsonAnimal animal = mapper.readValue(jsonString, JsonAnimal.class);
then you can create a "converter" to map the JsonAnimal to you Animal class.
This can be a way of doing it. : )
Some links:
Gson: http://code.google.com/p/google-gson/
Jackson: http://wiki.fasterxml.com/JacksonHome
The pure Java solutions all are challenged to deal with unreliable structure of your source data. If you're running in a JVM, I recommend that you consider using Groovy to do the Parse and the Build of your source JSON. The result ends up looking a lot like the Javascript solution you outlined above:
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
def originals = [
'{ "name": { "common": "Tiger", "latin": "Panthera tigris" }, "legs": 4 }',
'{ "name": { "common": "Gecko", "latin": "Gek-onero" }, "legs": 4, "arms": 0 }',
'{ "name": { "common": "Liger" }, "legs": 4, "wings": 2 }',
'{ "name": { "common": "Human", "latin": "Homo Sapien" }, "legs": 2, "arms": 2 }'
]
originals.each { orig ->
def slurper = new JsonSlurper()
def parsed = slurper.parseText( orig )
def builder = new JsonBuilder()
// This builder looks a lot like the Javascript solution, no?
builder {
common_name parsed.name.common
latin_name parsed.name.latin
limbs {
legs parsed.legs ?: 0
arms parsed.arms ?: 0
}
}
def normalized = builder.toString()
println "$normalized"
}
Running the script above deals with "jagged" JSON (not all elements have the same attributes) and outputs like...
{"common_name":"Tiger","latin_name":"Panthera tigris","limbs":{"legs":4,"arms":0}}
{"common_name":"Gecko","latin_name":"Gek-onero","limbs":{"legs":4,"arms":0}}
{"common_name":"Liger","latin_name":null,"limbs":{"legs":4,"arms":0}}
{"common_name":"Human","latin_name":"Homo Sapien","limbs":{"legs":2,"arms":2}}
If you'll be using this for many different types of objects, I would suggest to use reflection instead of serializing each object manually. By using reflection you will not need to create methods like normalizeAnimal, you just create one method or one class to do the serialization to json format.
If you search for "mapping json java" you'll find some useful references. Like gson. Here is an example that is on their website:
class BagOfPrimitives {
private int value1 = 1;
private String value2 = "abc";
private transient int value3 = 3;
BagOfPrimitives() {
// no-args constructor
}
}
//(Serialization)
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);
///==> json is {"value1":1,"value2":"abc"}
///Note that you can not serialize objects with circular references since that will result in infinite recursion.
//(Deserialization)
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
//==> obj2 is just like obj
You can try little jmom java library
JsonValue json = JsonParser.parse(stringvariablewithjsoninside);
Jmom mom = Jmom.instance()
.copy("/name/common", "/common_name", true)
.copy("/name/latin", "/latin_name", true)
.copy("/arms", "/limbs/arms", true)
.copy("/legs", "/limbs/legs", true)
.remove("/name")
;
mom.apply(json);
String str = json.toPrettyString(" ");

Categories