java.lang.StringIndexOutOfBoundsException: length=10684; index=10684 - java

In my Android Project, I'm trying to use PolyUtil.decode to draw a polyline on google map using a response from google maps API.
Here is the code I've used for this :
public void gettingDerictions(double sourceLat, double sourceLong, double destLat, double destLong) {
RequestQueue queue = Volley.newRequestQueue(this);
String url = "https://maps.googleapis.com/maps/api/directions/json?origin=" + sourceLat + "," + sourceLong + "&destination=" + destLat + "," + destLong + "&key=****************************";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
Log.e("The response", response);
List<LatLng> route = PolyUtil.decode(response);
System.out.println(route);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("The response", "it didn't work");
}
});
queue.add(stringRequest);
}
I'm getting this error:
07-31 22:04:13.486 21530-21530/com.innoventiq.arkbeh E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.innoventiq.arkbeh, PID: 21530
java.lang.StringIndexOutOfBoundsException: length=10684; index=10684
at java.lang.String.charAt(Native Method)
at com.google.maps.android.PolyUtil.decode(PolyUtil.java:464)
at com.innoventiq.arkbeh.MapsActivity$6.onResponse(MapsActivity.java:260)
at com.innoventiq.arkbeh.MapsActivity$6.onResponse(MapsActivity.java:255)
at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:82)
at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:29)
at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:102)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7406)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
UPDATE
Here is the value of response.
{
"geocoded_waypoints" : [
{
"geocoder_status" : "OK",
"place_id" : "Ek82IFJpY2ggSG9tZSwgQWwgQWdhbXkgQWwgQmFocmksIFFlc20gQWQgRGVraGlsYWgsIEFsZXhhbmRyaWEgR292ZXJub3JhdGUsIEVneXB0IhoSGAoUChIJv3T_1uiU9RQR7X1tYzsaZ8QQBg",
"types" : [ "street_address" ]
},
{
"geocoder_status" : "OK",
"place_id" : "ChIJ83j9iddBWBQR3SDSTdvOCbk",
"types" : [ "airport", "establishment", "point_of_interest" ]
}
],
"routes" : [
{
"bounds" : {
"northeast" : {
"lat" : 31.1095921,
"lng" : 31.2352784
},
"southwest" : {
"lat" : 30.0439783,
"lng" : 29.7347456
}
},
"copyrights" : "Map data ©2019 ORION-ME",
"legs" : [
{
"distance" : {
"text" : "206 km",
"value" : 206160
},
"duration" : {
"text" : "2 hours 29 mins",
"value" : 8967
},
"end_address" : "Nasser, Madinaty, محافظة القاهرة‬ 11566, Egypt",
"end_location" : {
"lat" : 30.0445393,
"lng" : 31.2352658
},
"start_address" : "6 Rich Home, Al Agamy Al Bahri, Qesm Ad Dekhilah, Alexandria Governorate, Egypt",
"start_location" : {
"lat" : 31.1092252,
"lng" : 29.7598111
},
"steps" : [
{
"distance" : {
"text" : "57 m",
"value" : 57
},
"duration" : {
"text" : "1 min",
"value" : 15
},
"end_location" : {
"lat" : 31.1089022,
"lng" : 29.7602755
},
"html_instructions" : "Head \u003cb\u003esoutheast\u003c/b\u003e toward \u003cb\u003eRich Home\u003c/b\u003e",
"polyline" : {
"points" : "u_{|DymstDLU`#q#PU"
},
"start_location" : {
"lat" : 31.1092252,
"lng" : 29.7598111
},
"travel_mode" : "DRIVING"
},
{
"distance" : {
"text" : "0.1 km",
"value" : 106
},
"duration" : {
"text" : "1 min",
"value" : 41
},
"end_location" : {
"lat" : 31.1095921,
"lng" : 29.7610398
},
"html_instructions" : "Turn \u003cb\u003eleft\u003c/b\u003e onto \u003cb\u003eRich Home\u003c/b\u003e",
"maneuver" : "turn-left",
"polyline" : {
"points" : "s}z|DwpstDIKu#cAiAgA"
},
"start_location" : {
"lat" : 31.1089022,
"lng" : 29.7602755
},
"travel_mode" : "DRIVING"
},
{
"distance" : {
"text" : "1.6 km",
"value" : 1553
},
"duration" : {
"text" : "8 mins",
"value" : 485
},
"end_location" : {
"lat" : 31.0988067,
"lng" : 29.7712707
},

Your response object is not well formatted before decoding. Try below implementation
public void gettingDerictions(double sourceLat, double sourceLong, double destLat, double destLong) {
RequestQueue queue = Volley.newRequestQueue(this);
String url = "https://maps.googleapis.com/maps/api/directions/json?origin=" + sourceLat + "," + sourceLong + "&destination=" + destLat + "," + destLong + "&key=****************************";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
// Log.e("The response", response);
// List<LatLng> route = PolyUtil.decode(response);
// System.out.println(route);
List<LatLng> movements = new ArrayList<LatLng>();
try{
JSONObject json = new JSONObject(response);
//Retrieve routes from response
JSONObject jsonRoute = json.getJSONArray("routes").getJSONObject(0);
//Retrieve legs from routes
JSONObject legs = jsonRoute.getJSONArray("legs").getJSONObject(0);
//Retrieve steps from legs
JSONArray steps = legs.getJSONArray("steps");
final int numSteps = steps.length();
JSONObject step;
//Retrieve points from steps
for (int i = 0; i < numSteps; i++) {
step = steps.getJSONObject(i);
String pontos = step.getJSONObject("polyline").getString("points");
movements.addAll(PolyUtil.decode(pontos));
}
}catch(Exception ex){
Log.d("DirectionErr",ex.getMessage());
}
//make use of movements object here
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("The response", "it didn't work");
}
});
queue.add(stringRequest);
}

EDIT:
I just realized there is an easier way to fix this. If you are getting your response in json then you should use JsonObjectRequest instead of String request, it will give you properly encoded Json that you can parse to String.
OLD ANSWER:.
This must have been caused by Escape Characters during encoding/decoding since you are using string.
Just remove unescape characters and it should work:
response = StringEscapeUtils.unescapeJava(polyLine);
There is an implementation of StringEscapeUtils in Apache commons-text, you can use it from here:
https://github.com/apache/commons-text/blob/master/src/main/java/org/apache/commons/text/StringEscapeUtils.java

Related

Docx4j functionality to turn a document into JSON representation?

Is there a good way to convert a document into JSON representation to then display on a web page? (It is a requirement that the document is converted to JSON)
My Idea if there isn't a built in way to do this is to represent the Run/Paragraph structure as JSON Objects, but I feel like this wouldn't work as well once I start working with more complex Word Documents.
If you add:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.11.3</version>
</dependency>
you can try something like:
import org.docx4j.Docx4J;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class ConvertOutJSON {
static String inputfilepath = System.getProperty("user.dir") + "/sample-docs/sample-docxv2.docx";
public static void main(String[] args)
throws Exception {
WordprocessingMLPackage wordMLPackage
= Docx4J.load(new java.io.File(inputfilepath));
String xml = wordMLPackage.getMainDocumentPart().getXML();
//System.out.println(xml);
XmlMapper xmlMapper = new XmlMapper();
JsonNode node = xmlMapper.readTree(xml);
ObjectMapper jsonMapper = new ObjectMapper();
//String json = jsonMapper.writeValueAsString(node);
String json = jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
System.out.println(json);
}
}
However in a quick test, I noticed some w:p nodes were not being emitted as JSON. I haven't looked to see whether they get dropped by Jackson at the readTree step or when ObjectMapper writes its output; you'll need to dig into Jackson to fix that.
It is currently producing output like:
{
"Ignorable" : "w14 wp14",
"body" : {
"p" : {
"rsidR" : "00D15781",
"rsidRDefault" : "00D15781",
"pPr" : {
"ind" : {
"left" : "0"
}
}
},
"tbl" : {
"tblPr" : {
"tblStyle" : {
"val" : "TableGrid"
},
"tblW" : {
"w" : "0",
"type" : "auto"
},
"tblLook" : {
"firstRow" : "1",
"lastRow" : "0",
"firstColumn" : "1",
"lastColumn" : "0",
"noHBand" : "0",
"noVBand" : "1",
"val" : "04A0"
}
},
"tblGrid" : {
"gridCol" : {
"w" : "3561"
}
},
"tr" : {
"rsidR" : "00D15781",
"tc" : {
"tcPr" : {
"tcW" : {
"w" : "7122",
"type" : "dxa"
},
"gridSpan" : {
"val" : "2"
}
},
"p" : {
"rsidR" : "00D15781",
"rsidRDefault" : "00945132",
"pPr" : {
"ind" : {
"left" : "0"
}
},
"r" : {
"t" : "Horizontal merge"
}
}
}
}
},
"sectPr" : {
"rsidR" : "00D15781",
"headerReference" : {
"type" : "default",
"id" : "rId12"
},
"pgSz" : {
"w" : "11907",
"h" : "16839",
"code" : "9"
},
"pgMar" : {
"top" : "720",
"right" : "720",
"bottom" : "720",
"left" : "720",
"header" : "720",
"footer" : "720",
"gutter" : "0"
},
"cols" : {
"space" : "720"
},
"docGrid" : {
"linePitch" : "360"
}
}
}
}

Android Firebase db datasnapshot pulling information from wrong db directory

In my Android app I am using Google Firebase to store information in the database.
I need to iterate through the information, and below for-loop is being used
public void showDataLobReq(DataSnapshot dataSnapshot){
for(DataSnapshot ds : dataSnapshot.child("Lobby_Requests").getChildren()){
System.out.println("asdfasdfasdfasdfasdf"+ds.getValue());
game = ds.child(userID).child("game").getValue(String.class);
console = ds.child(userID).child("console").getValue(String.class);
mic = ds.child(userID).child("mic").getValue(String.class);
players = ds.child(userID).child("players").getValue(String.class);
}
}
You may notice that I put '.child("Lobby_Requests")' after dataSnapshot. this is because the dataSnapshot takes a snapshot of the whole database, so I must go into the subdirectory "Lobby_Requests" because that is where the information I need to iterate through is.
Putting this '.child()' in is being problematic.
I print to the console what the dataSnapshot contains in the first line of the for loop and with .child("Lobby_Requests") it is pulling information from the directory "Lobbies" in the actual database, which is a completely different directory.
Yet, when I remove the '.child()' completely it gives me a view of the whole database like it should. Why is it doing this?
Code for listener:
nRef = mFirebaseDatabase.getReference();
nRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
showDataLobReq(dataSnapshot);
} else {
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Here is JSON:
{
"Games" : {
"Forza 6" : {
"Consoles" : {
"PC" : true,
"Xbox 1" : true,
"Xbox 360" : true
},
"FilePathName" : "forza6",
"Genres" : {
"Racing" : true
},
"Live Lobbies" : 0,
"Name" : "Forza 6"
},
"Minecraft" : {
"Consoles" : {
"PC" : true,
"Xbox 1" : true,
"Xbox 360" : true
},
"FilePathName" : "minecraft",
"Genres" : {
"Adventure" : true,
"Creation" : true,
"Open World" : true
},
"Live Lobbies" : 0,
"Name" : "Minecraft"
}
},
"Lobbies" : {
"Cd6lVd2XMUYoLH6b0xoHsrfXMud2" : {
"Messages" : {
"-Kq6-1HsMvElEXZZyCIk" : {
"messageText" : "hey",
"messageTime" : 1501208519771,
"messageUser" : ""
}
},
"console" : "Origin",
"game" : "Minecraft",
"leader" : "Cd6lVd2XMUYoLH6b0xoHsrfXMud2",
"mic" : "Mic",
"note" : "2345",
"players" : "4"
},
"KUWH5f1TmYfO1O1wgCJLli3XZFi2" : {
"console" : "Steam",
"game" : "Forza 6",
"mic" : "No Mic",
"note" : "Hey Join Here!",
"players" : "2"
},
"hpWkq0D8clPReUetOq9Xtmc4V582" : {
"Messages" : {
"-Kq5a0kX305lFCRTSM_G" : {
"messageText" : "hello",
"messageTime" : 1501201701014,
"messageUser" : ""
},
"-Kq5asufOWQwtmyNJrQ7" : {
"messageText" : "hey",
"messageTime" : 1501201926941,
"messageUser" : ""
}
},
"console" : "Xbox One",
"game" : "Minecraft",
"leader" : "hpWkq0D8clPReUetOq9Xtmc4V582",
"mic" : "Mic",
"note" : "kjhg",
"players" : "4"
}
},
"Lobby_Requests" : {
"Cd6lVd2XMUYoLH6b0xoHsrfXMud2" : {
"Cd6lVd2XMUYoLH6b0xoHsrfXMud2" : {
"console" : "Xbox One",
"game" : "Forza 6",
"mic" : "Mic",
"players" : "5"
}
},
"KUWH5f1TmYfO1O1wgCJLli3XZFi2" : {
"KUWH5f1TmYfO1O1wgCJLli3XZFi2" : {
"console" : "Steam",
"game" : "Forza 6",
"mic" : "No Mic",
"players" : "2"
}
},
"hpWkq0D8clPReUetOq9Xtmc4V582" : {
"hpWkq0D8clPReUetOq9Xtmc4V582" : {
"console" : "Xbox One",
"game" : "Minecraft",
"mic" : "Mic",
"players" : "4"
},
"players" : "4"
}
},
"users" : {
"8cHrNCybwjO3PIUKxyOLiAqxJBv1" : {
"gamertag" : "thedylan",
"uname" : "thedood"
},
"Cd6lVd2XMUYoLH6b0xoHsrfXMud2" : {
"gamertag" : "dmdylan",
"uname" : "ninja goat"
},
"KUWH5f1TmYfO1O1wgCJLli3XZFi2" : {
"gamertag" : "skaner",
"uname" : "asdf"
},
"YvYEIiCBUSYKTviVyWpLHdyDIFw1" : {
"gamertag" : "joejoe",
"uname" : "Jifflingly"
},
"ZmX9yIZ6MNguQa1S3MaYNcxfK2b2" : {
"gamertag" : "dmkaner",
"uname" : "dmkaner"
},
"hpWkq0D8clPReUetOq9Xtmc4V582" : {
"gamertag" : "dmkaner",
"uname" : "dmkaner"
},
"t21ncnuRmeV4F7RknETBisMrxS42" : {
"gamertag" : "asdf",
"uname" : "asdf"
}
}
}
The problem in your code is that you are pushing your data twice and there is no need for this.
"Lobby_Requests" : {
"Cd6lVd2XMUYoLH6b0xoHsrfXMud2" : {
"Cd6lVd2XMUYoLH6b0xoHsrfXMud2" : { //This is wrong
If you'll change the way in which you add data to the Firebase database by pushing that data only once, your code will work for fine. Your database should look like this:
"Lobby_Requests" : {
"Cd6lVd2XMUYoLH6b0xoHsrfXMud2" : {
"console" : "Xbox One",
"game" : "Forza 6",
"mic" : "Mic",
"players" : "5"
},
As you probably see, there is only one pushed key.

How to parse nested JSON from Map<String, Object>

I am using the below to map a json response to a Map
Map<String, Object> apiResponse = restTemplate.postForObject("https://maps.googleapis.com/maps/api/geocode/json?address="+defaultLocation+"&key="+API_KEY, httpEntity, Map.class, Collections.EMPTY_MAP);
I can use the below to output the entire JSON to a string
String jsonResponse = apiResponse.get("results").toString();
However, what I want to get is a nested value which is results->geometry->location
I have tried a number of solution with JSONArrays, JSONObjects, Substring but can't get them to work.
Response JSON:
{
"results" : [
{
"address_components" : [
{
"long_name" : "Auckland",
"short_name" : "Auckland",
"types" : [ "locality", "political" ]
},
{
"long_name" : "Auckland",
"short_name" : "Auckland",
"types" : [ "administrative_area_level_2", "political" ]
},
{
"long_name" : "Auckland",
"short_name" : "Auckland",
"types" : [ "administrative_area_level_1", "political" ]
},
{
"long_name" : "New Zealand",
"short_name" : "NZ",
"types" : [ "country", "political" ]
}
],
"formatted_address" : "Auckland, New Zealand",
"geometry" : {
"bounds" : {
"northeast" : {
"lat" : -36.660571,
"lng" : 175.287137
},
"southwest" : {
"lat" : -37.065475,
"lng" : 174.4438016
}
},
"location" : {
"lat" : -36.8484597,
"lng" : 174.7633315
},
"location_type" : "APPROXIMATE",
"viewport" : {
"northeast" : {
"lat" : -36.660571,
"lng" : 175.287137
},
"southwest" : {
"lat" : -37.065475,
"lng" : 174.4438016
}
}
},
"place_id" : "ChIJ--acWvtHDW0RF5miQ2HvAAU",
"types" : [ "locality", "political" ]
},
{
"address_components" : [
{
"long_name" : "Auckland",
"short_name" : "Auckland",
"types" : [ "political", "sublocality", "sublocality_level_1" ]
},
{
"long_name" : "Auckland",
"short_name" : "Auckland",
"types" : [ "locality", "political" ]
},
{
"long_name" : "Auckland",
"short_name" : "Auckland",
"types" : [ "administrative_area_level_2", "political" ]
},
{
"long_name" : "Auckland",
"short_name" : "Auckland",
"types" : [ "administrative_area_level_1", "political" ]
},
{
"long_name" : "New Zealand",
"short_name" : "NZ",
"types" : [ "country", "political" ]
},
{
"long_name" : "1010",
"short_name" : "1010",
"types" : [ "postal_code" ]
}
],
"formatted_address" : "Auckland, 1010, New Zealand",
"geometry" : {
"bounds" : {
"northeast" : {
"lat" : -36.8364659,
"lng" : 174.7838398
},
"southwest" : {
"lat" : -36.8621041,
"lng" : 174.7503805
}
},
"location" : {
"lat" : -36.8484597,
"lng" : 174.7633315
},
"location_type" : "APPROXIMATE",
"viewport" : {
"northeast" : {
"lat" : -36.8364659,
"lng" : 174.7838398
},
"southwest" : {
"lat" : -36.8621041,
"lng" : 174.7503805
}
}
},
"place_id" : "ChIJuZqpSPtHDW0R4LOiQ2HvAAU",
"types" : [ "political", "sublocality", "sublocality_level_1" ]
}
],
"status" : "OK"
}
Any help would be greatly appreciated.
JSONObject obj=new JSONObject(jsonresult);
// get result array
JSONArray resultsarray= obj.getJSONArray("results");
for (int i=0;i<resultsarray.length(),i++){
// get Objects using index
JSONObject jsonobject= results.getJSONObject(i);
// get geometry object
JSONObject geometry= jsonobject.getJSONObject("geometry");
// get location object from geometry
JSONObject location= geometry.getJSONObject("location");
// get location values from location object
double lat = location.optDouble("lat",0.0);
double long = location.optDouble("lng",0.0);
}
About optDouble
public double optDouble(String key, double defaultValue) {
Get an optional double associated with a key, or the defaultValue if
there is no such key or if its value is not a number. If the value is
a string, an attempt will be made to evaluate it as a number.
Ideally, you would like to access the properties with the same native notation like you would do in JS. Something like this:
String url = "https://maps.googleapis.com/maps/api/geocode/json?address=" + address;
String responseStr = fetch(url);
JsonHelper response = JsonHelper.forString(responseStr);
String status = (String) response.getValue("status");
if(status != null && status.equals("OK")) {
lat = (Double) response.getValue("results[0].geometry.location.lat");
lng = (Double) response.getValue("results[0].geometry.location.lng");
}
The following JsonHelper class code (taken from jello-framework) lets you do exactly that.
package jello.common;
import java.util.List;
import com.google.gson.Gson;
import java.util.AbstractMap;
public class JsonHelper {
private Object json;
public JsonHelper(String jsonString) {
Gson g = new Gson();
json = g.fromJson(jsonString, Object.class);
}
public static JsonHelper forString(String jsonString) {
return new JsonHelper(jsonString);
}
#SuppressWarnings("unchecked")
public Object getValue(String path) {
Object value = json;
String [] elements = path.split("\\.");
for(String element : elements) {
String ename = element.split("\\[")[0];
if(AbstractMap.class.isAssignableFrom(value.getClass())) {
value = ( (AbstractMap<String, Object>) value).get(ename);
if(element.contains("[")) {
if(List.class.isAssignableFrom(value.getClass())) {
Integer index = Integer.valueOf(element.substring(element.indexOf("[")+1, element.indexOf("]")) );
value = ((List<Object>) value).get(index);
}
else {
return null;
}
}
}
else {
return null;
}
}
return value;
}
}
Use jackson api for parsing,it will be easy
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(json);
if(node.get("results").isArray()){
for(int i=0; i <= node.get("results").size()-1; i++){
System.out.println(node.get("results").get(i));
}
I used Gson api and was able to get the location. Try this :
Code::
Gson gson = new Gson();
String json = "your json";
JsonObject map = gson.fromJson(json, JsonObject.class); // to be replaced with your restTemplate call
JsonArray arr = map.getAsJsonArray("results");
for (Object j : arr) {
System.out.println(((JsonObject) j).get("geometry").getAsJsonObject().get("location"));
}
Console Output::
{"lat":-36.8484597,"lng":174.7633315}
{"lat":-36.8484597,"lng":174.7633315}
So ideally just get the response as a JsonObject instead of a Map and you will be able to read the location.

google-maps-services java library result differs from browser call result

I am using this java libraray
<dependency>
<groupId>com.google.maps</groupId>
<artifactId>google-maps-services</artifactId>
<version>0.1.15</version>
</dependency>
And when I execute the code below
public static GeocodingResult getGeocode(String address) {
GeocodingResult[] results;
try {
GeoApiContext context = new GeoApiContext().setApiKey(GOOGLE_KEY);
results = GeocodingApi.geocode(context, address).await();
if (results.length > 0) {
return results[0];
} else {
return null;
}
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
public static void main(String[] args) {
GeocodingResult geocode = getGeocode("Imanova 19, Astana");
System.out.println(geocode.geometry.location.lat);
}
Result gives
INFO: Request: https://maps.googleapis.com/maps/api/geocode/json?key=MY_GOOGLE_KEY&address=Imanova+19%2C+Astana
51.16052269999999
But, when I try to call the same given request from browser, it gives another result.
The question is, why so and how to fix?
Edit from the comments:
Result of https://maps.googleapis.com/maps/api/geocode/json?address=Imanova+19%2C+Astana
{
"results" : [
{
"address_components" : [
{
"long_name" : "Astaná",
"short_name" : "Astaná",
"types" : [ "locality", "political" ]
},
{
"long_name" : "Astana",
"short_name" : "Astana",
"types" : [ "administrative_area_level_1", "political" ]
},
{
"long_name" : "Kazajistán",
"short_name" : "KZ",
"types" : [ "country", "political" ]
},
{
"long_name" : "020000",
"short_name" : "020000",
"types" : [ "postal_code" ]
}
],
"formatted_address" : "Astaná 020000, Kazajistán",
"geometry" : {
"bounds" : {
"northeast" : {
"lat" : 51.2903453,
"lng" : 71.7427397
},
"southwest" : {
"lat" : 51.0055461,
"lng" : 70.9179879
}
},
"location" : {
"lat" : 51.16052269999999,
"lng" : 71.47035579999999
},
"location_type" : "APPROXIMATE",
"viewport" : {
"northeast" : {
"lat" : 51.2903453,
"lng" : 71.7427397
},
"southwest" : {
"lat" : 51.0055461,
"lng" : 70.9179879
}
}
},
"partial_match" : true,
"place_id" : "ChIJCUa1fcSARUIRKJKx3Y0U-Zc",
"types" : [ "locality", "political" ]
}
],
"status" : "OK"
}
This answer https://stackoverflow.com/a/30749036/1862262 fully describes the solution for my problem.
In the same way I set region
GeocodingResult[] results = GeocodingApi.geocode(context, address).region("KZ").await();
And got the same result as the result in browser.
But I don't know what region it takes if it's not set.
Here is documentation about this option and problem https://developers.google.com/maps/documentation/geocoding/#RegionCodes

Retrieving values from nested JSON Object

I've got JSON file, which I want to parse.
The JSON file ("myfile") has format as follows:
{
"LanguageLevels": {
"1": "Początkujący",
"2": "ŚrednioZaawansowany",
"3": "Zaawansowany",
"4": "Ekspert"
}
}
I want to retrieve value (ŚrednioZaawansowany) of Key 2 from Language Levels.
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
public class JsonSimpleExample {
public static void main(String[] args) {
JSONParser parser = new JSONParser();
try {
Object obj = parser.parse(new FileReader("myfile");
JSONObject jsonObject = (JSONObject) obj;
JSONObject jsonChildObject = (JSONObject)jsonObject.get("LanguageLevels");
What to do next? How I can iterate over it?
Maybe you're not using the latest version of a JSON for Java Library.
json-simple has not been updated for a long time, while JSON-Java was updated 2 month ago.
JSON-Java can be found on GitHub, here is the link to its repo: https://github.com/douglascrockford/JSON-java
After switching the library, you can refer to my sample code down below:
public static void main(String[] args) {
String JSON = "{\"LanguageLevels\":{\"1\":\"Pocz\\u0105tkuj\\u0105cy\",\"2\":\"\\u015arednioZaawansowany\",\"3\":\"Zaawansowany\",\"4\":\"Ekspert\"}}\n";
JSONObject jsonObject = new JSONObject(JSON);
JSONObject getSth = jsonObject.getJSONObject("LanguageLevels");
Object level = getSth.get("2");
System.out.println(level);
}
And as JSON-Java open-sourced, you can read the code and its document, they will guide you through.
Hope that it helps.
You will have to iterate step by step into nested JSON.
for e.g a JSON received from Google geocoding api
{
"results" : [
{
"address_components" : [
{
"long_name" : "Bhopal",
"short_name" : "Bhopal",
"types" : [ "locality", "political" ]
},
{
"long_name" : "Bhopal",
"short_name" : "Bhopal",
"types" : [ "administrative_area_level_2", "political" ]
},
{
"long_name" : "Madhya Pradesh",
"short_name" : "MP",
"types" : [ "administrative_area_level_1", "political" ]
},
{
"long_name" : "India",
"short_name" : "IN",
"types" : [ "country", "political" ]
}
],
"formatted_address" : "Bhopal, Madhya Pradesh, India",
"geometry" : {
"bounds" : {
"northeast" : {
"lat" : 23.3326697,
"lng" : 77.5748062
},
"southwest" : {
"lat" : 23.0661497,
"lng" : 77.2369767
}
},
"location" : {
"lat" : 23.2599333,
"lng" : 77.412615
},
"location_type" : "APPROXIMATE",
"viewport" : {
"northeast" : {
"lat" : 23.3326697,
"lng" : 77.5748062
},
"southwest" : {
"lat" : 23.0661497,
"lng" : 77.2369767
}
}
},
"place_id" : "ChIJvY_Wj49CfDkR-NRy1RZXFQI",
"types" : [ "locality", "political" ]
}
],
"status" : "OK"
}
I shall iterate in below given fashion
to "location" : {
"lat" : 23.2599333,
"lng" : 77.412615
//recieve JSON in json object
JSONObject json = new JSONObject(output.toString());
JSONArray result = json.getJSONArray("results");
JSONObject result1 = result.getJSONObject(0);
JSONObject geometry = result1.getJSONObject("geometry");
JSONObject locat = geometry.getJSONObject("location");
//"iterate onto level of location";
double lat = locat.getDouble("lat");
double lng = locat.getDouble("lng");
You can see that JSONObject extends a HashMap, so you can simply use it as a HashMap:
JSONObject jsonChildObject = (JSONObject)jsonObject.get("LanguageLevels");
for (Map.Entry in jsonChildOBject.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
JSONArray jsonChildArray = (JSONArray) jsonChildArray.get("LanguageLevels");
JSONObject secObject = (JSONObject) jsonChildArray.get(1);
I think this should work, but i do not have the possibility to test it at the moment..
To see all keys of Jsonobject use this
String JSON = "{\"LanguageLevels\":{\"1\":\"Pocz\\u0105tkuj\\u0105cy\",\"2\":\"\\u015arednioZaawansowany\",\"3\":\"Zaawansowany\",\"4\":\"Ekspert\"}}\n";
JSONObject obj = new JSONObject(JSON);
Iterator iterator = obj.keys();
String key = null;
while (iterator.hasNext()) {
key = (String) iterator.next();
System.out.pritnln(key);
}
Try this, you can parse nested JSON
public static String getJsonValue(String jsonReq, String key) {
JSONObject json = new JSONObject(jsonReq);
boolean exists = json.has(key);
Iterator<?> keys;
String nextKeys;
String val = "";
if (!exists) {
keys = json.keys();
while (keys.hasNext()) {
nextKeys = (String) keys.next();
try {
if (json.get(nextKeys) instanceof JSONObject) {
return getJsonValue(json.getJSONObject(nextKeys).toString(), key);
} else if (json.get(nextKeys) instanceof JSONArray) {
JSONArray jsonArray = json.getJSONArray(nextKeys);
int i = 0;
if (i < jsonArray.length()) do {
String jsonArrayString = jsonArray.get(i).toString();
JSONObject innerJson = new JSONObject(jsonArrayString);
return getJsonValue(innerJson.toString(),key);
} while (i < jsonArray.length());
}
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
val = json.get(key).toString();
}
return val;
}
Here is an example of retrieving nested JSON object.
Department and Product are model classes.
Department class holds department as a String and products as ArrayList of Product
Product class holds name as a String
depts and products are ArrayList of corresponding model classes
String jsonDataString = readJSONDataFromFile();
JSONArray jsonArray = new JSONArray(jsonDataString);
for (int i=0; i<jsonArray.length(); ++i) {
JSONObject departmentJSONObject = jsonArray.getJSONObject(i);
String deptName = departmentJSONObject.getString("department");
JSONArray productsJSONArray = departmentJSONObject.getJSONArray("products");
for (int j =0; j <productsJSONArray.length();j++){
JSONObject productJSONObject = productsJSONArray.getJSONObject(j);
String prodName = productJSONObject.getString("name");
Product product = new Product(prodName);
products.add(product);
}
Department department = new Department(deptName, products);
depts.add(department);
Here is my raw json file
[
{
"department": "Cold Drink",
"products": [
{
"name": "lemonade",
"img": "some_url"
},
{
"name": "Oj",
"img": "some_url"
}
]
},
{
"department": "CD2",
"products": [
{
"name": "lemonade2",
"img": "some_url2"
},
{
"name": "oj2",
"img": "some_url2"
}
]
},
{
"department": "CD3",
"products": [
{
"name": "lemonade3",
"img": "some_url3"
},
{
"name": "oj3",
"img": "some_url3"
}
]
}
]

Categories