Sorting JSONArray using double as comparison violating contract? - java

I'm trying to sort a JSONArray but I'm getting the following error:
Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:895)
at java.util.TimSort.mergeAt(TimSort.java:512)
at java.util.TimSort.mergeForceCollapse(TimSort.java:453)
at java.util.TimSort.sort(TimSort.java:250)
at java.util.Arrays.sort(Arrays.java:1523)
at java.util.Collections.sort(Collections.java:238)
Here is my code:
private JSONArray SortJSONArray(String json) {
JSONArray sortedJsonArray = new JSONArray();
try {
JSONArray jsonArr = new JSONArray(json);
List<JSONObject> jsonValues = new ArrayList<JSONObject>();
for (int i = 0; i < jsonArr.length(); i++) {
jsonValues.add(jsonArr.getJSONObject(i));
}
Collections.sort(jsonValues, new Comparator<JSONObject>() {
private static final String KEY_NAME = "EUR";
#Override
public int compare(JSONObject a, JSONObject b) {
Double valA = 0.0;
Double valB = 0.0;
try {
valA = a.getDouble(KEY_NAME);
valB = b.getDouble(KEY_NAME);
} catch (JSONException e) {
Log.e("MainActivity", e.getMessage());
}
if(valA < valB) {
return -1;
} else if( valB < valA) {
return 1;
} else {
return 0;
}
}
});
for (int i = 0; i < jsonArr.length(); i++) {
sortedJsonArray.put(jsonValues.get(i));
}
} catch (JSONException e) {
Log.e("MainActivity", e.getMessage());
}
return sortedJsonArray;
}

The issue is that either a.getDouble(KEY_NAME) or b.getDouble(KEY_NAME) can throw an exception.
If a.getDouble(KEY_NAME) throws an exception and b.getDouble(KEY_NAME) does not, b.getDouble(KEY_NAME) is never evaluated and both valA and valB remain 0.0.
On the other hand, if you compare a and b is reversed order (i.e. call compare(b,a) instead of compare(a,b), b.getDouble(KEY_NAME) will be evaluated before a.getDouble(KEY_NAME) throws an exception, so valA will be 0.0 and valB will have some other value.
In that case compare(a,b) will return 0 and compare(b,a) will return a non-zero value (assuming b.getDouble(KEY_NAME) doesn't return 0.0), which violates the contract of Comparator.
Evaluating a.getDouble(KEY_NAME) and b.getDouble(KEY_NAME) in separate try blocks will resolve the issue.
try {
valA = a.getDouble(KEY_NAME);
} catch (JSONException e) {
Log.e("MainActivity", e.getMessage());
}
try {
valB = b.getDouble(KEY_NAME);
} catch (JSONException e) {
Log.e("MainActivity", e.getMessage());
}
return Double.compare(valA,valB);

Workaround is to return a value in the catch statement:
try {
valA = a.getDouble(KEY_NAME);
valB = b.getDouble(KEY_NAME);
} catch (JSONException e) {
Log.e("MainActivity", e.getMessage());
return -10;
}
if(valA < valB) {
return -1;
} else if( valB < valA) {
return 1;
} else {
return 0;
}

Related

How do i parse the deezer api in android

i am trying to change my api from last.fm to deezer and it has been a hurdle for me. please help. below is my code and endpoints.
LAST.fm endpoint : http://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key=c3bbdcbc61af20f159e92612a56c4122&artist=ynw%20melly&track=suicidal&format=json
Deezer endpoint : http://api.deezer.com/search?q=Alan%20Walker%20-%20Darkside
JAVA CODE
static String parsingImageSong(String data) {
if (!TextUtils.isEmpty(data)) {
try {
JSONObject mJsonObject = new JSONObject(data);
if (mJsonObject.opt("track") != null) {
JSONObject mJsTracks = mJsonObject.getJSONObject("track");
if (mJsTracks.opt("album") != null) {
JSONObject mJsAlbum = mJsTracks.getJSONObject("album");
if (mJsAlbum.opt("image") != null) {
JSONArray mJsImgs = mJsAlbum.getJSONArray("image");
if (mJsImgs.length() > 0) {
for (int j = 0; j < mJsImgs.length(); j++) {
JSONObject mJsImg = mJsImgs.getJSONObject(j);
String sizeImg = mJsImg.getString("size");
if (sizeImg.equalsIgnoreCase("extralarge")) {
return mJsImg.getString("#text").replace("300x300","3000x3000");
}
}
}
}
}
}
}
catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
}

How to get the values of a key of a json file

How can i get the values of a json key in Java here is my code
private void getWebApiData() {
String WebDataUrl = "myjsonfileurl";
new AsyncHttpTask.execute(WebDataUrl);
}
#SuppressLint("StaticFieldLeak")
public class AsyncHttpTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String result = "";
URL url;
HttpsURLConnection urlConnection = null;
try {
url = new URL(urls[0]);
urlConnection = (HttpsURLConnection) url.openConnection();
if (result != null) {
String response = streamToString(urlConnection.getInputStream());
parseResult(response);
return result;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
if (result != null) {
newsAdapter = new NewsAdapter(getActivity(), newsClassList);
listView.setAdapter(newsAdapter);
Toast.makeText(getContext(), "Data Loaded Successfully", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getContext(), "Failed to load data!", Toast.LENGTH_SHORT).show();
}
progressBar.setVisibility(View.GONE);
}
}
private String streamToString(InputStream stream) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));
String line;
String result = "";
while ((line = bufferedReader.readLine()) != null) {
result += line;
}
// Close stream
if (null != stream) {
stream.close();
}
return result;
}
private void parseResult_GetWebData(String result) {
try {
JSONObject jsonObject = new JSONObject(result);
JSONArray jsonArray = jsonObject.getJSONArray("books");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject articleObject = jsonArray.getJSONObject(i);
JSONObject sourceObject = articleObject.getJSONObject("A");
String name = sourceObject.optString("name");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
My json file
{
"books": [
{
"A": [
{
"Amazonite": {
"name": "Amazonite",
"image": "www.google.com"
},
"Amethyst": {
"name": "Amethyst",
"image": "www.google.com"
}
}
],
"B": [
{
"Beryl": {
"name": "Beryl",
"image": "www.google.com"
},
"BloodStone": {
"name": "Bloodstone",
"image": "www.google.com"
}
}
]
}
]
}
What i would like is how to get the values of data under the Alphabet A that is Amazonite and Amethyst and the value of data under Alphabet B but the could i have just give me empty text field nothing no data is being populated.
I have tried with this code but the values retures "null"
private void parseResult_GetWebData(String result) {
try {
JSONObject jsonObject = new JSONObject(result);
JSONArray jsonArray = jsonObject.getJSONArray("books");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject articleObject = jsonArray.getJSONObject(i);
String name = String.valueOf(articleObject.optJSONObject("A"));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
I am not sure what you really want, but if you just want to get "Amazonite and Amethyst" as you responded under OP, you can try this:
Code snippet
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject articleObject = jsonArray.getJSONObject(i);
JSONArray jsonArrayA = articleObject.getJSONArray("A");
for (int j = 0; j < jsonArrayA.length(); j++) {
JSONObject obj = jsonArrayA.getJSONObject(j);
System.out.println(obj.names());
obj.names().forEach(e -> {
System.out.println(obj.getJSONObject(e.toString()).get("name"));
});
}
}
Console output
["Amazonite","Amethyst"]
Amazonite
Amethyst
Update
I am not sure which name you want to retrieve because both Amazonite and Amethyst appear two times in JSON array A, so I provide two ways to show them as follows:
List<String> names = new ArrayList<>();
List<String> innerNames = new ArrayList<>();
for (int j = 0; j < jsonArrayA.length(); j++) {
JSONObject obj = jsonArrayA.getJSONObject(j);
JSONArray keys = obj.names();
for (int k = 0; k < keys.length(); k++) {
String name = keys.getString(k);
String innerName = obj.getJSONObject(keys.optString(k)).getString("name");
System.out.printf("name: %s, inner name: %s\n", name, innerName);
names.add(name);
innerNames.add(innerName);
}
}
System.out.println(names.toString());
System.out.println(innerNames.toString());
Console output
name: Amazonite, inner name: Amazonite
name: Amethyst, inner name: Amethyst
[Amazonite, Amethyst]
[Amazonite, Amethyst]

getDeclaredMethod not working in android 9(PIE)

public RefStaticMethod(Class<?> cls, Field field) {
try {
if (field.isAnnotationPresent(MethodParams.class)) {
Class<?>[] types = field.getAnnotation(MethodParams.class).value();
for (int i = 0; i < types.length; i++) {
Class<?> clazz = types[i];
if (clazz.getClassLoader() == getClass().getClassLoader()) {
try {
Class.forName(clazz.getName());
Class<?> realClass = (Class<?>) clazz.getField("TYPE").get(null);
types[i] = realClass;
} catch (Throwable e){
Log.e("hello", "RefStaticMethod: 1" );
throw new RuntimeException(e);
}
}
}
this.method = cls.getDeclaredMethod(field.getName(), types);
this.method.setAccessible(true);
} else if (field.isAnnotationPresent(MethodReflectParams.class)) {
boolean arrayset = false;
String[] typeNames = field.getAnnotation(MethodReflectParams.class).value();
Class<?>[] types = new Class<?>[typeNames.length];
Class<?>[] types2 = new Class<?>[typeNames.length];
for (int i = 0; i < typeNames.length; i++) {
Class<?> type = getProtoType(typeNames[i]);
if (type == null) {
try {
type = Class.forName(typeNames[i]);
} catch (ClassNotFoundException e) {
Log.e("hello", "RefStaticMethod: 2" );
e.printStackTrace();
}
}
types[i] = type;
if ("java.util.HashSet".equals(typeNames[i])) {
arrayset = true;
Class<?> type2 = type;
try {
type2 = Class.forName("android.util.ArraySet");
} catch (ClassNotFoundException e) {
Log.e("hello", "RefStaticMethod: 3" );
e.printStackTrace();
}
if (type2 != null) {
types2[i] = type2;
} else {
types2[i] = type;
}
} else {
types2[i] = type;
}
}
try {
this.method = cls.getDeclaredMethod(field.getName(), types);
} catch (Exception e) {
Log.e("hello", "RefStaticMethod: 4 "+e.toString() );
e.printStackTrace();
if (arrayset) {
this.method = cls.getDeclaredMethod(field.getName(), types2);
}
}
this.method.setAccessible(true);
} else {
for (Method method : cls.getDeclaredMethods()) {
if (method.getName().equals(field.getName())) {
this.method = method;
this.method.setAccessible(true);
break;
}
}
}
if (this.method == null) {
throw new NoSuchMethodException(field.getName());
}
}
catch(Exception e)
{
Log.e("hello", "RefStaticMethod: 5 "+e.toString());
}
}
Logcat error:
2019-07-02 03:01:01.893 29833-29861/io.virtualapp:x E/hello:
RefStaticMethod: 4 java.lang.NoSuchMethodException:
collectCertificates [class android.content.pm.PackageParser$Package,
int] 2019-07-02 03:01:01.896 29833-29861/io.virtualapp:x E/hello:
RefStaticMethod: 5 java.lang.NullPointerException: Attempt to invoke
virtual method 'void java.lang.reflect.Method.setAccessible(boolean)'
on a null object reference
have any solution for android 9(PIE) or any alternative way to resolve this issue of getDeclaredMethod. thanks in advance

Json Reflaction warning with custom List

I am trying to reflect a json to class. But i have problem when i have JsonArray inside of JsonArray with object's. It seems that is trying to find a class like List<Step> but cannot found.
My output is :
W/System.err: Value ... at steps of type org.json.JSONArray cannot be converted to JSONObject
My class is like:
class Step {
private Consecutive consecutive;
private List<List<Steps>> steps = null;
}
a part of my Json :
{"step":{"consecutive":{"enabled":true,"period":"day"},"steps":[[{"points":100},{"points":200},{"points":300},{"points":400}],[{"points":100},{"points":200},{"points":300},{"points":400}],[{"points":100},{"points":200},{"points":300},{"points":400}],[{"points":100},{"points":200},{"points":300},{"points":400}],[{"points":100},{"points":200},{"points":300},{"points":400}],[{"points":100},{"points":200},{"points":300},{"points":400}],[{"points":100},{"points":200},{"points":300},{"points":400}]]}}
My Json Parser :
public static Object populateObjectFromJSON(Class<?> classname, JSONObject js) {
Object obj = null;
System.out.println("Populating " + classname.getSimpleName() + " -with- " + js.toString());
try {
obj = classname.newInstance();
} catch (InstantiationException e1) {
System.err.println(e1.getMessage());
return null;
} catch (IllegalAccessException e1) {
System.err.println(e1.getMessage());
return null;
}
Field[] fields;
if (privacy == 0) {
fields = classname.getFields();
} else {
fields = classname.getDeclaredFields();
}
for (Field f : fields) {
// System.out.println("Declared " + f.getName());
if ((privacy == 2) && (Modifier.isPrivate(f.getModifiers()))) {
f.setAccessible(true);
}
try {
if (js.has(f.getName())) {
String type = f.getType().getSimpleName();
if (type.equalsIgnoreCase("boolean")) {
f.setBoolean(obj, js.getBoolean(f.getName()));
} else if (type.equalsIgnoreCase("int")) {
f.setInt(obj, js.getInt(f.getName()));
} else if (type.equalsIgnoreCase("double")) {
f.setDouble(obj, js.getDouble(f.getName()));
} else if (type.equalsIgnoreCase("float")) {
f.setFloat(obj, (float) js.getDouble(f.getName()));
} else if (type.equalsIgnoreCase("string")) {
f.set(obj, js.getString(f.getName()));
} else if (f.getType().isArray()) {
f.set(obj, Array.newInstance(f.getType().getComponentType(), js.getJSONArray(f.getName()).length()));
insertArrayFromJSON(f.get(obj), js.getJSONArray(f.getName()));
}else{
f.set(obj, populateObjectFromJSON(f.getType(), js.getJSONObject(f.getName())));
}
}
} catch (IllegalArgumentException e) {
System.err.println(e.getMessage());
} catch (IllegalAccessException e) {
System.err.println(e.getMessage());
} catch (JSONException e) {
System.err.println(e.getMessage());
}
if ((privacy == 2) && (Modifier.isPrivate(f.getModifiers()))) {
f.setAccessible(false);
}
}
return obj;
}
thanks

An Error While parsing data using Jsoup with google app engine

I start using google app engine but I'm a beginner.
I created a web application and I added the library Jsoup.
I'm trying to parse a lot of data from a web site but when I deploy the application I get this error:
Error: Server Error
The server encountered an error and could not complete your request.
Please try again in 30 seconds.
here is my code :
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
resp.getWriter().println("{\"Restaurant\":[");
listPages = new ArrayList<>();
listRestaurant = new ArrayList<>();
listUrlRestaurant = new ArrayList<>();
listObj = new ArrayList<>();
try {
doc = Jsoup.connect(url).userAgent("Mozilla").timeout(60000).get();
//System.out.println(doc.select("strong.next.page-numbers").text());
int i=1;
while(doc.select("strong.next.page-numbers").text().contains("SUIV")){
listPages.add(url);
//System.out.println("exist : "+url);
//System.out.println("*******");
//restaurants = doc.select("div.listing_img > a");
url = url.replace("page/"+i+"/", "page/"+(i+1)+"/");
i=i+1;
//System.out.println("*****"+url);
doc = Jsoup.connect(url).userAgent("Mozilla").timeout(60000).get();
//ParsingRestaurant(restaurants,resp,doc);
}
} catch (IOException e) {
e.printStackTrace();
}
//System.out.println(listPages.size());
try{
for (int i = 0; i < listPages.size(); i++) {
doc2 = Jsoup.connect(listPages.get(i)).userAgent("Mozilla").timeout(60000).get();
restaurants = doc2.select("div.listing_img > a");
for (Element element : restaurants) {
listUrlRestaurant.add(element.attr("href"));
//System.out.println(element.attr("href"));
}
}
} catch (IOException e) {
e.printStackTrace();
}
//System.out.println(listUrlRestaurant.size());
for (int i = 0; i < listUrlRestaurant.size(); i++) {
ParsingRestaurant(listUrlRestaurant.get(i), resp, doc3,listObj);
}
for (int i = 0; i < listObj.size(); i++) {
if (i!=listObj.size()) {
resp.getWriter().println(listObj.get(i)+",");
}else{
resp.getWriter().println(listObj.get(i));
}
}
resp.getWriter().println("]}");
}
private void ParsingRestaurant(String url, HttpServletResponse resp, Document doc,List<String> listObj) {
// TODO Auto-generated method stub
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Restaurant obj = new Restaurant();
try {
doc = Jsoup.connect(url).userAgent("Mozilla").timeout(60000).get();
name = doc.select("h1.entry-title").first();
obj.setName(name.text());
adress = doc.select("span#frontend_address").first();
obj.setAdress(adress.text());
facebook = doc.select("a#facebook").first();
if (facebook == null) {
obj.setFacebook("empty");
}else{
obj.setFacebook(facebook.attr("href"));
}
phone = doc.select("span.entry-phone.frontend_phone.listing_custom").first();
if (phone == null) {
obj.setPhone("empty");
}else{
obj.setPhone(phone.text());
}
time = doc.select("span.entry-listing_timing.frontend_listing_timing.listing_custom").first();
if (time == null) {
obj.setPhone("empty");
}else{
obj.setTime(time.text());
}
map = doc.select("div.google-map-directory > a ").first();
//System.out.println(name.text()+adress.text()+facebook.attr("href")+phone.text()+time.text());
String location = map.attr("href");
location = location.replace("http://www.google.com/maps/dir/Current+Location/", "");
String[] output = location.split(",");
obj.setLongitude(output[0]);
obj.setLatitude(output[1]);
images = doc.select("a.listing_img.galerie_listing");
for (Element e : images) {
obj.images.add(e.attr("href"));
}
details = doc.select("div#listing_apercu > div");
for (Element e : details) {
//System.out.println(e.select("label").text());
obj.titles.add(e.select("label").text());
String x = e.select("p > span").text();
for (int j = 1; j < x.length(); j++) {
if (Character.isUpperCase(x.charAt(j))) {
x = changeCharInPosition(j-1, ',', x);
}
}
obj.details.add(x);
}
String json = gson.toJson(obj);
listObj.add(json);
} catch (IOException e) {
e.printStackTrace();
}
}
public String changeCharInPosition(int position, char ch, String str){
char[] charArray = str.toCharArray();
charArray[position] = ch;
return new String(charArray);
}
}
any idea about the problem?!

Categories