I am trying to get weather forecast data from the WeatherUnderground API.
So far I am using the following code:
URLConnection connection = url.openConnection();
connection.setConnectTimeout(5000);
connection.connect();
JsonParser jp = new JsonParser();
JsonElement forecastJson = jp.parse(new InputStreamReader((InputStream) connection.getContent())).getAsJsonObject()
.getAsJsonObject().get("forecast")
.getAsJsonObject().get("simpleforecast")
.getAsJsonObject().getAsJsonArray("forecastday").get(1);
System.out.println("forecastJson = " + forecastJson.toString());
String date = String.valueOf(jp.parse(forecastJson
.getAsJsonObject().get("date")
.getAsJsonObject().get("epoch").getAsString()));
String high = String.valueOf(jp.parse(forecastJson
.getAsJsonObject().get("high")
.getAsJsonObject().get("celsius").getAsString()));
String low = String.valueOf(jp.parse(forecastJson
.getAsJsonObject().get("low")
.getAsJsonObject().get("celsius").getAsString()));
String conditions;
try {
conditions = String.valueOf(jp.parse(forecastJson
.getAsJsonObject().get("conditions").getAsString()));
} catch (JsonSyntaxException e) {
e.printStackTrace();
}
The JsonElement forecastJson" I receive looks like this:
{
"date": {
"epoch": "1467046800",
"pretty": "7:00 PM CEST on June 27, 2016",
"day": 27,
"month": 6,
"year": 2016,
"yday": 178,
"hour": 19,
"min": "00",
"sec": 0,
"isdst": "1",
"monthname": "June",
"monthname_short": "Jun",
"weekday_short": "Mon",
"weekday": "Monday",
"ampm": "PM",
"tz_short": "CEST",
"tz_long": "Europe/Berlin"
},
"period": 2,
"high": {
"fahrenheit": "77",
"celsius": "25"
},
"low": {
"fahrenheit": "58",
"celsius": "14"
},
"conditions": "Partly Cloudy",
"icon": "partlycloudy",
"icon_url": "http://icons.wxug.com/i/c/k/partlycloudy.gif",
"skyicon": "",
"pop": 0,
"qpf_allday": {
"in": 0,
"mm": 0
},
"qpf_day": {
"in": 0,
"mm": 0
},
"qpf_night": {
"in": 0,
"mm": 0
},
"snow_allday": {
"in": 0,
"cm": 0
},
"snow_day": {
"in": 0,
"cm": 0
},
"snow_night": {
"in": 0,
"cm": 0
},
"maxwind": {
"mph": 15,
"kph": 24,
"dir": "W",
"degrees": 260
},
"avewind": {
"mph": 11,
"kph": 18,
"dir": "W",
"degrees": 260
},
"avehumidity": 48,
"maxhumidity": 0,
"minhumidity": 0
}
I am able to get the "date", "high" and "low" Strings, but I'm unable to get the "conditions" and I don't understand what I'm doing wrong.
I am getting the following exception:
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON
As far as I understand the JSON is not malformed. How am I supposed to get the "conditions" value?
I've tried other JSON parsers / libraries as well, but nothing worked out. I'd like to continue working with the Gson-Library, and I guess I'm quite close, but stuck.
Thanks for any help.
If you break down the line that's throwing the exception you can see that you are actually trying to parse as JSON a string that is in fact not JSON.
try {
JsonObject jo = forecastJson.getAsJsonObject();
JsonElement je = jo.get("conditions");
String s1 = je.getAsString();
// at this point s1 contains the value "Partly Cloudy" which you
// are trying to parse as JSON.
JsonElement je2 = jp.parse(s1);
conditions = String.valueOf(je2);
} catch (JsonSyntaxException e) {
e.printStackTrace();
}
As "JB Nizet" pointed out in the comment under my question, I was trying to parse the JSON every time again when I wanted to get another piece of its contents. That was my (beginner) mistake.
Now I parse only once and then get the contents directly, without any problem:
JsonParser jp = new JsonParser();
JsonElement forecastJson = jp.parse(new InputStreamReader((InputStream) connection.getContent())).getAsJsonObject()
.getAsJsonObject().get("forecast")
.getAsJsonObject().get("simpleforecast")
.getAsJsonObject().getAsJsonArray("forecastday").get(1);
String date = forecastJson.getAsJsonObject().get("date")
.getAsJsonObject().get("epoch").getAsString();
String high = forecastJson.getAsJsonObject().get("high")
.getAsJsonObject().get("celsius").getAsString();
String low = forecastJson.getAsJsonObject().get("low")
.getAsJsonObject().get("celsius").getAsString();
String conditions = forecastJson.getAsJsonObject()
.get("conditions").getAsString();
First of all, as they say in the comments there's really no need to parse every piece again.
String date = String.valueOf(jp.parse(forecastJson
.getAsJsonObject().get("date")
.getAsJsonObject().get("epoch").getAsString()));
Is the same as:
String date = forecastJson.getAsJsonObject().get("date")
.getAsJsonObject().get("epoch").getAsString();
The problem that you're experiencing is actually something that I suspect is a bug in the Gson library. When it tries to parse a string with spaces in it, it will tokenize that string and expect that after the first word (Partly in this case) the document should end and that the json is malformed since it hasn't reached the end of the document.
So to solve this, either do as the comments say, which is the reasonable thing in your case. Or if you wan't you could always change Partly cloudy to for example Partly_cloudy and it will work :)
Related
I have a json file which I got from my backend.
The json file is as follows.
{
"documentTemplate": {
"pageFormat": {
"pageWidth": "50",
"pageLength": "13",
"usePageLengthFromPrinter": false
},
"template": {
"header": [
" Delivery Order ",
"Date : ${date} NO. : ${no_surat} ",
"Customer: ${customer} Delivery Date: ${delivery_date}"
],
"detail": [
{
"table": "table_details",
"border": "true",
"columns": [
{
"source": "description",
"width": 9,
"caption": "DESCRIPTION"
},
{
"source": "do_hanwa_and_date",
"width": 9,
"caption": "DO HW / DATE HW"
},
{
"source": "qty",
"width": 9,
"caption": "QTY"
},
{
"source": "nett",
"width": 9,
"caption": "NETT"
},
{
"source": "gross",
"width": 9,
"caption": "GROSS"
},
{
"source": "size",
"width": 9,
"caption": "SIZE"
},
{
"source": "location",
"width": 9,
"caption": "LOCATION"
},
{
"source": "urut",
"width": 9,
"caption": "URUT"
}
]
},
" ",
" ",
" ___________ ___________ ",
" (Signature) (Signature) "
]
}
},
"documentValue": {
"date": "13-05-2019",
"no_surat": "01024/05/DO-MARU/19JKT",
"customer": "PT. WIJAYA STEELINDO",
"delivery_date": "13-05-2019",
"table_details": [
{
"description": "03NKBTL190205005/12",
"do_hanwa_and_date": "46916 / 29-03-2019",
"qty": "1",
"nett": "4,568",
"gross": "4,616",
"size": "0.70MM X 151.8MM",
"location": "PT2212",
"urut": 64592
},
{
"description": "03NKBTL190204997/04",
"do_hanwa_and_date": "46916 / 29-03-2019",
"qty": "1",
"nett": "4,504",
"gross": "4,552",
"size": "0.70MM X 151.8MM",
"location": "PU5111",
"urut": 64591
}
]
}
}
To process the data: I use Gson.
public class Report {
String filePathString;
public HashMap<String, String> convertJsonToObject() {
Gson gson = new Gson();
try (JsonReader reader = new JsonReader(new FileReader(this.filePathString) )) {
// Converting JSON File to Java Object
HashMap<String, String> hashMapResult = gson.fromJson(reader, HashMap.class);
return hashMapResult;
} catch (IOException e) {
}
return null;
}
It's time to use the data from the GSON converter.
I use JSwing.
private void jButtonCompileGsonActionPerformed(java.awt.event.ActionEvent evt) {
// Create a report, param => file`s path
Report report = new Report(jTextFieldPathFile.getText());
// Read the file, as the return is a hashMap
HashMap<String, String> result = report.convertJsonToObject();
// Get based key
String documentTemplate = String.valueOf(result.get("documentTemplate")).replaceAll("\r?\n", "");
String documentValue = String.valueOf(result.get("documentValue")).replaceAll("\r?\n", "");
// Just to clarify
System.out.println(documentTemplate);
System.out.println(documentValue);
}
The result is:
documentTemplate => {pageFormat={pageWidth=50, pageLength=13, usePageLengthFromPrinter=false}, template={header=[ Delivery Order , Date : ${date} NO. : ${no_surat} , Customer: ${customer} Delivery Date: ${delivery_date}], detail=[{table=table_details, border=true, columns=[{source=description, width=9.0, caption=DESCRIPTION}, {source=do_hanwa_and_date, width=9.0, caption=DO HW / DATE HW}, {source=qty, width=9.0, caption=QTY}, {source=nett, width=9.0, caption=NETT}, {source=gross, width=9.0, caption=GROSS}, {source=size, width=9.0, caption=SIZE}, {source=location, width=9.0, caption=LOCATION}, {source=urut, width=9.0, caption=URUT}]}, , , ___________ ___________ , (Signature) (Signature) ]}}
documentValue => {date=13-05-2019, no_surat=01024/05/DO-MARU/19JKT, customer=PT. WIJAYA STEELINDO, delivery_date=13-05-2019, table_details=[{description=03NKBTL190205005/12, do_hanwa_and_date=46916 / 29-03-2019, qty=1, nett=4,568, gross=4,616, size=0.70MM X 151.8MM, location=PT2212, urut=64592.0}, {description=03NKBTL190204997/04, do_hanwa_and_date=46916 / 29-03-2019, qty=1, nett=4,504, gross=4,552, size=0.70MM X 151.8MM, location=PU5111, urut=64591.0}]}
I use this library: SimpleESCP
From these libraries, the interpretation is as follows.
import javax.json.JsonObject;
public class JsonDataSource implements DataSource {
private static final Logger LOG;
private JsonObject source;
public JsonDataSource(String jsonString){
}
}
I use it like this and get the following error message:
JsonDataSource jsonDataSource = new JsonDataSource(documentValue);
Exception in thread "AWT-EventQueue-0" javax.json.stream.JsonParsingException: Unexpected char 100 at (line no=1, column no=2, offset=1)
Please help and advice.
Thank you.
I am making a weather app to understand how to use Gson and web api's with java here is my current code:
public class Weather
{
public static void main(String[] args) throws Exception
{
URL ipStacks = new URL("http://api.ipstack.com/check?access_key=(my api key)");
BufferedReader reader = new BufferedReader(
new InputStreamReader(ipStacks.openStream()));
String inputLine = reader.readLine();
String json = inputLine;
Gson gson = new Gson();
LocationData location = gson.fromJson(json, LocationData.class);
System.out.println(location.ip);
System.out.println(location.latitude);
System.out.println(location.longitude);
String darkSkyBase = "https://api.darksky.net/forecast/(my api key)/";
URL darkSky = new URL(darkSkyBase+location.latitude+","+location.longitude);
BufferedReader reader2 = new BufferedReader(
new InputStreamReader(darkSky.openStream()));
inputLine = reader2.readLine();
WeatherData weather = gson.fromJson(inputLine, WeatherData.class);
System.out.println(weather.currently);
}
}
class LocationData
{
String ip;
String latitude;
String longitude;
}
class WeatherData
{
String currently;
}
I am getting this error:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 81 path $.currently
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
at com.google.gson.Gson.fromJson(Gson.java:927)
at com.google.gson.Gson.fromJson(Gson.java:892)
at com.google.gson.Gson.fromJson(Gson.java:841)
at com.google.gson.Gson.fromJson(Gson.java:813)
at com.thomasbriggs.json.App.main(App.java:37)
Caused by: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 81 path $.currently
at com.google.gson.stream.JsonReader.nextString(JsonReader.java:825)
at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:402)
at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:390)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
... 5 more
I am guessing because with the darksky api the currently is another json list but how do I tell Gson to expect a json list?
The JSON string I am having trouble with looks like this:
{
"latitude": 42.3601,
"longitude": -71.0589,
"timezone": "America/New_York",
"currently": {
"time": 1509993277,
"summary": "Drizzle",
"icon": "rain",
"nearestStormDistance": 0,
"precipIntensity": 0.0089,
"precipIntensityError": 0.0046,
"precipProbability": 0.9,
"precipType": "rain",
"temperature": 66.1,
"apparentTemperature": 66.31,
"dewPoint": 60.77,
"humidity": 0.83,
"pressure": 1010.34,
"windSpeed": 5.59,
"windGust": 12.03,
"windBearing": 246,
"cloudCover": 0.7,
"uvIndex": 1,
"visibility": 9.84,
"ozone": 267.44
},
"minutely": {
"summary": "Light rain stopping in 13 min., starting again 30 min. later.",
"icon": "rain",
"data": [{
"time": 1509993240,
"precipIntensity": 0.007,
"precipIntensityError": 0.004,
"precipProbability": 0.84,
"precipType": "rain"
},
...
]
},
"hourly": {
"summary": "Rain starting later this afternoon, continuing until this evening.",
"icon": "rain",
"data": [{
"time": 1509991200,
"summary": "Mostly Cloudy",
"icon": "partly-cloudy-day",
"precipIntensity": 0.0007,
"precipProbability": 0.1,
"precipType": "rain",
"temperature": 65.76,
"apparentTemperature": 66.01,
"dewPoint": 60.99,
"humidity": 0.85,
"pressure": 1010.57,
"windSpeed": 4.23,
"windGust": 9.52,
"windBearing": 230,
"cloudCover": 0.62,
"uvIndex": 1,
"visibility": 9.32,
"ozone": 268.95
},
...
]
},
"daily": {
"summary": "Mixed precipitation throughout the week, with temperatures falling to 39°F on Saturday.",
"icon": "rain",
"data": [{
"time": 1509944400,
"summary": "Rain starting in the afternoon, continuing until evening.",
"icon": "rain",
"sunriseTime": 1509967519,
"sunsetTime": 1510003982,
"moonPhase": 0.59,
"precipIntensity": 0.0088,
"precipIntensityMax": 0.0725,
"precipIntensityMaxTime": 1510002000,
"precipProbability": 0.73,
"precipType": "rain",
"temperatureHigh": 66.35,
"temperatureHighTime": 1509994800,
"temperatureLow": 41.28,
"temperatureLowTime": 1510056000,
"apparentTemperatureHigh": 66.53,
"apparentTemperatureHighTime": 1509994800,
"apparentTemperatureLow": 35.74,
"apparentTemperatureLowTime": 1510056000,
"dewPoint": 57.66,
"humidity": 0.86,
"pressure": 1012.93,
"windSpeed": 3.22,
"windGust": 26.32,
"windGustTime": 1510023600,
"windBearing": 270,
"cloudCover": 0.8,
"uvIndex": 2,
"uvIndexTime": 1509987600,
"visibility": 10,
"ozone": 269.45,
"temperatureMin": 52.08,
"temperatureMinTime": 1510027200,
"temperatureMax": 66.35,
"temperatureMaxTime": 1509994800,
"apparentTemperatureMin": 52.08,
"apparentTemperatureMinTime": 1510027200,
"apparentTemperatureMax": 66.53,
"apparentTemperatureMaxTime": 1509994800
},
...
]
},
"alerts": [
{
"title": "Flood Watch for Mason, WA",
"time": 1509993360,
"expires": 1510036680,
"description": "...FLOOD WATCH REMAINS IN EFFECT THROUGH LATE MONDAY NIGHT...\nTHE FLOOD WATCH CONTINUES FOR\n* A PORTION OF NORTHWEST WASHINGTON...INCLUDING THE FOLLOWING\nCOUNTY...MASON.\n* THROUGH LATE FRIDAY NIGHT\n* A STRONG WARM FRONT WILL BRING HEAVY RAIN TO THE OLYMPICS\nTONIGHT THROUGH THURSDAY NIGHT. THE HEAVY RAIN WILL PUSH THE\nSKOKOMISH RIVER ABOVE FLOOD STAGE TODAY...AND MAJOR FLOODING IS\nPOSSIBLE.\n* A FLOOD WARNING IS IN EFFECT FOR THE SKOKOMISH RIVER. THE FLOOD\nWATCH REMAINS IN EFFECT FOR MASON COUNTY FOR THE POSSIBILITY OF\nAREAL FLOODING ASSOCIATED WITH A MAJOR FLOOD.\n",
"uri": "http://alerts.weather.gov/cap/wwacapget.php?x=WA1255E4DB8494.FloodWatch.1255E4DCE35CWA.SEWFFASEW.38e78ec64613478bb70fc6ed9c87f6e6"
},
...
],
{
"flags": {
"units": "us",
...
}
}
Any help would be great, if you have any question please ask.
currently is a object while your type is String. If you do not want to create structure for currently then declare it as a map Map<String, Object> currently - GSON will put all key-value pairs here
I was checking the JSON and it seems your are getting double values for longitude and latitude:
"latitude": 42.3601,
"longitude": -71.0589,
but you are trying to save them in String
class LocationData
{
String ip;
String latitude;
String longitude;
}
Change the variables to double and try again.
I get data from an API in which the JSON object changes randomly, like if it is at "position": 1, now it will change randomly to "number": 1. So, how can I check in my application if the object is at "position": 1 or "number": 1 and use it as int?
JSON :-
{
"now": [{
"time": {
"starts_in": 0,
"ends_in": 79580,
"starts_at": 0,
"ends_at": "2018-01-21T08:00:00.788Z"
},
"coins": {
"free": 8,
"first_win": 16,
"max": 52,
"collected": 0
},
"unk1": -88317689,
"position": 1,
"xp_multiplier": 0,
"location_scid": {
"scid_type": 15,
"scid_id": 1
},
"tid": "TID_WANTED_3",
"location": "Terre",
"mode": {
"name": "Bty",
"color": "#0884FA",
"description": " The team wins!"
},
"unk4": 0,
"info": "",
"unk5": 0,
"unk6": 0
}, {
"time": {
"starts_in": 0,
"ends_in": 36380,
"starts_at": 0,
"ends_at": "2018-01-20T20:00:00.788Z"
},
"coins": {
"free": 24,
"first_win": 0,
"max": 32,
"collected": 0
}
}],
"later": [{
"time": {
"starts_in": 79580,
"ends_in": 165980,
"starts_at": "2018-01-21T08:00:00.788Z",
"ends_at": "2018-01-22T08:00:00.788Z"
},
"coins": {
"free": 8,
"first_win": 16,
"max": 52,
"collected": 0
},
"unk1": -88217689,
"position": 1,
"xp_multiplier": 0,
"location_scid": {
"scid_type": 15,
"scid_id": 7
},
"tid": "TID_GOLDRUSH_1",
"location": "Mine",
"mode": {
"name": "Grab",
"color": "#AA57CF",
"description": " An. "
}
}]
}
Thanks in advance :)
JSONObject c = //Your jsonObject;
String position = c.getInt("position");
String number = c.getInt("number");
if(position!=null){
//TODO You know it is position and it's int value
}else if(number!=null){
//TODO You know it is number and it's int value
}else{
//TODO Its neither of two
}
If you're using Gson to convert your JSON to a class, you can use both position and number as attributes for your destination class.
After that, check which one is null and which one is not and use that is not null as your number.
Just try this one,
JSONObject object = (Your jsonObject);
if(object.has("position")){
** do your code here **
}else if(object.has("number"){
** do your code here **
}
In my project I have an int jsonobject by 20 value. To get the int value I used this:
model.setInt(jsonObject.getInt("price"));
Now it returns 0 value for price. How can I get real value?
Here is My out put Json:
"data": [
{
"id": "571dd7817f8b9a1c190bbdb5",
"goods": 0,
"rate": {
"r1": 0
},
"price": 20
}
Please look at the example:
String jsonData = "{\"count\": 20}";
JSONObject obj = new JSONObject(jsonData);
System.out.println("Count: " + obj.getInt("count"));
Your JSON is invalid. you can use online tools like the jsonformatter to test the validity of your JSON.
Maybe try something like:
{
"data": [
{
"id": "571dd7817f8b9a1c190bbdb5",
"goods": 0,
"rate": {"r1": 0},
"price": 20
}
]
}
Looking at your code, you may have better luck with this structure:
{
"id": "571dd7817f8b9a1c190bbdb5",
"goods": 0,
"rate": {"r1": 0},
"price": 20
}
This question already has answers here:
Simplest way to read JSON from a URL in Java
(12 answers)
Closed 7 years ago.
I have a json url link which i would like to read its json response and extract values into variables so that i can use them later
{
"responseHeader": {
"status": 0,
"QTime": 4,
"params": {
"q": "*:*",
"facet.field": "TESTARRAY",
"indent": "true",
"rows": "0",
"wt": "json",
"facet": "true"
}
},
"response": {
"numFound": 12,
"start": 0,
"docs": []
},
"facet_counts": {
"facet_queries": {},
"facet_fields": {
"TESTARRAY": [
"JON",
22,
"SMITH",
34,
"ROBERT",
12
]
},
"facet_dates": {},
"facet_ranges": {},
"facet_intervals": {}
}
}
For extraction,I am using
JSONObject obj = new JSONObject(IOUtils.toString(new URL(jsonlink), Charset.forName("UTF-8")));
JSONArray arr = obj.getJSONArray("TEST_ARRAY");
Integer smithage=arr.get("SMITH");
So far this approach is not working.
What would be the best way to deal with it
Thanks in advance
TEST_ARRAY is not a top-level field, you need to dig down to get it, something like:
JSONObject obj = new JSONObject(IOUtils.toString(new URL(jsonlink), Charset.forName("UTF-8")));
JSONObject facet_counts = obj.getJSONObjecy("facet_counts");
JSONObject facet_fields = facet_counts.getJSONObjecy("facet_fields");
JSONArray test_array = obj.getJSONArray("TESTARRAY");
Integer smithage = test_array.getInt(3);