Does the StringBuffer change the order of JSON? - java

I'm using StringBuffer to get JSON from a URL.
This is the original JSON
[{"name":"Italy","topLevelDomain":[".it"],"alpha2Code":"IT","alpha3Code":"ITA","callingCodes":["39"],"capital":"Rome","altSpellings":["IT","Italian Republic","Repubblica italiana"],"region":"Europe","subregion":"Southern Europe","population":60665551,"latlng":[42.83333333,12.83333333],"demonym":"Italian","area":301336.0,"gini":36.0,"timezones":["UTC+01:00"],"borders":["AUT","FRA","SMR","SVN","CHE","VAT"],"nativeName":"Italia","numericCode":"380","currencies":[{"code":"EUR","name":"Euro","symbol":"€"}],"languages":[{"iso639_1":"it","iso639_2":"ita","name":"Italian","nativeName":"Italiano"}],"translations":{"de":"Italien","es":"Italia","fr":"Italie","ja":"イタリア","it":"Italia","br":"Itália","pt":"Itália","nl":"Italië","hr":"Italija","fa":"ایتالیا"},"flag":"https://restcountries.eu/data/ita.svg","regionalBlocs":[{"acronym":"EU","name":"European Union","otherAcronyms":[],"otherNames":[]}],"cioc":"ITA"}]
This is the JSON That I end up with once I convert it to a string from the response
[{"area":301336,"nativeName":"Italia","capital":"Rome","demonym":"Italian","flag":"https://restcountries.eu/data/ita.svg","alpha2Code":"IT","languages":[{"nativeName":"Italiano","iso639_2":"ita","name":"Italian","iso639_1":"it"}],"borders":["AUT","FRA","SMR","SVN","CHE","VAT"],"subregion":"Southern Europe","callingCodes":["39"],"regionalBlocs":[{"otherNames":[],"acronym":"EU","name":"European Union","otherAcronyms":[]}],"gini":36,"population":60665551,"numericCode":"380","alpha3Code":"ITA","topLevelDomain":[".it"],"timezones":["UTC+01:00"],"cioc":"ITA","translations":{"br":"Itália","de":"Italien","pt":"Itália","ja":"イタリア","hr":"Italija","it":"Italia","fa":"ایتالیا","fr":"Italie","es":"Italia","nl":"Italië"},"name":"Italy","altSpellings":["IT","Italian Republic","Repubblica italiana"],"region":"Europe","latlng":[42.83333333,12.83333333],"currencies":[{"symbol":"\u20ac","code":"EUR","name":"Euro"}]}]
This is my code for getting the JSON + Converting it.
JSONArray JSON = null;
//Reading Variables
BufferedReader r = new BufferedReader(new InputStreamReader(con.getInputStream()));
String input;
StringBuffer response = new StringBuffer();
//Adding response to StringBuffer
while((input = r.readLine()) != null) {
response.append(input);
}
//Stopping the reader
r.close();
System.out.println(response);
//Convert StringBuffer to JSON
JSON = new JSONArray(response.toString());
System.out.println(JSON);
return JSON;
Is there a way of preventing it from doing this?

It's not the StringBuffer but the JSONArray.
The order of elements in an array [] is maintained like the list ["AUT","FRA","SMR","SVN","CHE","VAT"] in both examples.
Anything as a name value pair surrounded by {} can be reordered like {"code":"EUR","name":"Euro","symbol":"€"} and {"symbol":"\u20ac","code":"EUR","name":"Euro"}.
To prevent this, you can keep it as a String or create your own object and define the toString method.

Your question is similar to Keep the order of the JSON keys during JSON conversion to CSV.
It is not StringBuffer doing this. It is the JSON implementation itself.
For a start, according to all of the JSON specifications that I have seen, the order of the attributes of a JSON object are not significant. A JSON parser is not expected to preserve the attribute order, and neither is the in memory representation of a JSON object. So, for example, a typical in-memory representation of a JSON object uses a HashMap to hold the attribute names and values.
So my first piece of advice to you would be to change your application so that the order of the JSON attributes doesn't matter. If you design a JSON API where attribute order matters, then your API will be problematic.
(If this is in a testcase, it is not difficult to compare JSON properly. For example, parse the JSON and compare objects attribute by attribute.)
If you are lumbered with a (so-called) JSON API where the order of attributes has some meaning, my advice is:
Complain. Submit a bug report. This is not a proper JSON API.
Look for a JSON library that provides a way to work around the bad design. For example, some libraries allow you to provide a Map class to be used when constructing a JSONObject. The default is usually HashMap, but you could use LinkedHashMap instead.

Related

Processing a string formatted as a JSONArray

We have some code where we read a JSON file into a string and then use Json-lib to process it as follows:
// ...
JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(jsonStr);
// ...
We now have a situation where the file is actually a JSONArray (i.e. starts with [ and ends with ]). The file passes all JSON validation tests but our code raises the following exception:
java.lang.ClassCastException: net.sf.json.JSONArray cannot be cast to net.sf.json.JSONObject
We are able to get past the problem by resorting to the following hack:
// ...
JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON("{" + jsonStr + "}");
// ...
Question: Is there a way to process the file, without resorting to the hack?
Question: Is there a way to process the file, without resorting to the hack?
I am assuming that you are using JSON-lib as implied by the [json-lib] tag.
I am also assuming that you have encountered this problem in writing the unit tests for your code. (If not ... why not?)
In the JSON-lib APIs, JSONObject and JSONArray have a common supertype JSON, so you should be able to assign a JSONObject or JSONArray to a variable of type JSON. (The JSON interface has methods isObject and isArray that allow you to test if a JSON is an object or an array ... but no asObject or asArray methods.)
However, if your tests actually require a JSONObject ... you have a problem. In JSON, the "object" and "array" data structures are fundamentally different. Neither is a conceptual subtype of the other. What your "hack" is doing is wrapping the JSON array inside a JSON object. This may or may not be the correct thing to do. (I suspect it isn't. But if it is the correct thing to do, then the "hack" is a reasonable way to do it. You could also construct a JSONObject and add the parsed JSONArray to it programatically.)
If the code under test is designed / specified to work with a JSON object and not with a JSON array, then the CORRECT solution is to reject the input file as bad input, at some point.
If your code under test is designed to do the parsing, then it should throw an exception (or whatever) to reject the bad input file. Your unit test should check that it does that.
If your code under test is designed to take a (parsed) JSONObject, then the testcase (the input file containing a JSON array) is a bad testcase. Remove it ... for the purposes of this unit test.
In short, the correct solution to your problem is going to depend on what the code you are testing is supposed to do.
You can read jsonStr as JSON Object, then convert it to Java Object:
net.sf.json.JSON json = JSONSerializer.toJSON(jsonStr);
YourJavaObject jObj = null;
List<YourJavaObject> list = null;
if(json instanceof JSONObject){
jObj = (YourJavaObject)JSONObject.toBean(JSONObject.fromObject(json), YourJavaObject.class);
}else if(json instanceof JSONArray){
list = JSONArray.toList(JSONArray.fromObject(json), new YourJavaObject(), new JsonConfig());
}

List of HashMap into JSONs string with new line in Java

I have to convert a List into jsons string with new line.
Right now the code which i am using converts the List of HashMap into single jsons string. like below:
List<HashMap> mapList= new ArrayList<>();
HashMap hashmap = new HashMap();
hashmap.add("name","SO");
hashmap.add("rollNo","1");
mapList.put(hashmap);
HashMap hashmap1 = new HashMap();
hashmap1.add("name","SO1");
hashmap1.add("rollNo","2");
mapList.put(hashmap1 );
Now I am converting it into jsons string using ObjectMapper and the output would be
ObjectMapper mapper = new ObjectMapper();
String output = mapper.writeValueAsString(mapList);
Output:
[{"name":"SO","rollNo":1},{"name":"SO1","rollNo":2}]
Its working fine but I need the output inthe format shown below, i.e for every HashMap there should be new line in the JSON string.
[{"name":"SO","rollNo":1},
{"name":"SO1","rollNo":2}]
If i clearly understand the question, you can use:
output.replaceAll(",",",\n");
or you can go through each HashMap.Entry and call
mapper.writeValueAsString(entry);
or use configuration
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
I suggest a slightly different path, and that is use a custom serializer, as outlined here for example.
It boils down to have your own
public static class MgetSerializer extends JsonSerializer<Mget> {
Which works for List for example.
The point is: I would avoid to "mix" things, as: having a solution where your code writes part of the output, and jackson creates other parts of the output. Rather enable jackson to do exactly what you want it to do.
Beyond that, I find the whole approach a bit dubious in the first place. JSON strings do not care about newlines. So, if you care how things are formatted, rather look into the tools you are using to look at your JSON.
Meaning: why waste your time formatting a string that isn't meant for direct human consumption in the first place? Browser consoles will show you JSON strings in a "folded" way, and any decent editor has similar capabilities these days.
In other words: I think you are investing your energy in the wrong place. JSON is a transport format, and you should only worry about the content you want to transmit, not in (essentially meaningless formatting effects).
You can use String methods to change/replace the output's String. However, this is not correct for json Strings as they may contain commas or other characters that you should escape in the String replace methods.
Alternatively, you should parse the Json String and use JsonNode on the Json as below:
ObjectMapper mapper = new ObjectMapper();
String output = mapper.writeValueAsString(mapList);
JsonNode jsonNode = mapper.readTree(output);
Iterator<JsonNode> iter=jsonNode.iterator();
String result = "[";
while(iter.hasNext()){
result+=iter.next().toString() + ",\n";
}
result =result.substring(0,result.length()-2) + "]";
System.out.println(result);
Result:
[{"rollNo":"1","name":"SO"},
{"rollNo":"2","name":"SO1"}]
This approach will work for String containing characters like comma, for example consider the input hashmap.put("n,,,ame","SO");
The result is:
[{"n,,,ame":"SO","rollNo":"1"},
{"rollNo":"2","name":"SO1"}]
Update: Output updated to include [ and ] and commas between rows.
Update: Fixed the output accordingly

How to Pre Process Json String in Java :: Convert Capitalised Field names to lowerCase Camel case names

My current Android project consumes many Json web services.
I have no control over the Json content.
I wish to persist this Json directly into my applications local Realm database.
The issue is the Json Field Names Are All Capitalised.
I do not wish my Realm DTO objects to have capitalised field names as thats just WRONG.
How can I transform the Capitalised field names to acceptable Java field name format?
Is there any Json pre processing libraries that will perform the required transformation of Capitalised field names?
I realise I can use Jackson/GSON type libraries to solve this issue, however that means transforming Json to Java Pojo before I can persist the data.
The json Field names are "ThisIsAFieldName".
What I want is to transform them to "thisIsAFieldName".
I think you should really consider letting your JSON deserializer handle this, but if this really isn't a possibility you can always use good old string manipulation :
String input; // your JSON input
Pattern p = Pattern.compile("\"([A-Z])([^\"]*\"\\s*:)"); // matches '"Xxxx" :'
Matcher m = p.matcher(input);
StringBuffer output = new StringBuffer();
while (m.find()) {
m.appendReplacement(output, String.format("\"%s$2", m.group(1).toLowerCase());
}
m.appendTail(output);
Ideone test.

Android - Accessing JSON children from a URL

I'm in the process of converting my website to an Android app and one of the pages' data currently is populated via JSON in my website. The way it works is that the URL generates a different JSON data with the same structure based on the passed ID. I already have the logic for passing the ID to the URL. Now I want to read the data through Java code and parse the JSON children and its values in it.
I have a URL that leads to the JSON file in textual form, but I'm not sure how to go about reading the data from it and accessing the child nodes based on the JSON key.
So I guess what I'm asking is what is the usual approach for this procedure? I see a lot of different examples, but none of which are applicable to my problem.
Anyone have any suggestions as to how I should approach this?
JSONObject = new JSONObject(yourjsonstring);
Now you have your Json Object...
If your Json start with array use this:
JSONArray = new JSONArray(yourjsonarray);
You can use existing libraries to parse JSON, gson or Moshi are two solutions.
The way you go about parsing the JSON is as followed
First you need to make pojo's with the same structure as the JSON file.
then you can parse it to java code via the fromJSON() method, this will make new objects and fill it with the data from the JSON.
gson example for clarification:
Gson gson = new Gson();
Response response = gson.fromJson(jsonLine, Response.class);
where jsonLine = your json file and the Response.Class the pojo in which you want to json to load.
Now you have the JSON values as Java classes in response.
If you're using Retrofit and OkHTTP to perform the network calls i suggest you use Moshi as it's also from Square and claimed to work faster and better than gson. (if you want to know why you can leave a comment).
I think what you're trying to do is this
on post execute method do the following
#Override
protected void onPostExecute(String result) {
String status = "";
String message = "";
String tag = "";
String mail = "";
try {
JSONObject jsonResult = new JSONObject(result);
status = jsonResult.optString("status");
message = jsonResult.optString("message");
tag = jsonResult.optString("tag");
mail = jsonResult.optString("mail");
} catch (JSONException e) {
e.printStackTrace();
}
of course your json array contains different keys
Just reolace them with yours

Java object from JSON input file

Hi I have a json input file as follows,
{'Latitude':'20',
'coolness':2.0,
'altitude':39000,
'pilot':{'firstName':'Buzz',
'lastName':'Aldrin'},
'mission':'apollo 11'}
How to create a java object from the json input file.
Thanks
You can use the very simple GSON library, with the Gson#fromJson() method.
Here's an example: Converting JSON to Java
There are more than one APIs that can be used. The simplest one is JSONObject
Just do the following:
JSONObject o = new JSONObject(jsonString);
int alt = o.getInt("altitude");
....
there are getXXX methods for each type. It basically stores the object as a map. This is a slow API.
You may use Google's Gson, which is an elegant and better library -- slightly more work required than JSONObject. If you are really concerned about speed, use Jackson.

Categories

Resources