I have to refactor some areas of my app to use the streaming API in Gson, but very quickly I'm running into a strange problem I'm not sure how to get around. The following constructor on my class receives a JsonReader and is supposed to loop through the properties of the object. LogCat shows the name of the first property output, then an exception "Expected a name but was BOOLEAN". I only asked for the name using reader.nextName(). What gives?
JSON Object:
{
"IsActive":true,
"LocationName":"Denver",
...
}
Class constructor:
public AppLocation(JsonReader reader){
try {
reader.beginObject();
while(reader.hasNext()){
final String pName = reader.nextName();
final boolean isNull = reader.peek() == JsonToken.NULL;
if(!isNull){
Log.d("MENET", pName);
}else{
reader.skipValue();
}
}
reader.endObject();
} catch (IOException e) {
Log.e("MENET", e.getMessage());
}
}
The streaming method of using this reader works with "elements" i.e. names or values.
So after the first "element", which is a name, you would get a value.
Except your code is calling reader.nextName() which is why it says "Expected a name..."
There is a good example on the Android site under JsonReader:
http://developer.android.com/reference/android/util/JsonReader.html
Related
I am currently working over CSV exports. I am fetching header from properties file with below code -
String[] csvHeader = exportables.get(0).getCSVHeaderMap(currentUser).keySet().stream().
map(s ->messageSource.getMessage("report."+s, null, locale)).toArray(String[]::new);
The above code works well. But i need to find a way to handle exception and also fetch data from another file, if it is not found in above file. I am expecting to use somewhat below code -
try{
exportables.get(0).getCSVHeaderMap(currentUser).keySet().stream().
map(s ->messageSource.getMessage("report."+s, null, locale)).toArray(String[]::new);
}catch(NoSuchMessageException e){
// code to work over lacking properties
}
I want to catch the 's' element in catch block (or in other good way). So that i can fetch it from another file and also add its return to current csvHeader.
One way is to make for each element a try catch block like:
exportables.get(0).getCSVHeaderMap(currentUser).keySet().stream().
map(s -> {
String result;//Put the class to which you map
try{
result = messageSource.getMessage("report."+s, null, locale);
}catch(NoSuchMessageException e){
// code to work over lacking properties here you have access to s
}
return result;
}
).toArray(String[]::new);
Another solution will be to check for specific problems and then there is no need to catch exceptions. For example if s is null and then you want to get the data from another place:
exportables.get(0).getCSVHeaderMap(currentUser).keySet().stream().
map(s -> {
String result;//Put the class to which you map
if(null == s)// Some condition that you want to check.
{
//get info from another place
//result = ....
}
else
{
result = messageSource.getMessage("report."+s, null, locale);
}
return result;
}
).toArray(String[]::new);
I am trying to trying to test a set of result generated by a service class with some defined expected result. The service produce the actual result.
The service is feed with values from a json file which contain some values and expected result. The output of service is compared with expected result using AssertEquals and the test is passing only when they are equal.
Is it possible to continue test even if some AssertEquals fails and generate a report of how many AssertEquals have passed or failed.
I explored maven surefire but I am not able to get expected result.
Note: There is only one #Test method.Inside this method only I am calling the service with multiple times with different parameters and comparing expected & actual result
#Test
public void createTest() throws Exception {
try {
// some other code to read the file
JSONParser parser = new JSONParser();
// ruleValidationResourcePath is location of the file
JSONArray array = (JSONArray) parser.parse(new FileReader(ruleValidationResourcePath));
//looping this json and passing each object values to a service
for(Object o:array){
JSONObject rulesValidation = (JSONObject) o;
String ruleAdExpr = (String) rulesValidation.get("ruleA");
String _result = (String)rulesValidation.get("result");
PatObj patObj= new PatObj ();
patObj.setRule(ruleAdExpr.trim());
//service is an instance of class which hold props method
PatObj pat = service.props(patObj);
if(patObj.getRule() != null){
String _machineRule =pat .getMachine_rule().toLowerCase().trim();
String expResult = _result.toLowerCase().trim();
// here some _machineRule & expResult may be different
// currently test is failing if they are not equal
// will like to continue test even if they are not equal
// and create report of how many failed/passed
Assert.assertEquals(_machineRule,expResult);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
Is it possible to continue test even if some AssertEquals fails.
Yes, it is possible but I wouldn't recommend you doing that because it is misuse of JUnit.
The JUnit methodology follows the rule that a test should check only one particular case per test method.
In your case you JSON loading logic is just a setup, and you check getMachineRule() method with different parameters.
JUnit world has its own mechanisms of handling such cases.
How do you implement it properly:
You need to rework the test by making it parametrised.
First add JUnitParams to your project.
Then you need to introduce a method that will load JSONArray and use its result as parameters for your test.
All together:
#RunWith(JUnitParamsRunner.class)
public class RoleTest {
#Test
#Parameters
public void createTest(JSONObject rulesValidation) throws Exception {
// use the same logic as you have inside your "for" loop
//...
assertEquals(machineRule, expResult);
}
private Object[] parametersForCreateTest() {
// load JSON here and convert it to array
JSONParser parser = new JSONParser();
JSONArray jsonArray = (JSONArray) parser.parse(
new FileReader(ruleValidationResourcePath)
);
return jsonArray.toArray();
}
}
This way the createTest will be performed as many times as you have objects in your JSONArray and you'll see the report for each particular run (even if some of them fail).
Note: the method naming matters. A method that return parameters should be named the same way as the test method but prefixed with parametersFor - in your case parametersForCreateTest. Find more examples in the documentation.
This pretty much goes against what the Assertion is intended. One of the difficulties here is that a failed assertion throws an error and not an exception.
You could use:
catch (AssertionError e) {
...
Once you catch the error, you still need to tally it so the code would be far cleaner if you simply made the comparison using an if statement and recording the result
if(_machineRule.equals(expResult)) {success++;}
and then
Assert.assertEquals(expectedCount,success);
after your loop completes processing of all the elements in your list. Another method might be:
try{
Assert.assertEquals(_machineRule,expResult);
System.out.println(description + " - passed");
}catch(AssertionError e){
System.out.println(description + " - failed");
throw e;
}
I believe you want the org.junit.rules.ErrorCollector rule from the junit 4.7+ API. It should do exactly what you're looking for; allowing a single test to assert multiple times and report the end-state of each check individually.
//This must be public
#Rule
public ErrorCollector collector = new ErrorCollector();
#Test
public void createTest() throws Exception {
try {
// some other code to read the file
JSONParser parser = new JSONParser();
// ruleValidationResourcePath is location of the file
JSONArray array = (JSONArray) parser.parse(new FileReader(ruleValidationResourcePath));
//looping this json and passing each object values to a service
for(Object o:array){
JSONObject rulesValidation = (JSONObject) o;
String ruleAdExpr = (String) rulesValidation.get("ruleA");
String _result = (String)rulesValidation.get("result");
PatObj patObj= new PatObj ();
patObj.setRule(ruleAdExpr.trim());
//service is an instance of class which hold props method
PatObj pat = service.props(patObj);
if(patObj.getRule() != null){
String _machineRule =pat .getMachine_rule().toLowerCase().trim();
String expResult = _result.toLowerCase().trim();
// here some _machineRule & expResult may be different
// currently test is failing if they are not equal
// will like to continue test even if they are not equal
// and create report of how many failed/passed
collector.checkThat(expResult, IsEqual.equalTo(_machineRule));
//Assert.assertEquals(_machineRule,expResult);
}
}
} catch (FileNotFoundException e) {
collector.addError(e);
// e.printStackTrace();
}
}
I have a list of json object coming in from AWS input stream.
Each json objects are specific custom/user objects.
I need help as I'm stuck in point 2.
picks json object-->converts to custom Object.
If the conversion fails with any parse exception of json, then the code should log/print in the console the error'd out a record. continue to next json record.
I have the object-mapper/JsonParser(from Jackson Library) to do the conversion using readValueAs() method.
I'm stuck in the second part to fetch the error'd out the record and log it. then continue with next record.
Examples are below
{
"col1":"col1Value",
"col2":"col2Value",
"col3":"col3Value",
{sub-json-objects}**,**
"col4":"col4Value"
}
{
"col11":"col11Value",
"col12":"col12Value",
"col13":"col13Value",
{sub-json-objects}***(supposingly if the comma is missing here)***
"col14":"col14Value"
}
i.e.
{
"col11":"col11Value",
"col12":"col12Value",
"col13":"col13Value", {sub-json-objects}
"col14":"col14Value"
}
If you guys can suggest me any other approach its fine. I'm looking for error'd out json + log and continue it further.
I tried below
#Override
public T next() {
try {
return (T) jp.readValueAs((Class<T>) type);
} catch (Exception ex) {
logger.info("Failed Record --> " + jp.currentToken());
logger.error(ex.getMessage(), ex);
}
return null;
}
Regards,
Pawan.
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();
}
}