I was just wondering if anyone could recommend a better alternative method than org.json for decoding a complex JSON string. For reference, this will be coming from a web server down to Android (& iOS, but that's the other dev's problem!) devices, it doesn't have to go back up.
The string is of the following nature...
{"header":"value","count":value, ..., "messages":[
{"messagetype":1,"name":"value"},
{"messagetype":2,"name":"value","name":value},
{"messagetype":1,"name":"value"},
{"messagetype":3,"name":"value","subvalues":["value",value,value]},
...
{"messagetype":4,"name":value,"name":"value","name":value}
]}
Basically, there are some header fields which I can always rely on but then there will be an "array" of messages, variable in count, content and order.
I've been researching this for a few days now and have dismissed GSON and a few others because that either need to know the exact structure in advance and/or don't deal well with the embedded types (the contained messages).
Answer three in this question pointed me to using the org.json library and I know I can use that to parse through the string but I guess one of that answer's replies ("That's super old school and nobody uses that library anymore in the real world") has made me question my approach.
Can anyone suggest a library/approach which would handle this problem better? If anyone else has used an alternative approach to dealing with this type of complex and variable structure, I'd really appreciate your input.
Thanks in advance.
I really do not agree with the opinion about org.json libray: "That's super old school and nobody uses that library anymore in the real world", since parsing json by using this library is pretty straightforward. Besides, how complex can json get?, I mean, is all about key/value pairs, nothing that can't be solved with a few lines of code, for instance I will illustrate you a few cases, so that you'll get convinced that is pretty simple to do:
Suppose you have a response from the server containing all info you need formatted in a json array, then you can do something like this to parse the String:
JsonArray arrayJson = new JsonArray(response);
But now you want to access arrayJson childs:
for (int i = 0; i < arrayJson.length() - 1; i++)
{
JsonObject json = arrayJson.getJSONObject(i);
}
And now assume you have another array of json's inside those you retrieved in the for loop:
Then you'll get them this way:
for (int i = 0; i < arrayJson.length() - 1; i++)
{
JsonObject json = arrayJson.getJSONObject(i);
JSONArray anotherArray = json.getJSONArray("key");
}
....., more nestings you can handle them the same way, so I think I established my point. Remember that sometimes, struggling on finding easier ways to do things, can get them even harder to do.
Related
Edit: Figured it out, check my posted answer if you're having similar issues.
I know there are several questions about this issue, but none of their solutions are working for me.
In my model class I have made sure to use List instead of Arraylist to avoid Firebase issues, but am still getting this error. It's a lot of code but most questions ask for all the code so I'll post it all.
TemplateModelClass.java
//
I've used this basic model successfully many times. For the
HashMaps<String, List<String>>,
the String is an incremented Integer converted to String. The List's are just Strings in a List. Here's some sample JSON from Firebase:
//
Formatted that as best as I could. If you need a picture of it let me know and I'll get a screenshot
And am getting this error, as stated in the title:
com.google.firebase.database.DatabaseException: Expected a Map while deserializing, but got a class java.util.ArrayList
The most upvoted question about this seems to have something to do with a problem using an integer as a key, but I think I've avoided that by always using an integer converted to a string. It may be interpreting it strangely, so I'll try some more stuff in the meantime. Thanks for reading!
Alright, figured it out. If anyone reading this has this problem and are using incremented ints/longs/whatever that get converted to strings, you must add some characters to the converted int. Firebase apparently converts these keys back into non-Strings if it can be converted.
For example, if you do something like this:
int inc = 0;
inc++; // 1
map.put(String.valueOf(inc), someList);
Firebase interprets that key as 1 instead of "1".
So, to force Fb to intepret as a string, do something like this:
int inc = 0;
inc++; // 1
map.put(String.valueOf(inc) + "_key", someList);
And everything works out perfectly. Obviously if you also need to read those Strings back to ints, just split the string with "[_]" and you're good to go.
The main issue is that you are using a List instead of a Map. As your error said, while deserializing it is expectig a Map but is found an ArrayList.
So in order to solve this problem youd need to change all the lists in your model with maps like this:
private Map<String, Object> mMapOne;
After changing all those fileds like this, you need also to change your public setters and getters.
Hope it helps.
I am porting an app from Android Java to iPhone.
In Android I used Lists/ArrayLists alot.
On iPhone I plan to use NSMutableArray.
Is there any way to define or even indicate the type of objects in an NSMutableArray.
I know one can put any type of object there, but I would like to make it more visible and transparent.
Many thanks
It's not clear exactly what you're asking.
If you just want to make it clear to the reader what sorts of object of are in the array, just name it appropriately (you can't enforce it at the language level):
NSMutableArray *arrayOfMyClasses;
If, on the other hand, you want to find out the type of an object that you're reading back from the array then you can get the underlying class using:
[obj class]
Or easily compare to other class types:
if ([obj isKindOfClass:[MyClass class]) { ... }
Tim
I assume you are looking for template pattern in Objective C. Unfortunately, it is not available in Objective C (at least directly).
You might find this question of StackOverflow.com interesting
You can only indicate a type.
for(id obj in _assets) {
NSString *className = NSStringFromClass([obj class]);
NSLog(#"%#", className);
}
Arrays are ordered collections of any sort of object. For example, the
objects contained by the array in Figure 1 can be any combination of
cat and dog objects, and if the array is mutable you can add more dog
objects. The collection does not have to be homogeneous.
Collections Programming Topics - Arrays: Ordered Collections
I'm developping an app for Android that needs to get an important amount of data from a JSON feed. This feed is a one line JSON file, weighting approx 400 ko, containing approximately 10 arrays that I need to get.
I'm using the JSON library for Android to do so, and the output works well, but it takes ages (well, 30 secs approx) to compute. The download step is done quickly, that's the creation of the JSON objects that seems to be very long. Here are my steps (removing try/catch blocks and so on).
JSONObject feed = new JSONObject(big_string_from_feed);
JSONArray firstArray = feed.getJSONArray("key1");
JSONArray secondArray = feed.getJSONArray("key2");
[...]
And after i go through all my arrays to get every element the following way :
for (int currentIndex =0;currentIndex<firstArray.length();currentIndex++){
JSONObject myObject = firstArray.getJSONObject(currentIndex);
[....]
}
Is there something wrong in the way I do this ? Is there a better way to do it ?
Thank you very much in advance.
If performance is a concern, use Jackson. See https://github.com/eishay/jvm-serializers/wiki for performance results. (These results should be updated soon to include Jackson manual/tree-strings processing, which will have performance somewhere between Jackson manual and Jackson databind-strings processing. Manual/tree-strings processing is the approach demonstrated in the original question.)
Look at json-simple (see http://code.google.com/p/json-simple). It provides SAX style parsing of JSON streams, and is faster.
Is there any easy way to sort a JSONArray of objects by an attribute in Android?
Perhaps using the Google GSON library you can deserialise the array to a typed collection of objects, and then using Collections perform a sort.
Look at 6th line in on the following link.. Looks a bit messy but might be quickest way..
http://sites.google.com/site/gson/gson-user-guide#TOC-Collections-Examples
So I have this JSON, which then my activity retrieves to a string:
{"popular":
{"authors_last_month": [
{
"url":"http://activeden.net/user/OXYLUS",
"item":"OXYLUS",
"sales":"1148",
"image":"http://s3.envato.com/files/15599.jpg"
},
{
"url":"http://activeden.net/user/digitalscience",
"item":"digitalscience",
"sales":"681",
"image":"http://s3.envato.com/files/232005.jpg"
}
{
...
}
],
"items_last_week": [
{
"cost":"4.00",
"thumbnail":"http://s3.envato.com/files/227943.jpg",
"url":"http://activeden.net/item/christmas-decoration-balls/75682",
"sales":"43",
"item":"Christmas Decoration Balls",
"rating":"3",
"id":"75682"
},
{
"cost":"30.00",
"thumbnail":"http://s3.envato.com/files/226221.jpg",
"url":"http://activeden.net/item/xml-flip-book-as3/63869",
"sales":"27",
"item":"XML Flip Book / AS3",
"rating":"5",
"id":"63869"
},
{
...
}],
"items_last_three_months": [
{
"cost":"5.00",
"thumbnail":"http://s3.envato.com/files/195638.jpg",
"url":"http://activeden.net/item/image-logo-shiner-effect/55085",
"sales":"641",
"item":"image logo shiner effect",
"rating":"5",
"id":"55085"
},
{
"cost":"15.00",
"thumbnail":"http://s3.envato.com/files/180749.png",
"url":"http://activeden.net/item/banner-rotator-with-auto-delay-time/22243",
"sales":"533",
"item":"BANNER ROTATOR with Auto Delay Time",
"rating":"5",
"id":"22243"},
{
...
}]
}
}
It can be accessed here as well, although it because it's quite a long string, I've trimmed the above down to display what is needed.
Basically, I want to be able to access the items from "items_last_week" and create a list of them - originally my plan was to have the 'thumbnail' on the left with the 'item' next to it, but from playing around with the SDK today it appears too difficult or impossible to achieve this, so I would be more than happy with just having the 'item' data from 'items_last_week' in the list.
Coming from php I'm struggling to use any of the JSON libraries which are available to Java, as it appears to be much more than a line of code which I will need to deserialize (I think that's the right word) the JSON, and they all appear to require some form of additional class, apart from the JSONArray/JSONObject script I have which doesn't like the fact that items_last_week is nested (again, I think that's the JSON terminology) and takes an awful long time to run on the Android emulator.
So, in effect, I need a (preferably simple) way to pass the items_last_week data to a ListView. I understand I will need a custom adapter which I can probably get my head around but I cannot understand, no matter how much of the day I've just spent trying to figure it out, how to access certain parts of a JSON string..
originally my plan was to have the
'thumbnail' on the left with the
'item' next to it, but from playing
around with the SDK today it appears
too difficult or impossible to achieve
this
It is far from impossible, but it will be tedious to get right, unless you use something that already wraps up that pattern for you (and that hopefully is reasonably "right"). On the Web, performance/bandwidth issues were the user's problem -- in mobile, they're your problem.
as it appears to be much more than a
line of code which I will need to
deserialize (I think that's the right
word) the JSON
new JSONObject(data) is one line of code. Now, fetching the JSON, which I presume you are doing from the aforementioned URL, will be several lines of code. Neither the parsing of the JSON nor the fetching of it off the Internet is unique to Android -- all of that would look the same on a desktop Java app, or a Java servlet, or whatever.
apart from the JSONArray/JSONObject
script I have which doesn't like the
fact that items_last_week is nested
I have not had a problem parsing JSON with structures like your file exhibits. Moreover, this is hardly unique to Android -- the JSON parser is used in many other Java-based projects.
and takes an awful long time to run on
the Android emulator
The speed of the emulator is tied to the speed of your development machine. For me, the emulator is usually slower than actual phone hardware...and my desktop is a quad-core. Bear in mind that the emulator is pretending to be an ARM chipset running on your PC, converting ARM opcodes into x86 opcodes on the fly, so it's not going to be fast and won't leverage multiple cores very well.
So, in effect, I need a (preferably
simple) way to pass the
items_last_week data to a ListView.
There is nothing really built into Android to take an arbitrary JSON structure, with arbitrary data, and directly pour it into a ListView. This is not unique to JSON -- XML would exhibit similar phenomenon.
Your choices are:
Create a custom ListAdapter that wraps the parsed JSON.
Convert the parsed JSON into a MatrixCursor (think 2D array of data) and use a SimpleCursorAdapter.
Convert the parsed JSON into an ArrayList<String> and use an ArrayAdapter.
For the short term, option #3 is probably the simplest.
I understand I will need a custom
adapter which I can probably get my
head around but I cannot understand,
no matter how much of the day I've
just spent trying to figure it out,
how to access certain parts of a JSON
string..
And that question is too vague for much in the way of assistance. You might consider opening up a separate question, tagged for Java and JSON, where you get into the details of where you are having problems with the json.org parser.