0

I'm running into a few issues similar to what others have had in the past with Json parsing in Java. This is the first time I try something like this so any help/tips is extremely useful.

I'm trying to parse in data from this site: https://api.bitcoinaverage.com/exchanges/USD

I have tried numerous ways with both Json and Gson. And have tried looking for help here but to no avail.

Here are the classes that are set up (these were auto generated):

Info.java:

    public class Info{
    private String display_URL;
    private String display_name;
    private Rates[] rates;
    private String source;
    private Number volume_btc;
    private Number volume_percent;

    public String getDisplay_URL(){
        return this.display_URL;
    }
    public void setDisplay_URL(String display_URL){
        this.display_URL = display_URL;
    }
    public String getDisplay_name(){
        return this.display_name;
    }
    public void setDisplay_name(String display_name){
        this.display_name = display_name;
    }
    public Rates[] getRates(){
        return this.rates;
    }
    public void setRates(Rates[] rates){
        this.rates = rates;
    }
    public String getSource(){
        return this.source;
    }
    public void setSource(String source){
        this.source = source;
    }
    public Number getVolume_btc(){
        return this.volume_btc;
    }
    public void setVolume_btc(Number volume_btc){
        this.volume_btc = volume_btc;
    }
    public Number getVolume_percent(){
        return this.volume_percent;
    }
    public void setVolume_percent(Number volume_percent){
        this.volume_percent = volume_percent;
    }
}

Rates.java:

public class Rates {
    private Number ask;
    private Number bid;
    private Number last;

    public Number getAsk(){
        return this.ask;
    }
    public void setAsk(Number ask){
        this.ask = ask;
    }
    public Number getBid(){
        return this.bid;
    }
    public void setBid(Number bid){
        this.bid = bid;
    }
    public Number getLast(){
        return this.last;
    }
    public void setLast(Number last){
        this.last = last;
    }
}

MainClass.java:

public class MainClass {

    public static void main(String[] args) throws Exception {

        Gson gson = new Gson();

        String json = readUrl("https://api.bitcoinaverage.com/exchanges/USD");

        Info page = gson.fromJson(json, Info.class);
        System.out.println(page.getDisplay_name());
    }

    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();
        }
    }
}

When I try to call a getter, a null is returned. How do I go about parsing the data properly, and then being able to call an attribute from which ever object I want? For example, if I want an attribute from "anx_hk" or "bitfinex".

This is the first time me posting something here so I hope I'm following the proper guidelines.

I also plan on passing this over to Android once I get the fell for parsing Json better. Thanks for the help! It'll greatly be appreciated.

1
  • The Info type does not match the properties of the top level JSON object. You would need an object with a bitfinex property to get that data. Commented Apr 4, 2014 at 5:00

2 Answers 2

1

I'll be honest with you, that's a pretty lame API response. Here it is

{
  "anx_hk": {
    "display_URL": "https://anxbtc.com/",
    "display_name": "ANXBTC",
    "rates": {
      "ask": 454.26,
      "bid": 444.46,
      "last": 443.78
    },
    "source": "bitcoincharts",
    "volume_btc": 11.73,
    "volume_percent": 0.02
  }, 
  ...,
  "timestamp": "Fri, 04 Apr 2014 04:30:26 -0000",
  ...
}

There's no JSON array here, so you can get rid of all your array types. This response is a JSON object, which contains a bunch of JSON objects (which share a format) and a JSON name value pair where the name is timestamp.

The common JSON objects have two fields of type double (that's what type your field should be, not Number)

"volume_btc": 11.73,
"volume_percent": 0.02

, three fields of type String

"display_URL": "https://anxbtc.com/",
"display_name": "ANXBTC",
"source": "bitcoincharts",

and one that is a JSON object that contains three more doubles

"rates": {
      "ask": 454.26,
      "bid": 444.46,
      "last": 443.78
}

The actual issue here is that, I'm assuming, the JSON objects in the root JSON object have names that may change or new ones may be added. This is not a good fit for a POJO. Instead you'd want to use a Map<String, Info>, but Gson can't map to that by default. It is not well suited for such deserialization. You'd have to provide your own TypeAdapter.

Instead, I'm going to suggest you use Jackson.

If we put that all together, we get something like

class ApiResponse {
    private Map<String, Info> page = new HashMap<>();
    private Date timestamp;

    public Map<String, Info> getPage() {
        return page;
    }

    @JsonAnySetter
    public void setPage(String name, Info value) {
        page.put(name, value);
    }

    public Date getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Date timestamp) {
        this.timestamp = timestamp;
    }
}

class Info {
    private String display_URL;
    private String display_name;
    private Rates rates;
    private String source;
    private Double volume_btc;
    private Double volume_percent;

    public String getDisplay_URL() {
        return this.display_URL;
    }

    public void setDisplay_URL(String display_URL) {
        this.display_URL = display_URL;
    }

    public String getDisplay_name() {
        return this.display_name;
    }

    public void setDisplay_name(String display_name) {
        this.display_name = display_name;
    }

    public Rates getRates() {
        return this.rates;
    }

    public void setRates(Rates rates) {
        this.rates = rates;
    }

    public String getSource() {
        return this.source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public Double getVolume_btc() {
        return this.volume_btc;
    }

    public void setVolume_btc(Double volume_btc) {
        this.volume_btc = volume_btc;
    }

    public Double getVolume_percent() {
        return this.volume_percent;
    }

    public void setVolume_percent(Double volume_percent) {
        this.volume_percent = volume_percent;
    }
}

class Rates {
    private Double ask;
    private Double bid;
    private Double last;

    public Number getAsk() {
        return this.ask;
    }

    public void setAsk(Double ask) {
        this.ask = ask;
    }

    public Double getBid() {
        return this.bid;
    }

    public void setBid(Double bid) {
        this.bid = bid;
    }

    public Double getLast() {
        return this.last;
    }

    public void setLast(Double last) {
        this.last = last;
    }
}

With deserialization code such as

String json = readUrl("https://api.bitcoinaverage.com/exchanges/USD");

ObjectMapper mapper = new ObjectMapper();
ApiResponse response = mapper.readValue(json, ApiResponse.class);
System.out.println(response);

With appropriate toString() methods (mine were auto-generated with Eclipse), you would get something like

ApiResponse [pages={bitkonan=Info [display_URL=https://bitkonan.com/, display_name=BitKonan, rates=Rates [ask=475.0, bid=438.01, last=437.0], source=api, volume_btc=7.24, volume_percent=0.01], vaultofsatoshi=Info [display_URL=https://vaultofsatoshi.com, display_name=Vault of Satoshi, rates=Rates [ask=460.0, bid=460.0, last=460.0], source=api, volume_btc=11.46, volume_percent=0.02], bitstamp=Info [display_URL=https://bitstamp.net/, display_name=Bitstamp, rates=Rates [ask=439.16, bid=436.34, last=436.34], source=api, volume_btc=22186.29, volume_percent=35.19], ...}, timestamp=Fri Apr 04 01:02:43 EDT 2014]

as output.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! This helped out a ton. I'm able to work more off of this.
1

The api response contains many objects, but seems that you are trying to read them as a single Info object.
You may try to read the response as a Map<String, Info>, and iterate the entries.

Map<String, Info> hashMap = gson.fromJson(body, HashMap.class);
for (Map.Entry entry : hashMap.entrySet()) {
    // your code
}

1 Comment

They're not all Info objects however.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.