How to extract property from JSON embedded within JSON? - java

This is the JSON String I am getting back from a URL and I would like to extract highDepth value from the below JSON String.
{
"description": "",
"bean": "com.hello.world",
"stats": {
"highDepth": 0,
"lowDepth": 0
}
}
I am using GSON here as I am new to GSON. How do I extract highDepth from the above JSON Strirng using GSON?
String jsonResponse = restTemplate.getForObject(url, String.class);
// parse jsonResponse to extract highDepth

You create a pair of POJOs
public class ResponsePojo {
private String description;
private String bean;
private Stats stats;
//getters and setters
}
public class Stats {
private int highDepth;
private int lowDepth;
//getters and setters
}
You then use that in the RestTemplate#getForObject(..) call
ResponsePojo pojo = restTemplate.getForObject(url, ResponsePojo.class);
int highDepth = pojo.getStats().getHighDepth();
No need for Gson.
Without POJOs, since RestTemplate by default uses Jackson, you can retrieve the JSON tree as an ObjectNode.
ObjectNode objectNode = restTemplate.getForObject(url, ObjectNode.class);
JsonNode highDepth = objectNode.get("stats").get("highDepth");
System.out.println(highDepth.asInt()); // if you're certain of the JSON you're getting.

Refering to JSON parsing using Gson for Java, I would write something like
JsonElement element = new JsonParser().parse(jsonResponse);
JsonObject rootObject = element.getAsJsonObject();
JsonObject statsObject = rootObject.getAsJsonObject("stats");
Integer highDepth = Integer.valueOf(statsObject.get("highDepth").toString());

Related

Can not find a (Map) Key deserializer for type [simple type, class com.example.app.ReferralApiModel]

I'm trying to fetch JSON data from my website throw REST API with retrofit2.
But when I run the app this error message show:
Can not find a (Map) Key deserializer for type [simple type, class com.example.app.ReferralApiModel]
I'm using retrofit library.
This is my code for the retrofit call:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(AppConfig.URL)
.addConverterFactory(JacksonConverterFactory.create())
.client(defaultHttpClient)
.build();
ReferralsPlaceHolderApi placeHolderApi = retrofit.create(ReferralsPlaceHolderApi.class);
Call<List<Map<ReferralApiModel, String>>> call = placeHolderApi.getReferrals();
And this is my ReferralsPlaceHolderApi class:
public interface ReferralsPlaceHolderApi {
#JsonDeserialize(keyAs = ReferralsCustomDeserializer.class)
#GET(AppConfig.ENDPOINT_REFERRALS)
Call<List<Map<ReferralApiModel, String>>> getReferrals();
}
Also this is my ReferralApiModel class:
public class ReferralApiModel {
private String date;
private String amount;
private String currency;
private String status;
public ReferralApiModel() {}
public ReferralApiModel(String date, String amount, String currency, String status) {
this.date = date;
this.amount = amount;
this.currency = currency;
this.status = status;
}
public String getDate() {
return date;
}
public String getAmount() {
return amount;
}
public String getCurrency() {
return currency;
}
public String getStatus() {
return status;
}
}
This is the json data that I'm trying to get:
"[{\"id\":\"1\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"1\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"302\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 12:53:29\",\"status\":\"0\",\"payment\":\"0\",\"username\":\"aaa\"},{\"id\":\"2\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"2\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"303\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 13:03:43\",\"status\":\"1\",\"payment\":\"0\",\"username\":\"aaa\"},{\"id\":\"3\",\"refferal_wp_uid\":\"0\",\"campaign\":\"\",\"affiliate_id\":\"5\",\"visit_id\":\"2\",\"description\":\"\",\"source\":\"woo\",\"reference\":\"304\",\"reference_details\":\"68\",\"parent_referral_id\":\"0\",\"child_referral_id\":\"0\",\"amount\":\"1500.00\",\"currency\":\"\د\ج\",\"date\":\"2022-01-31 13:04:33\",\"status\":\"2\",\"payment\":\"0\",\"username\":\"aaa\"}]"
Can anyone help me with this?.
Also I've found that this problem may be a class mapping problem, from this answer :
https://stackoverflow.com/a/16383752/8055951
If it's ?!, Can someone tell me how to map the ReferralsPlaceHolderApi class.
Thanks.
Jackson cannot deserialize custom classes as map keys. The key of your deserialized map is ReferralApiModel. I order to achieve it, you need to write your own KeyDeserializer and register it for your class with Jackson. You can see here or here how to do that.
Also the json string in the question makes it look as if you don't need to deserialize into List<Map<ReferralApiModel, String>>, but into List<ReferralApiModel> instead. Which would make writing custom key deseriaslizers redundant.
Edit: Ok, receiving json array, which has been json sting-ified is just strange. It would be best, if someone on your team is responsible for this API and can fix it. If not, you have workarounds:
Parse twice with object mapper - first parse it to normal string, which would be json array, then parse this string into List<YourObject>
ObjectMapper mapper = new ObjectMapper();
String string = mapper.readValue(initialJson, String.class);
List<ReferralApiModel> list = mapper.readValue(string, TypeFactory.defaultInstance().constructCollectionType(List.class, ReferralApiModel.class));
list.forEach(System.out::println);
Turn it manually into proper json array. That means remove first and last char - double quote, and remove all those escapes - \. Something like this:
String jsonString = "the string";
jsonString = jsonString.substring(1, jsonString.length() - 1).replace("\\", "");
ObjectMapper mapper = new ObjectMapper();
List<ReferralApiModel> list = mapper.readValue(jsonString, TypeFactory.defaultInstance().constructCollectionType(List.class, ReferralApiModel.class));
list.forEach(System.out::println);

How can i use replace in JSON?

Heyy,
I have a JSON String i.e.
{"userId":"WaNenOnQt","photos":[{"photo_url":"vendor_photos/WaNenOnQt/web_(138)(4thcopy).JPG","index":1},{"photo_url":"vendor_photos/WaNenOnQt/54230451_265006064447640_7942942433146217157_n.jpg","index":2}]}
I want only the List data i.e. -
[{"photo_url":"vendor_photos/WaNenOnQt/web_(138)(4thcopy).JPG","index":1},{"photo_url":"vendor_photos/WaNenOnQt/54230451_265006064447640_7942942433146217157_n.jpg","index":2}]
Is there any replace function in java or how can i segregate the list ?
assuming you are getting that JSON through an endpoint you are exposing, you should bind it to the method signature, for example if you are using Spring:
public class MyPojo {
private String userId;
private List<Photo> photoList;
//getters & setters
}
Photo class
public class Photo {
#JsonProperty("photo_url")
private String url;
private int index;
//getters & setters
}
Controller class
#RequestMapping(value = "/test", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> test(#RequestBody MyPojo request) {
List<Photo> photos = request.getPhotoList();
}
Alternatively if you don't have an endpoint, you can manually transform the JSON String to a POJO and vice-versa, using Java's ObjectMapper. For example:
public void transform(String jsonString) throws... {
ObjectMapper mapper = new ObjectMapper();
MyPojo pojo = mapper.readValue(jsonString, MyPojo.class);
List<Photo> photo = pojo.getPhotoList();
}
I'm also assuming that you need a Java List, and don't need the JSON array simply as a String.
You van use small json library
String jsonstring = "{\"userId\":\"WaNenOnQt\",\"photos\":[{\"photo_url\":\"vendor_photos/WaNenOnQt/web_(138)(4thcopy).JPG\",\"index\":1},{\"photo_url\":\"vendor_photos/WaNenOnQt/54230451_265006064447640_7942942433146217157_n.jpg\",\"index\":2}]}";
JsonValue json = JsonParser.parse(jsonstring);
JsonValue photos = json.asObject().first("photos");
String result = photos.toCompactString();

json serialization with a variable field as a string

I have a pojo that I am unmarshalling a REST response to. One of the fields ("variable value") is just a Json variable element (can be any form).
Is there a way to tell it to treat the field as a plain string for all cases instead of trying to deserialize to an object?
Here's a json obiect ("variable value" can be any form):
{"id":1, "variable value": {"name":"one", "age": 22, "data":{"key":"value"}}}
I would like to save this json as a class object using gson
public class SomeCommand {
private Long id;
private String data;
}
It sounds that you would like to parse the given JSON string to transform variable value into String object. You can achieve this by creating 2 classes - SomeCommandOriginal and SomeCommand as follows:
First, convert the JSON string to SomeCommandOriginal to map the value of variable value to JsonNode.
class SomeCommandOriginal {
private Long id;
#JsonProperty("variable value")
private JsonNode variableValue;
//general getters and setters
}
class SomeCommand {
private Long id;
private String data;
public SomeCommand(SomeCommandOriginal someCommandOriginal) {
super();
this.id = someCommandOriginal.id;
this.data = someCommandOriginal.variableValue.toString();
}
//general getters and setters
}
Second, initialize an instance of SomeCommand and pass someCommandOriginal as the argument of customized constructor:
ObjectMapper mapper = new ObjectMapper();
SomeCommandOriginal someCommandOriginal = mapper.readValue(jsonStr, SomeCommandOriginal.class);
SomeCommand someCommand = new SomeCommand(someCommandOriginal);
System.out.println(someCommand.getData());
Console output:
{"name":"one", "age": 22, "data":{"key":"value"}}
UPDATED
If you are using Gson, just modify the datatype of variableValue to be JsonObject and switch to #SerializedName annotation as follows:
class SomeCommandOriginal {
private Long id;
#SerializedName("variable value")
private JsonObject variableValue;
//general getters and setters
}
And then you can get the same result as well:
Gson gson = new Gson();
SomeCommandOriginal someCommandOriginal = gson.fromJson(jsonStr, SomeCommandOriginal.class);
SomeCommand someCommand = new SomeCommand(someCommandOriginal);
System.out.println(someCommand.getData());

GSON parsing multiple keys of the same type

I'm working on a personal project in Android and I want to use GSON to parse a JSON file containing the data I need.
I have a local JSON file with the following structure:
{
"Object1": {
"foo": "value1",
"bar": "value2",
"baz": "value3",
...
},
"Object2": {
"foo": "value4",
"bar": "value5",
"baz": "value6",
...
},
...
}
I have already made an Object class of the following structure:
Class Object {
String data;
...
}
How would I parse this JSON file with this structure?
EDIT: The JSON file I use is very large, it contains about 400+ of these objects of type Object. I would have to iterate over each object to create a new JSONObject, but I do not know how to do this.
In the solution below, we convert the JSON you've provided in your link as a JSONOject. Then we get the list of names contained in the JSON ("Abaddon", "Archeri", ...). Once we have the list we iterate through it. For each name we get the JSON object associated with it.
Then we use GSON to convert each object into a Demon object. The Demon class has been generated using http://www.jsonschema2pojo.org/ as suggested above.
As all the objects in the JSON have the same structure we need only one class to deserialize every single one of them.
Deserializer
public List<Demon> deserialize(String json) {
try {
JSONObject jsonObject = new JSONObject(json);
final JSONArray names = jsonObject.names();
final List<Demon> demons = new ArrayList<>();
final Gson gson = new Gson();
Demon demon;
for (int i = 0; i < names.length(); i++) {
demon = gson.fromJson(jsonObject.get(names.getString(i)).toString(), Demon.class);
demons.add(demon);
}
return demons;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
Demon class
public class Demon {
#SerializedName("ailments")
#Expose
public String ailments;
#SerializedName("align")
#Expose
public String align;
#SerializedName("code")
#Expose
public Integer code;
#SerializedName("inherits")
#Expose
public String inherits;
#SerializedName("lvl")
#Expose
public Integer lvl;
#SerializedName("pcoeff")
#Expose
public Integer pcoeff;
#SerializedName("race")
#Expose
public String race;
#SerializedName("resists")
#Expose
public String resists;
#SerializedName("skills")
#Expose
public List<String> skills = null;
#SerializedName("source")
#Expose
public List<String> source = null;
#SerializedName("stats")
#Expose
public List<Integer> stats = null;
public Demon(){
// Default constructor
}
}

Format of POJO for nested JSON?

So lets say the JSON response is:
[{ "data" : { "item1": value1, "item2:" value2 }}]
How do you get the values 'value1' and 'value2' when you must first access data?
If the fields were at the root then I could just have the method return a POJO with those field names.
I basically want the below to work.
#GET("/path/to/data/")
Pojo getData();
class Pojo
{
public String item1;
public String item2;
}
You can try below code to convert your json string to Pojo object with required fields using Gson library.
Gson gson = new Gson();
JsonArray jsonArray = gson.fromJson (jsonString, JsonElement.class).getAsJsonArray(); // Convert the Json string to JsonArray
JsonObject jsonObj = jsonArray.get(0).getAsJsonObject(); //Get the first element of array and convert it to Json object
Pojo pojo = gson.fromJson(jsonObj.get("data").toString(), Pojo.class); //Get the data property from json object and convert it to Pojo object
or you can define your nested Pojo class to parse it.
class Pojo
{
private String item1;
private String item2;
//Setters and Getters
}
class Data
{
private Pojo data;
//Setters and Getters
}
ArrayList<Data> yourArray = new Gson().fromJson(jsonString, new TypeToken<List<Data>>(){}.getType());
EDIT : Try below code to get value1 and value2 using Retrofit.
class Pojo
{
private String item1;
private String item2;
//Setters and Getters
}
class Data
{
private Pojo data;
//Setters and Getters
}
class MyData
{
private ArrayList<Data> dataList;
//Setters and Getters
}
IService service = restAdapter.create(IService.class);
MyData data = service.getData();
ArrayList<Data> list = data.getDataList(); // Retrive arraylist from MyData
Data obj = list.get(0); // Get first element from arraylist
Pojo pojo = obj.getData(); // Get pojo from Data
Log.e("pojo", pojo.item1 + ", " + pojo.item2);

Categories