1

I am having trouble with parson the JSON from a URL. Below, is the code.

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.List;
import com.google.gson.Gson;


public class Test_Application {

    /**
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Gson gson = new Gson();

        String json = readUrl("http://api.wunderground.com/api/57dd9039b81a9c21/conditions/q/CA/San_Francisco.json");

        Page page = gson.fromJson(json, Page.class);

        System.out.println(page.description);
        System.out.println(page.language);
        System.out.println(page.link);
        System.out.println(page.title);

    }

    private static String readUrl(String urlString) throws Exception {
        BufferedReader reader = null;
        try {
            URL url = new URL(urlString);
            reader = new BufferedReader(new InputStreamReader(url.openStream()));
            StringBuffer buffer = new StringBuffer();
            int read;
            char[] chars = new char[1024];
            while ((read = reader.read(chars)) != -1)
                buffer.append(chars, 0, read); 

            return buffer.toString();
        } finally {
            if (reader != null)
                reader.close();
        }

    }

    static class Page {
        String title;
        String link;
        String description;
        String language;
        List<Item> items;
    }

    static class Item {
        String title;
        String link;
        String description;
    }


}

The output is:

null
null
null
null

What I think the problem is that, I have an inappropriate class to read the data. Would that be correct?

Thanks

EDIT

The website returns the following:

{
  "response": {
    "version": "0.1",
    "termsofService": "http://www.wunderground.com/weather/api/d/terms.html",
    "features": {
      "conditions": 1
    }
  },
  "current_observation": {
    "image": {
      "url": "http://icons-ak.wxug.com/graphics/wu2/logo_130x80.png",
      "title": "Weather Underground",
      "link": "http://www.wunderground.com"
    },
    "display_location": {
      "full": "San Francisco, CA",
      "city": "San Francisco",
      "state": "CA",
      "state_name": "California",
      "country": "US",
      "country_iso3166": "US",
      "zip": "94101",
      "latitude": "37.77500916",
      "longitude": "-122.41825867",
      "elevation": "47.00000000"
    },
    "observation_location": {
      "full": "SOMA - Near Van Ness, San Francisco, California",
      "city": "SOMA - Near Van Ness, San Francisco",
      "state": "California",
      "country": "US",
      "country_iso3166": "US",
      "latitude": "37.773285",
      "longitude": "-122.417725",
      "elevation": "49 ft"
    },
    "estimated": {

    },
    "station_id": "KCASANFR58",
    "observation_time": "Last Updated on February 19, 7:08 AM PST",
    "observation_time_rfc822": "Tue, 19 Feb 2013 07:08:18 -0800",
    "observation_epoch": "1361286498",
    "local_time_rfc822": "Tue, 19 Feb 2013 07:08:31 -0800",
    "local_epoch": "1361286511",
    "local_tz_short": "PST",
    "local_tz_long": "America/Los_Angeles",
    "local_tz_offset": "-0800",
    "weather": "Mostly Cloudy",
    "temperature_string": "47.9 F (8.8 C)",
    "temp_f": 47.9,
    "temp_c": 8.8,
    "relative_humidity": "87%",
    "wind_string": "From the SW at 4.0 MPH Gusting to 13.0 MPH",
    "wind_dir": "SW",
    "wind_degrees": 225,
    "wind_mph": 4.0,
    "wind_gust_mph": "13.0",
    "wind_kph": 6.4,
    "wind_gust_kph": "20.9",
    "pressure_mb": "1012",
    "pressure_in": "29.90",
    "pressure_trend": "-",
    "dewpoint_string": "44 F (7 C)",
    "dewpoint_f": 44,
    "dewpoint_c": 7,
    "heat_index_string": "NA",
    "heat_index_f": "NA",
    "heat_index_c": "NA",
    "windchill_string": "46 F (8 C)",
    "windchill_f": "46",
    "windchill_c": "8",
    "feelslike_string": "46 F (8 C)",
    "feelslike_f": "46",
    "feelslike_c": "8",
    "visibility_mi": "10.0",
    "visibility_km": "16.1",
    "solarradiation": "",
    "UV": "0",
    "precip_1hr_string": "0.00 in ( 0 mm)",
    "precip_1hr_in": "0.00",
    "precip_1hr_metric": " 0",
    "precip_today_string": "0.02 in (1 mm)",
    "precip_today_in": "0.02",
    "precip_today_metric": "1",
    "icon": "mostlycloudy",
    "icon_url": "http://icons-ak.wxug.com/i/c/k/mostlycloudy.gif",
    "forecast_url": "http://www.wunderground.com/US/CA/San_Francisco.html",
    "history_url": "http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=KCASANFR58",
    "ob_url": "http://www.wunderground.com/cgi-bin/findweather/getForecast?query=37.773285,-122.417725"
  }
}

Updated code

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.List;
import com.google.gson.Gson;


public class Test_Application {

    /**
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        Gson gson = new Gson();

        String json = readUrl("http://api.wunderground.com/api/57dd9039b81a9c21/conditions/q/CA/San_Francisco.json");

        // Page page = gson.fromJson(json, Page.class);
        Response response = gson.fromJson(json, Response.class);

        System.out.println(response.termsOfService);
        System.out.println(response.version);

    }

    private static String readUrl(String urlString) throws Exception {
        BufferedReader reader = null;
        try {
            URL url = new URL(urlString);
            reader = new BufferedReader(new InputStreamReader(url.openStream()));
            StringBuffer buffer = new StringBuffer();
            int read;
            char[] chars = new char[1024];
            while ((read = reader.read(chars)) != -1)
                buffer.append(chars, 0, read); 

            return buffer.toString();
        } finally {
            if (reader != null)
                reader.close();
        }

    }

    static class Response{
        String version;
        String termsOfService;
    }


}
Jeel Shah
  • 3,274
  • 17
  • 47
  • 68
  • 2
    @downvoter, may I please have the reason to improve the post? – Jeel Shah Feb 19 '13 at 15:28
  • What does the website return? – Boris the Spider Feb 19 '13 at 15:29
  • P.S. I didn't downvote. – Boris the Spider Feb 19 '13 at 15:29
  • 2
    The problem is that your POJO doen't resemble the JSON in any way, shape, or form. – Brian Roach Feb 19 '13 at 15:30
  • @bmorris591 Thanks :) I have updated the code with the response. I have used an online JSON viewer to get the response. – Jeel Shah Feb 19 '13 at 15:31
  • @BrianRoach is correct, you need to create a POJO that matches the JSON. – Boris the Spider Feb 19 '13 at 15:33
  • @BrianRoach could you please provide a simple example? I'm having trouble with the POJO concept. – Jeel Shah Feb 19 '13 at 15:34
  • See: http://stackoverflow.com/questions/14826237/reading-a-json-reply-from-weatherunderground/14842859#14842859 In fact, this could probably be closed as a dup. – Brian Roach Feb 19 '13 at 15:35
  • @gekkostate [this](http://stackoverflow.com/questions/14826237/reading-a-json-reply-from-weatherunderground) and [this](http://stackoverflow.com/questions/14910124/how-to-meaningfully-extract-information-from-a-json-reply/14910200#14910200) may be helpful. – Boris the Spider Feb 19 '13 at 15:35
  • @BrianRoach In essence, I have to go through the various aspects of the JSON and make a relevant POJO that can deserialize? – Jeel Shah Feb 19 '13 at 15:37
  • That is correct. JSON represents an object. Your Java object (POJO) needs to match that object. Or as I show in the answer I link to, you can just parse it and pick out the items you want and not use a POJO. – Brian Roach Feb 19 '13 at 15:40
  • THe *one* exception being that you don't have to create the *entire* object in Java if you only want certain parts of the JSON. Gson will silently ignore any part of the JSON that you don't include in your POJO (And vice versa, as you have discovered - that's why all your fields are currently null). – Brian Roach Feb 19 '13 at 15:42
  • @BrianRoach Great! It would be great, if you would like to add this as answer, so I can accept it. – Jeel Shah Feb 19 '13 at 15:44

2 Answers2

2

Alternatives to GSON exists:

This snippet may help to do a generic decoder:

Map< String, Object > decoded =
   gson.fromJson(data, new TypeToken< Map< String, Object>>() {}.getType());

The following code is a beginning of a specific decoder:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;

import com.google.gson.Gson;

public class Test_Application
{
   public static void main(
      String[] args ) throws Exception
   {
      Gson gson = new Gson();
      String json = readUrl(
         "http://api.wunderground.com/api/57dd9039b81a9c21/" +
         "conditions/q/CA/San_Francisco.json" );
      System.out.println( json );

      Map< String, Object > decoded =
         gson.fromJson(
            json,
            new TypeToken< Map< String, Object>>() {}.getType());
      System.out.println( decoded );

      Answer answer = gson.fromJson( json, Answer.class );
      System.out.println( answer.response.version );
      System.out.println( answer.response.termsofService );
      System.out.println( answer.response.features.get( "conditions" ));
      System.out.println( answer.current_observation.image );
      System.out.println( answer.current_observation.display_location );
   }

   static class Response
   {
      String                version;
      URL                   termsofService;
      Map< String, String > features;
   }

   static class Observation
   {
      Map< String, String > image;
      Map< String, String > display_location;
      // TODO: complete me
   }

   static class Location
   {
      // TODO: complete me
   }

   static class Answer
   {
      Response    response;
      Observation current_observation;
      Location    display_location;
      // TODO: complete me
   }

At this state of development, it returns:

{response={version=0.1, termsofService=http://www.wunderground.com/weather/api/d/terms.html, features={conditions=1.0}}, current_observation={image={url=http://icons-ak.wxug.com/graphics/wu2/logo_130x80.png, title=Weather Underground, link=http://www.wunderground.com}, display_location={full=San Francisco, CA, city=San Francisco, state=CA, state_name=California, country=US, country_iso3166=US, zip=94101, latitude=37.77500916, longitude=-122.41825867, elevation=47.00000000}, observation_location={full=SOMA - Near Van Ness, San Francisco, California, city=SOMA - Near Van Ness, San Francisco, state=California, country=US, country_iso3166=US, latitude=37.773285, longitude=-122.417725, elevation=49 ft}, estimated={}, station_id=KCASANFR58, observation_time=Last Updated on February 19, 8:16 AM PST, observation_time_rfc822=Tue, 19 Feb 2013 08:16:18 -0800, observation_epoch=1361290578, local_time_rfc822=Tue, 19 Feb 2013 08:16:18 -0800, local_epoch=1361290578, local_tz_short=PST, local_tz_long=America/Los_Angeles, local_tz_offset=-0800, weather=Mostly Cloudy, temperature_string=48.7 F (9.3 C), temp_f=48.7, temp_c=9.3, relative_humidity=83%, wind_string=From the ESE at 1.0 MPH, wind_dir=ESE, wind_degrees=109.0, wind_mph=1.0, wind_gust_mph=0.0, wind_kph=1.6, wind_gust_kph=0.0, pressure_mb=1012, pressure_in=29.88, pressure_trend=-, dewpoint_string=44 F (7 C), dewpoint_f=44.0, dewpoint_c=7.0, heat_index_string=NA, heat_index_f=NA, heat_index_c=NA, windchill_string=49 F (9 C), windchill_f=49, windchill_c=9, feelslike_string=49 F (9 C), feelslike_f=49, feelslike_c=9, visibility_mi=10.0, visibility_km=16.1, solarradiation=, UV=0, precip_1hr_string=0.00 in ( 0 mm), precip_1hr_in=0.00, precip_1hr_metric= 0, precip_today_string=0.02 in (1 mm), precip_today_in=0.02, precip_today_metric=1, icon=mostlycloudy, icon_url=http://icons-ak.wxug.com/i/c/k/mostlycloudy.gif, forecast_url=http://www.wunderground.com/US/CA/San_Francisco.html, history_url=http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=KCASANFR58, ob_url=http://www.wunderground.com/cgi-bin/findweather/getForecast?query=37.773285,-122.417725}}

0.1
http://www.wunderground.com/weather/api/d/terms.html
1
{url=http://icons-ak.wxug.com/graphics/wu2/logo_130x80.png, title=Weather Underground, link=http://www.wunderground.com}
{full=San Francisco, CA, city=San Francisco, state=CA, state_name=California, country=US, country_iso3166=US, zip=94101, latitude=37.77500916, longitude=-122.41825867, elevation=47.00000000}
Community
  • 1
  • 1
Aubin
  • 14,617
  • 9
  • 61
  • 84
  • once I fill in the classes you have specified, I should be able to access the data right? – Jeel Shah Feb 19 '13 at 15:57
  • 1
    Just as an FYI (And I only know this from other WU JSON questions) `features` in `Response` can actually contain a bunch of things which is why in my `Response` it's a `Map`. I don't know the full list of possibilities; you could also flesh out a complete `Features` object if there's a list in the API docs of all of them. – Brian Roach Feb 19 '13 at 15:58
  • Yes, but it's painful, if you want just use fields, a generic Map< String, Object > with a custom made parser may be useful. – Aubin Feb 19 '13 at 15:59
  • THere is literally no reason to do what you state given the Gson will happily act as a generic JSON parser if you don't want to use a POJO. It's in my original answer that this question is really a dup of ... – Brian Roach Feb 19 '13 at 16:23
1

Your problem is that your POJO doesn't match your JSON.

JSON represents an object, and your POJO needs to match it. Here's a start of what that would look like (all fields public with no getters/setters just to make this example small):

class MyWUPojo {
    public Response response;
    // more after this that match the JSON
}

class Response {
    public String version;
    public String termsofservice;
    public Map<String, Integer> features;
}

Note that the one caveat is that if you are only interested in part of the JSON response, that's all you have to implement. Gson will silently ignore any part of the JSON you haven't included in your POJO.

Brian Roach
  • 76,169
  • 12
  • 136
  • 161