Android: Handling json objects that can be a string or array - java

Ran into a situation where am not sure how to handle it.
I have json data that comes from a server; for example:(am just posting part of the json, so, yes, the json is valid)
"wall_id": 889149,
"poster_image_thumbnail": "http:\/\/www.mface.me\/images\/avatar\/thumb_62441559ddb1dda7513d0f94.jpg",
"post_type": "profile",
"post_content": [{
"text": "",
"images_count": 1,
"images": ["https:\/\/fbcdn-sphotos-a-a.akamaihd.net\/hphotos-ak-ash4\/227408_475848819113499_663318592_n.jpg"]
}]
Created a class to store this json data
public class feedFormat{
Integer wall_id;
String poster_image_thumbnail;
String post_type;
String post_content;
}
There are times when post_content can be empty or an array as the example above. I have declared post_content as String in feedFormat. This is obviously throwing a cast exception (Converting array to string?).
I was expecting JSONObject to read it as a string and later convert it into an array from there, but does'nt seem to go that way.
How can i dynamically handle a string or an array? if it is an array, i need to break it down.
I am porting this app from IOS to android, there is a "id" object in IOS that can be of any class. I check if the class is a NSSTring or NSArray and take it from there. Here in Java, am not sure how to handle it.
Any suggestions are highly appreciated

If your JSON array is empty, it will be like that :
"post_content": []
It will then remain an array, with the particularity of being 0-sized.
Then I suggest you parse directly your JSON array into a appropriate data structure, whatever the size, like an ArrayList> for example. You will then be able to go through all the items of your JSON array, and for each item, add a new HashMap in your arraylist. Every hashmap will contain there pairs of key values.
However, if I understand well your JSON, it seems that it will be always an array of three elements, the third element being itself a array, which size is given bu the attribute images_count. This is not very good, your JSON structure should be :
"post_content": {
"text": "",
"images": [
"https://fbcdn-sphotos-a-a.akamaihd.net/hphotos-ak-ash4/227408_475848819113499_663318592_n.jpg"
]
}
Since images is an array, you can easily get its size.

JSONObject has functions called has(String key) which checks if there is a mapping for a key and isNull(String key) which checks if a particular key is null. Use these to check the key before reading.

public class FeedFormat{
Integer wall_id;
String poster_image_thumbnail;
String post_type;
JSONArray post_content;
}
feedFormat toto = new feedFormat();
toto.post_content = yourJsonObject.getJsonArray("post_content");
This is the easiest way to do what you want. Another way is to create another class.
public class FeedFormat{
Integer wall_id;
String poster_image_thumbnail;
String post_type;
ArrayList<PostContent> post_content = new ArrayList<PostContent>();
}
public class PostContent {
String text;
Integer imageCount;
ArrayList<String> images = new ArrayList<String>();
}
With that you can handle each post content into specific object instead of use JSONObject / JSONArray.

you can check like this jsonobject.has("post_content")
if(jsonobject.has("post_content")) {
/// read array and do remaining stuff
}else {
// if not read another strings and put post_content as null.
}

You can use something like this:
String data= "wall_id": 889149,
"poster_image_thumbnail": "http:\/\/www.mface.me\/images\/avatar\/thumb_62441559ddb1dda7513d0f94.jpg",
"post_type": "profile",
"post_content": [{
"text": "",
"images_count": 1,
"images": ["https:\/\/fbcdn-sphotos-a-a.akamaihd.net\/hphotos-ak-ash4\/227408_475848819113499_663318592_n.jpg"]
}]
JSONArray jArray=data.getJSONArray("post_content");
for(int i=0; i<jArray.length(); i++)
{
JSONObject jObj=jArray.getJSONObject(i);
String text=jObj.getString("text");
int images_count=jObj.getInt("images_count");
String images=jObj.getInt("images");
}

Related

Java Jackson Serialize JSON to HashTable

I am trying to serialize a list of JSON blobs and put certain keys into a HashTable during the serialization. Here is an example of my JSON:
[
{
"name": "sally",
"id": 1,
"eye_color": "green"
},
{
"name": "jack",
"id": 2,
"eye_color": "blue"
},
{
"name": "jane",
"id": 3,
"eye_color": "brown"
}
]
What I am looking for specifically is a POJO (or set of POJOs) which can serialize the above JSON like so with Jackson assuming the above JSON is in a file called above_json.json:
MyPOJO pojo = objectMapper.readValue(new File("above_json.json"), MyPOJO.class);
I want the result of the serialization to give me a HashTable (or an Object which encapsulates the HashTable) where the HashTable key is the value of name and the Hashtable value is the value of the corresponding id above.
Assuming we serialized the above JSON in this fashion, I would want to access the HashTable like so:
myTable.get("jane")
result: 3
myTable.get("jack")
result: 2
myTable.get("Jill")
result: null
I know how to serialize basic JSON with Jackson. I have an example like below:
JSON Input:
"Parameter":{
"Name":"Parameter-Name",
"Value":"Parameter-Value"
}
POJO to serialize above simple JSON:
public class Parameter {
#JsonProperty("Name")
public String name;
#JsonProperty("Value")
public String value;
}
But obviously this type of setup does not put the results into a HashTable. I need a POJO like what I have in this example which will serialize JSON directly into a HashTable
I don't think that is possible.
You serialize this json into a list of pojos, and have a utility function to generate the hashtable in the way you desire from the list of pojos.
Create a POJO for holding the properties you are interested in.
#JsonIgnoreProperties(ignoreUnknown = true)
private static class MyPOJO {
#JsonProperty("name")
private String name;
#JsonProperty("id")
private Integer id;
public Integer getId() {
return id;
}
public String getName() {
return name;
}
}
Deserialize the contents of the file into List<MyPOJO>
List<MyPOJO> myPOJO = mapper.readValue(new File(".."), new TypeReference<List<MyPOJO>>(){});
Stream the contents of the map to construct a map whose key is the name and value is the id.
Map<String, Integer> map = myPOJO.stream()
.collect(Collectors.toMap(MyPOJO::getName, MyPOJO::getId));
First of all, you probably don't want to use a HashTable, as it's considered to be an obsolete type (see here).
Either use a HashMap or if you want thread safety, a ConcurrentHashMap or a thread-unsafe Map backed by Collections.synchronized[...] and referenced to within synchronized statements.
Secondly, you can use a TypeReference to de-serialize as your desired type.
Finally, your JSON's syntax is incorrect: it starts with a square bracket ([) and ends with a curly bracket (}), which is technically unparseable.
Assuming you want an array of Maps here (e.g. HashMap<String, String>[]), here is some suitable code, provided you replace the last curly bracket with a square one:
// the map array
Map<String, String>[] map = null;
map = om.readValue(yourFile, new TypeReference<HashMap<String, String>[]>() {});
// prints the de-serialized contents
System.out.println(Arrays.toString(map));
Edit
Since you have now edited your JSON to remove the first square bracket and replace it with a curly bracket, no you can't parse as a Map as is.
Edit 2
Since you have now re-edited your JSON to feature square brackets once again instead of curly brackets in the wrapping object, you can once again de-serialize as a Map[]. Until the next edit, I guess...

How to remove empty objects from Json Array

So the json is something like it,
"stores": [
{
"amazon": []
},
{
"flipkart": {
"product_store": "Flipkart",
"product_store_logo": "http://images-api.datayuge.in/image/ZmxpcGthcnRfc3RvcmUucG5n.png",
"product_store_url": "https://price-api.datayuge.com/redirect?id=aHR0cHM6Ly9kbC5mbGlwa2FydC5jb20vZGwvbWktYTEtYmxhY2stNjQtZ2IvcC9pdG1leDl3eHh6M2FtamF0P3BpZD1NT0JFWDlXWFVTWlZZSEVUJmFmZmlkPWFydW5iYWJ1bA",
"product_price": "14999",
"product_offer": "",
"product_color": "",
"product_delivery": "3-4",
"product_delivery_cost": "0",
"is_emi": "1",
"is_cod": "1",
"return_time": "10 Days"
}
},
{
"snapdeal": []
}
]
So the non empty object like flipkart is a JsonObject but all other empty objects are array. So I am so confused about how to remove them.
JSONArray store_array = product_details_json.getJSONObject("data").getJSONArray("stores");
for (int i = 0; i<store_array.length(); i++){
JSONObject store = store_array.getJSONObject(i);
if (!store.getJSONObject(store.keys().next()).has("product_store")){
store_array.remove(i);
}else {
Log.i("Size :",store_array.length()+"");
}
}
But that's not working. I know I am doing this all wrong. Because it has both array and objects so i get the following error
Value [] at amazon of type org.json.JSONArray cannot be converted to JSONObject
Need Help!
I see two problems with your code:
Your JSON structure for "stores" is heterogeneous — some elements have a key that maps to an array and some to an object. That's the immediate cause of the error you are seeing. You can either modify your JSON so everything key maps to an object or code defensively.
When you remove an entry, all subsequent entries move up one space, but since you then increment the loop index i, you skip the entry that just moved into the index you just removed. The easiest way to deal with that is to iterate through store_array in reverse order.
Putting this all together (and assuming you aren't going to change your JSON structure), something like the following (untested) should work:
JSONArray store_array = product_details_json.getJSONObject("data").getJSONArray("stores");
for (int i = store_array.length() - 1; i >= 0; i--){
JSONObject store = store_array.getJSONObject(i);
Object storeData = store.get(store.keys().next());
boolean isValidStore = storeData instanceof JSONObject
&& ((JSONObject) storeData).has("product_store");
if (!isValidStore) {
store_array.remove(i);
}
}

How to set Data to multidimensional array in Java?

I try to set data from list to two multidimensional array.
Normally I can set data to two multidimensional array like this:
Object[][] newData = {
{ "test", "test2", 15.98, 0.14, "+0.88%",
32157250 },
{ "AAPL", "Apple Inc.", 126.57, -1.97, "-1.54%", 31367143 }"
However I want to set data dynamically from list .
I have a method wich return a list :
List<User> user = listUser(id);
static User {
private int id;
private String name;
and getter(...),setter(..).
I need to set user from listUser(id) method to Object[][] array.
I try to do it but I couldnt get succesfull result :
for (int i=0;i<user.size();i++){
for(int j=0;j<user.size();j++){
newData[i][j]=user.get(i).getName();
}
}
Could you help me ?
The columns are fixed, i.e., 0,1,2,etc.. and you need to iterate and set the data for each row as shown below:
for (int i=0;i<user.size();i++){
for(int j=0;j<user.size();j++){
newData[i][j]=user.get(i).getId();//get id for each rowand set to 0th column
newData[i][j]=user.get(i).getName();
newData[i][j]=user.get(i).getX();//other fields
newData[i][j]=user.get(i).getY();//other fields
}
}
Also, it is not a good idea to use Object[][] (not sure for what reason you are using this) as it requires explicit casting while retrieving/using the fields.
It looks like the data is well structured. I would create a class and keep a single-dimension array of your private "CompanyStock" class instead of using a dangerous 2d Object[][] array.

Better way to match list of strings using JsonPath and Hamcrest Matchers

I'm using JsonPath to test REST endpoints of my API. My test case looks something like this.
First I create the new object
class Item {
String name;
int id;
List<String> places;
}
String name = "Randomname" + new Random().nextLong();
JSONObject obj = new Item(name, 3, Arrays.asList("Rome3", "London3", "Paris3"));
post("/items").content(obj);
Then I get a list of all items and check that the item I just created is in the list.
mockMvc.perform(get("/api/v1/test"))
.andExpect(jsonPath("$.data[*].name", hasItems("item 1", "item 2"))) // Fine
.andExpect(jsonPath("$.data[?(#.id == 1)].name", contains("item 1")))
.andExpect(jsonPath("$.data[?(#.id == 1)].places", contains(contains("Rome1", "London1", "Paris1"))))
.andReturn();
Which works, but I dont think I'm doing it right because I have a nested contains(contains()). (I've put the full JSON response at the end of this post.)
The problem is that because the JsonPath expressions are returning a list, I need to use a list matcher. For example, instead of writing this
jsonPath("$.data[?(#.id == 1)].name", is("item 1"))
I need to write it like this
jsonPath("$.data[?(#.id == 1)].name", contains("item 1"))
Because the JsonPath expression will return a JSON list of one element
[
"item 1"
]
Which isn't so bad, but it gets worse with lists, e.g. trying to check if the List of Strings in my variable places contains what I want. The JSON returned is a List of Lists, so this JsonPath expression
jsonPath("$.data[?(#.id == 1)].places"
Will return this
[
[
"Rome2",
"London3",
"Paris3"
]
]
So it requires a nested hasItems
jsonPath("$.data[?(#.id == 1)].places", hasItems(hasItems("Rome1", "London1")))
And at that works, but doing this just gives me that feeling that I'm not doing this correctly and I'm missing something.
So my question is, what is the appropriate way to handle checking/matching a list of lists?
Is there a better way to validate the JSON that is being returned by an endpoint?

How can i sort Nested JSON Array?

How can i sort Nested JSON Array? Like for a JSON below...
{
"id":"rtmc05.lax.someabc.net",
"name":"rtmc05.lax.someabc.net",
"tenants":[{
"id":"rtmc",
"name":"rtmc"
},{
"id":"hrs",
"name":"hrs"
},{
"id":"amotelbe1",
"name":"amotelbe"
},{
"id":"cds",
"name":"cds"
},{
"id":"idx-server",
"name":"idx-server",
"tenants":[{
"id":"amotelbe",
"name":"amotelbe",
"tenants":[{
"id":"amotelui",
"name":"amotelui"
}]
}]
}]
}
There's a few parts implicit to your question, and it's not clear where you're having trouble:
How do you take a JSON string and make usable Java objects out of it. (I'm assuming Java, not JavaScript, since you've tagged your question with "java".)
How do you sort those objects after they're made?
How do you handle sorting the nested parts? (In your example, "idx-server" has sub-tenants.)
Not sure exactly which parts of this you're having trouble with, so here's some notes for all three.
Part 1: Getting Java objects
I agree with the other guy that Jackson is a good JSON parser to use. Here's a couple lines of code you could use to parse some JSON:
String jsonString = "..."; // Load this in whatever way makes sense for you
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> parsedJson = mapper.readValue(jsonString, Map.class);
If your JSON string is really huge, then there are other readValue overloads that you can use to avoid reading the whole String into memory.
Part 2: Sorting Java objects
Once you've got the parsed JSON, sorting is just a matter of calling Collections.sort(...), passing in the tenants array. Plus you'll need to write a Comparator that defines the ordering that you want. For example, here's a comparator that sorts by name:
public class NameComparator implements Comparator<Map<String,Object>> {
public int compare(Map<String,Object> o1, Map<String,Object> o2) {
String name1 = (String) o1.get("name");
String name2 = (String) o2.get("name");
return name1.compareTo(name2);
}
}
Then you get the tenants array out (Jackson makes them into ArrayList objects) and call Collections.sort(...). For example,
List<Map<String,Object>> tenants =
(List<Map<String,Object>>) parsedJson.get("tenants");
Collections.sort(tenants, new NameComparator());
Part 3: Handling the nesting
The clearest way to do this is to add some extra code to walk through your JSON looking for any object with a tenants array, and sort it. For example, here's a recursive function that should do it:
public static void recursiveSortTenants(Map<String,Object> jsonObject) {
List<Map<String,Object>> tenants =
(List<Map<String,Object>>) jsonObject.get("tenants");
if (tenants != null) {
Collections.sort(tenants, new NameComparator());
// For each tenant, see if it has sub-tenants. If so,
// call this function again to sort them.
for (Map<String,Object> tenant : tenants) {
if (tenants.containsKey("tenants")) {
recursiveSortTenants(tenant);
}
}
}
}
Hope this helps!
Parse it into (javascript) objects then write a sort function that sorts an array of such javascript objects.
Deserialize it to POJOs(with Gson or Jackson), and write a Comparator for that POJOs.

Categories

Resources