My android app connects to Firebase and pulls "Alert Objects" that are sent there by my server.
When I export the data from Firebase, I get a beautifully formated JSON representation of the data.
Problem:
When I pull the data to my android device using a DataSnapshot, the data has '=' (equals signs) instead of ':' (semicolons). Also the quotations are not there.
When I try to do something like JSONObject alert = new JSONObject(data.getValue().toString()); I get errors for obvious reasons. I say obvious because if you look at what my code prints to the console you can see that it is no longer in valid JSON format.
A friend mentioned that I need to do something with encoding but we didn't have time to discuss it.
How can I iterate through these (kinda weird) Alert Objects that I have created and turn them into JSON objects within my Java so that I can access their properties like alert.date and alert.message.
I thought screenshots would help you see what I am doing. The firebase is not secured at all so you can feel free to take a look at it. It won't really do much and when I go to production I will be moving it anyways.
I am sure this is a super easy question to answer, I am just not too well versed with JSON and encoding as a whole.
Thanks!
you can it using gson library
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
/*JSONObject jsonObject = null;
try {
jsonObject=new JSONObject();
} catch (JSONException e) {
e.printStackTrace();
}*/
Gson gson = new Gson();
String s1 = gson.toJson(dataSnapshot.getValue());
JSONArray object = null;
try {
object = new JSONArray(s1);
} catch (JSONException e) {
e.printStackTrace();
}
JSONArray jsonArray = object;
Log.e("string", s1);
}
You cannot access JSON natively in Java.
But the Firebase DataSnapshot class provides everything you need.
If you have a DataSnapshot of the data at the fbAlerts in your screenshot, you can print the date+message and recipients for each:
for (DataSnapshot alert: alerts.getChildren()) {
System.out.println(alert.child("date").getValue();
System.out.println(alert.child("message").getValue();
for (DataSnapshot recipient: alert.child("recipients").getChildren()) {
System.out.println(recipient.child("name").getValue();
}
}
Alternatively, you can build a Java class that represents an alert. See the Firebase guide on reading data in Android for examples of that.
Use this way to convert the jsonObject form the dataSnapshot
Map<String, String> value = (Map<String, String>) dataSnapshot.getValue();
Log.i("dataSnapshot", "dataSnapshot" + new JSONObject(value));
From the above code extract, it looks like you have a JSONArray rather than a JSONObject.
In which case, you need to do something like the following:
// Find the right array object
JSONArray jsonArray = response.getJSONArray("fbAlerts");
// Loop through the array
for (int i=0; i< jsonArray.length(); i++) {
JSONObject myObj = jsonArray.getJSONObject(i);
strMsg = myObj.getString("message");
}
In the example - when you have repeating groups, this would seem to indicate an array and therefore needs an iterator to access the object contents.
Related
I am making an app in android studio using an API that returns the following:
[{"domains": ["upes.ac.in"], "country": "India", "state-province": "Dehradun", "web_pages": ["https://www.upes.ac.in/"], "name": "University of Petroleum and Energy Studies", "alpha_two_code": "IN"}]
I run it as follows:
public void onResponse(String response) {
listaUniversidades = new ArrayList<>();
JSONArray jsonArray = new JSONArray(response);
String nombreUni, pais, url;
for (int i = 0; i < jsonArray.length(); i++) {
nombreUni = jsonArray.getJSONObject(i).getString("name");
pais = jsonArray.getJSONObject(i).getString("country");
url = jsonArray.getJSONObject(i).getString("web_pages"));
texto.setText(url);
listaUniversidades.add(new Universidad(nombreUni, pais, url));
}}
The thing is that the web_pages returns the following: ["http://.www.upes.ac.in/"]
How could I make it return the correct url? Since that way I can not access the university website.
Thank you!
I will assume that you aways want to get the first "web_page" inside the "web_pages" array.
You can try to convert the "web_pages" attribute to an array before trying to get the first element, like this:
url = jsonArray
.getJSONObject(i)
.getJSONArray("web_pages"))
.getJSONObject(0)
.toString();
Have you verified that the API returns the expected value for web_pages? You can set a breakpoint on the line
String nombreUni, pais, url;
And then inspect the variable jsonArray. I think the incorrect value that you got is most likely because the API returns that value.
The problem is that "web_pages": ["https://www.upes.ac.in/"] is a JSON Array, so you need to convert it to the array and then access the appropriate item in it(presumably first one?)
It can be done the way Aleph proposed above.
In my Android app, I used Gson in order to save/load the object's Arraylist in SharedPreferences. Follows are my code using Gson.
public static ArrayList<RequestModal> getModalList(Context ctx) {
Gson gson = new Gson();
String json = getSharedPreferences(ctx).getString("ModalList", new Gson().toJson(new ArrayList<>()));
Type type = new TypeToken<ArrayList<RequestModal>>() {}.getType();
return gson.fromJson(json, type);
}
In here "RequestModal" is the simple object include a bit of strings and integers.
It works well in case "online". But if internet is offline, forever works on below code.
Type type = new TypeToken<ArrayList<RequestModal>>() {}.getType();
How can I solve it? What is the way implement the feature like this with/without using Gson? Please help me anyone having a good idea.
Thank you in advance.
You can implement this without Gson:
public static EpisodeDetails parseEpisodeDetails(String content) {
EpisodeDetails episodeDetails = new EpisodeDetails();
try {
JSONObject jsonObject = new JSONObject(content);
episodeDetails.title = jsonObject.getString("title");
episodeDetails.subTitle = jsonObject.getString("subtitle");
episodeDetails.synopsis = jsonObject.getString("synopsis");
episodeDetails.ends_on = jsonObject.getString("ends_on");
JSONArray images = jsonObject.getJSONArray("image_urls");
if (images.length() > 0) {
episodeDetails.image_url = images.getString(0);
}
} catch (JSONException e) {
e.printStackTrace();
return null;
}
return episodeDetails;
}
What I'm doing is just taking the String, in your case the one saved on the shared prefs called ModalList and inserting the values on my structure, on my code the structure is called EpisodeDetails, on your code the correspondent is RequestModal. If you don't want to do it via code and want to try another library I recommend Jackson.
Another thing, on this line:
String json = getSharedPreferences(ctx).getString("ModalList", new Gson().toJson(new ArrayList<>()));
Your second parameter is not necessary. getString takes the key to load as first parameter and a default value as second paramter (in the case of empty result). You could change this to "" or null.
Well, another solution to your problem could be TinyDB. It makes use of Gson to save ArrayLists of objects in sharedPrefs, its usage is so simple as:
Person person = new Person("john", 24);
tinydb.putObject("user1", person);
ArrayList<Person> usersWhoWon = new ArrayList<Person>();
tinydb.putListObject("allWinners", usersWhoWon);
and that's it, check out my link given above to see the usage details.
This is a basic Java question I think that I can't work out how to get around.
I get data from Google Analytics API and store the rows in my database as a string as a JSONArray
[["New Zealand","Auckland","1640","8.795731707317072","516.4469512195122"],["New Zealand","Wellington","1314","8.428462709284627","580.3302891933029"]]
For Google Maps I need a JSON Array:
function drawMap() {
var data = google.visualization.arrayToDataTable([
['City', 'Popularity'],
['New York', 200],
['Boston', 300],
['Miami', 400],
['Chicago', 500],
['Los Angeles', 600],
['Houston', 700]
]);
From https://developers.google.com/chart/interactive/docs/gallery/geomap
I need to change my data, by parsing it and iterating through it to remove the first (i.e. "New Zealand") and last variable from each object - I also need to add the headers i.e. ['City', 'Popularity']
Using GSonBuilder I can create JSON
[{"city":"Wellington","sessions":"1314","viewsPerSessions":"8.428462709284627","avgDuration":"8.428462709284627"},{"city":"Christchurch","sessions":"432","viewsPerSessions":"10.127314814814815","avgDuration":"10.127314814814815"}]
How do I turn that into a JSON Array?
I use the JSON parse of Android. With this you can get what you want.
Try this:
JSONArray js_data = [["New Zealand","Auckland","1640","8.795731707317072","516.4469512195122"],["New Zealand","Wellington","1314","8.428462709284627","580.3302891933029"]];
int lenght = js_data.length();
JSONArray city;
for(int i=0;i<length;i++) {
//get each city
city = js_data.getJSONArray(i);
String nameCity = city.getString(0);
String pop = city.getString(4);
//Create a object JSON or whatever you want with this data
JSONArray js_array = new JSONArray();
js_array.put(city); js_array.put(pop);
//And put on a list
js_map.put(js_array);
}
This is a basic java coding.
Hope it's helps.
I realize my questions have been asked a lot but I have spent a considerable amount of time scouring both SO and google trying to get a better understanding of this concept with no success. I've seen many different implementations, which is what leads me to get some advice about my specific situation.
MY OBJECTIVE
I need to perform a post request to a php file and the goal is to ultimately populate fields in a list activity with some of the json data.
HTTP POST RESPONSE
Here is the format of the response data I'm getting back from the server, which appears to be a JSON object of arrays(?).
{"expense":[{"cat_id_PK":237,"cat_name":"Name1","cat_amount":"100.00","is_recurring":0},
{"cat_id_PK":238,"cat_name":"Name2","cat_amount":"200.00","is_recurring":0},
{"cat_id_PK":239,"cat_name":"Name3","cat_amount":"300.00","is_recurring":0},
{"cat_id_PK":240,"cat_name":"Name4","cat_amount":"400.00","is_recurring":0}],
"expense_rec": [{"cat_id_PK":207,"cat_name":"Name5","cat_amount":"500.00","is_recurring":1}]}
FIRST QUESTION
The code below is what I'm using to read the response. Is this how I should be handling that? It seems weird to get a json encoded response and then change it to a string, only to try and access elements of a json object again. Am I on the wrong track here?
//This code is in the doInBackground method of my "sendPostRequest" async task.
HttpResponse httpResponse = httpClient.execute(httpPost);
InputStream inputStream = httpResponse.getEntity().getContent();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuilder stringBuilder = new StringBuilder();
String bufferedStrChunk = null;
while ((bufferedStrChunk = bufferedReader.readLine()) != null) {
stringBuilder.append(bufferedStrChunk);
}
//Returns string to onPostExecute()
return stringBuilder.toString();
SECOND QUESTION
I have another file called "PostResponse.java" that holds the following code I modeled after a tutorial online. I'm unsure of how to interact with this class from the onPostExecute method. How can I access say, the first item in the first object (something like in PHP where you could do: expense[0]['cat_name']). I've tried to do this various ways with no success. Here is the PostResponse.java class:
public class PostResponse {
public Integer cat_id_PK;
public String cat_name;
public BigDecimal cat_amount;
public Integer is_recurring;
public int getID() {
return this.cat_id_PK;
}
public void setID(int cat_id_PK){
this.cat_id_PK = cat_id_PK;
}
public String getName() {
return this.cat_name;
}
public void setName(String cat_name) {
this.cat_name = cat_name;
}
public BigDecimal getAmount() {
return this.cat_amount;
}
public void setAmount(BigDecimal cat_amount) {
this.cat_amount = cat_amount;
}
public int getRecurring() {
return this.is_recurring;
}
public void setRecurring(int is_recurring) {
this.is_recurring = is_recurring;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("*** Categories ***");
sb.append("cat_id_PK="+getID()+"\n");
sb.append("cat_name="+getName()+"\n");
sb.append("cat_amount="+getAmount()+"\n");
sb.append("is_recurring="+getRecurring()+"\n");
return sb.toString();
}
}
and here is the content of my onPostExecute method:
protected void onPostExecute(String result) {
super.onPostExecute(result);
Gson gson = new Gson();
PostResponse response = gson.fromJson(result, PostResponse.class);
System.out.println(result);
}
Like I said originally, my ultimate goal is to populate these items to a list activity, but at this point I'd settle for just knowing how to get at specific elements. However, if anyone would like to include how to populate a list activity in their response, it would save me a lot more headaches, as nothing with java is coming easy for me!
FIRST QUESTION
The code below is what I'm using to read the response. Is this how I should be handling that? It seems weird to get a json encoded response and then change it to a string, only to try and access elements of a json object again. Am I on the wrong track here?
It's one way of handling the http response. A "json encoded response" is little more than a text-based response, so converting it into a string on the receiving end would make sense. That is, the json you receive isn't an 'object' as far as Java is concerned: it's just textual representation of an object (or a bunch of objects in your case), received as a stream of bytes.
That being said, you can potentially shorten your code by skipping the string(builder) part. Gson provides an alternative constructor that takes a Reader instance, for which you can suppy the BufferedReader in your code snippet.
As a side note: the conversion of textual json into Java objects is a potentially 'heavy' operation. As such, you'd best avoid doing it on the main/ui thread, so just move it into the doInBackground() method of your AsyncTask (and change types appropriately).
SECOND QUESTION
I have another file called "PostResponse.java" that holds the following code I modeled after a tutorial online. I'm unsure of how to interact with this class from the onPostExecute method. How can I access say, the first item in the first object (something like in PHP where you could do: expense[0]['cat_name']). I've tried to do this various ways with no success.
You're close, but if you look more closely to the json sample, you'll see that your PostResponse class is not a good match for it:
{
"expense": [
{
"cat_id_PK": 237,
"cat_name": "Name1",
"cat_amount": "100.00",
"is_recurring": 0
},
{
"cat_id_PK": 238,
"cat_name": "Name2",
"cat_amount": "200.00",
"is_recurring": 0
},
{
"cat_id_PK": 239,
"cat_name": "Name3",
"cat_amount": "300.00",
"is_recurring": 0
},
{
"cat_id_PK": 240,
"cat_name": "Name4",
"cat_amount": "400.00",
"is_recurring": 0
}
],
"expense_rec": [
{
"cat_id_PK": 207,
"cat_name": "Name5",
"cat_amount": "500.00",
"is_recurring": 1
}
]
}
Consider the more hierarchical formatting above. On the first level there are two (json) objects: expense and expense_rec (both contain 0...* elements, as the square brackets indicate). That means that whatever class you're going to be trying to map the json onto, should define these fields too. If you now look at your PostResponse class, it should become obvious that in its current form it in fact models one of the child objects of the aforementioned fields.
Basically, the classes to map the json onto, should look somewhat like this:
PostResponse:
public class PostResponse {
public ExpenseItem[] expense;
public ExpenseItem[] expense_rec;
// List<ExpenseItem> is also supported
// getters & setters
}
ExpenseItem:
public class ExpenseItem {
public Integer cat_id_PK;
public String cat_name;
public BigDecimal cat_amount;
public Integer is_recurring;
// getters & setters
}
With the model classes defined, try to let Gson work its magic again. If all goes well, you should be able to access the data in a way similar to what you're used to in PHP:
// map json to POJOs
PostResponse response = new Gson().fromJson(bufferedReader, PostResponse.class);
// retrieve the cat_name for the first item (assuming there is one)
String catName = response.getExpense()[0].getName();
... or any of the other fields through the getters defined in ExpenseItem.
Once you have this part working, it's going to be fairly straightforward to supply the array or list of expenses to an adapter (have a look at ArrayAdapter in the Android framenwork) and bind that adapter to a ListView.
The answer is yes, you will get the response in InputStream
For your second question check this out - jsonschema2pojo this can be helpful while creating models for your JSON data.
Then to use GSON
Gson gson = new Gson();
YourObj yourObj = (YourObj) gson.fromJson(result, YourObj.class);
The answer is yes.Response is received as InputSteam
protected void onPostExecute(String result)
{
super.onPostExecute(result);
Gson gson = new Gson();
PostResponse response = gson.fromJson(result, PostResponse.class);
System.out.println(result);
}
This code section mostly means that after an AsyncTask that get web Response and get the String format json response,this onPostExecute will be called with that Stringfied json.
Gson gson = new Gson();
Gson is a library supported by Google for android to deserialization into your class OBject.
gson.fromJson(result, PostResponse.class);
This method is the real process of deserialization. result is Stringfied json and the second is the Target class you want to deserialize into.
This will return a PostResponse Object and you can use it now.
For the json data (
{"expense":[{"cat_id_PK":237,"cat_name":"Name1","cat_amount":"100.00","is_recurring":0},
{"cat_id_PK":238,"cat_name":"Name2","cat_amount":"200.00","is_recurring":0},
{"cat_id_PK":239,"cat_name":"Name3","cat_amount":"300.00","is_recurring":0},
{"cat_id_PK":240,"cat_name":"Name4","cat_amount":"400.00","is_recurring":0}],
"expense_rec": [{"cat_id_PK":207,"cat_name":"Name5","cat_amount":"500.00","is_recurring":1}]}),
it contains two different arrays here, one is "expense" and another is "expense_rec". So if you want to populate these items to a list activity, you can try the follow methods.
protected void onPostExecute(String result) {
super.onPostExecute(result);
JSONObject jsonObject = new JSONObject(builder.toString());
Log.i(TAG, "jsonObject is : " + jsonObject.toString());
//this is the first array data
JSONArray jsonArray = jsonObject.getJSONArray("expense");
Log.i(TAG, "Array length is: " + jsonArray.length());
for(int i = 0; i < jsonArray.length(); i++){
JSONObject jsoObj = jsonArray.getJSONObject(i);
String name = jsoObj.getString("cat_name");
Log.i(TAG, "file name is: " + name);
}
//this is the second array data
jsonArray = jsonObject.getJSONArray("expense_rec");
for(int i = 0; i < jsonArray.length(); i++){
JSONObject jsoObj = jsonArray.getJSONObject(i);
String name = jsoObj.getString("cat_name");
Log.i(TAG, "file name is: " + name);
}
}
So, I've been trying for some time to parse this nested JSON string. If this was regular Java, or even php,I'm sure this would have been done long ago. Unfortunately I'm stuck with J2ME on this one. Through some searching I found that there exits a lone JSON parser. This I found through some digging on a similar question. I've tried some work on my own, with an example on another question. However, I'm still having a few difficulties. I will explain now.
This is the JSON string I'm trying to parse:
{"Result":"Success","Code":"200","CustomerInfo":"{\"clientDisplay\":{\"customerId\":429,\"globalCustNum\":\"0012-000000429\",\"displayName\":\"Hugo Daley\",\"parentCustomerDisplayName\":\"G-KINGSTON\",\"branchId\":12,\"branchName\":\"Bangalore_branch1244724101456\",\"externalId\":\"123000890\",\"customerFormedByDisplayName\":\"New User1244724101456\",\"customerActivationDate\":\"2012-06-17\",\"customerLevelId\":1,\"customerStatusId\":3,\"customerStatusName\":\"Active\",\"trainedDate\":null,\"dateOfBirth\":\"1950-10-10\",\"age\":61,\"governmentId\":\"100000090\",\"clientUnderGroup\":true,\"blackListed\":false,\"loanOfficerId\":17,\"loanOfficerName\":\"New User1244724101456\",\"businessActivities\":null,\"handicapped\":null,\"maritalStatus\":null,\"citizenship\":null,\"ethnicity\":null,\"educationLevel\":null,\"povertyStatus\":null,\"numChildren\":null,\"areFamilyDetailsRequired\":false,\"spouseFatherValue\":null,\"spouseFatherName\":null,\"familyDetails\":null},\"customerAccountSummary\":{\"globalAccountNum\":\"001200000001259\",\"nextDueAmount\":\"2128.0\"},\"clientPerformanceHistory\":{\"loanCycleNumber\":0,\"lastLoanAmount\":\"0.0\",\"noOfActiveLoans\":0,\"delinquentPortfolioAmount\":\"0.0\",\"totalSavingsAmount\":\"1750.0\",\"meetingsAttended\":0,\"meetingsMissed\":0,\"loanCycleCounters\":[],\"delinquentPortfolioAmountInvalid\":false},\"address\":{\"displayAddress\":null,\"city\":\"\",\"state\":\"\",\"zip\":\"\",\"country\":\"\",\"phoneNumber\":\"\"},\"recentCustomerNotes\":[{\"commentDate\":\"2012-06-17\",\"comment\":\"appr\",\"personnelName\":\"New User1244724101456\"}],\"customerFlags\":[],\"loanAccountsInUse\":[{\"globalAccountNum\":\"001200000001262\",\"prdOfferingName\":\"Hawker Loan\",\"accountStateId\":3,\"accountStateName\":\"Application Approved\",\"outstandingBalance\":\"15643.0\",\"totalAmountDue\":\"8977.0\"},{\"globalAccountNum\":\"001200000001279\",\"prdOfferingName\":\"Hazina Micro Loan\",\"accountStateId\":2,\"accountStateName\":\"Application Pending Approval\",\"outstandingBalance\":\"6439.0\",\"totalAmountDue\":\"1716.0\"},{\"globalAccountNum\":\"001200000001280\",\"prdOfferingName\":\"Car Finance\",\"accountStateId\":3,\"accountStateName\":\"Application Approved\",\"outstandingBalance\":\"381.5\",\"totalAmountDue\":\"120.0\"}],\"savingsAccountsInUse\":[{\"globalAccountNum\":\"001200000001260\",\"prdOfferingName\":\"Current Account\",\"accountStateId\":16,\"accountStateName\":\"Active\",\"savingsBalance\":\"1750.0\",\"prdOfferingId\":null}],\"customerMeeting\":{\"meetingSchedule\":\"Recur every 1 Week(s) on Monday\",\"meetingPlace\":\"KINGSTON\"},\"activeSurveys\":false,\"customerSurveys\":[],\"closedLoanAccounts\":[{\"globalAccountNum\":\"001200000001261\",\"prdOfferingName\":\"AUTO LOAN-2\",\"accountStateId\":10,\"accountStateName\":\"Cancel\",\"outstandingBalance\":\"2576.0\",\"totalAmountDue\":\"206.0\"}],\"closedSavingsAccounts\":[]}"}
Don't worry this is just sample data, nothing real here.
Now I require the Customers No, Name, Address, and Savings Account balance. This is the code I've used to parse it:
public CustomerInfo(String jsonTxt) {
try {
JSONObject json = new JSONObject(jsonTxt);
JSONObject customer = json.getJSONObject("CustomerInfo");
custNo = json.getString("globalCustNum");
custName = json.getString("displayName");
address = json.getString("DisplayAddress");
savAcctBal = json.getDouble("totalSavingsAmount");
} catch (final JSONException je) {
je.printStackTrace();
}
}
This of course throws an JSONException. I've learned that the JSON Library may have a few bugs. I've done some tricks, with print statements. It turns out that it likes to consume the 1st element of the JSON string. This heavily screws up going through nested elements like we have here in the example.
Is there an alternative I can use?
Boy, do I want to shoot myself. I figured out my issue before I went to bed. My approach was correct; it was just a matter of me reading the output of Print statements wrong as well as underestimated just how nested the JSON was.
Internally, the JSONOBject class stores the JSON elements, pairs, etc. in a Hashtable. The Hashtable has a side-effect where it will sort the data that's given to it. This of course through off how the JSON was ordered. I figured it was consuming some parts of the JSON, while it really was just putting them to the back...the waaay back if not the end of the JSON. This greatly through me off. I did not realise this until I just ran toString on the Hashtable itself. I then also realise that the JSON was actually more nested than I thought. The four parts I wanted to get, where in 3 different nested JSON objects.
Thus, my solution was to save myself even more grief and just put the JSON through a pretty printer and looked and the structure properly.
Here is my Solution code:
public CustomerInfo(String jsonTxt) {
try {
JSONObject json = new JSONObject(jsonTxt);
JSONObject customer = new JSONObject(json.getString("CustomerInfo"));
JSONObject client = new JSONObject(customer.getString("clientDisplay"));
custNo = client.getString("globalCustNum");
custName = client.getString("displayName");
JSONObject cph = new JSONObject(customer.getString("clientPerformanceHistory"));
JSONObject caddress = new JSONObject(customer.getString("address"));
address = caddress.getString("displayAddress");
savAcctBal = cph.getDouble("totalSavingsAmount");
} catch (final JSONException je) {
je.printStackTrace();
}
}
protip: Always use a Pretty Printer on your JSON, and appreciate it's structure before you do anything. I swear this wont happen to me again.
You can parse the JSON string by the following example
public CustomerInfo(String jsonTxt) {
try {
JSONObject json= (JSONObject) new JSONTokener(jsonTxt).nextValue();
test = (String) json2.get("displayName");
}
catch (JSONException e) {
e.printStackTrace();
}
}