GNUman
GNUman

Reputation: 1

Parsing unnamed nested arrays with minimal-json?

So I'm working on a fairly simple Java program which grabs market data from cryptocurrency exchanges and displays information to the user. I am using the minimal-json library.

Here is my current code:

public class Market {
    static JsonArray arrayBittrex;

    public static void startTimer(){
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                String url = "https://bittrex.com/api/v1.1/public/getmarketsummaries";
                try {
                    URL url2 = new URL(url);
                    URLConnection con = url2.openConnection();
                    InputStream in = con.getInputStream();
                    String encoding = "UTF-8";
                    String body = IOUtils.toString(in, encoding);
                    arrayBittrex = Json.parse(body).asObject().get("result").asArray();
                }
                catch(MalformedURLException e) {}
                catch(IOException e) {}
            }
        }, 0,5000);
    }

    public static float getPrice(String exchange, String market) {
        for (JsonValue item : arrayBittrex) {
            float last = item.asObject().getFloat("Last", 0);
            System.out.println(last);
            return last;
        }
        return 0;
    }
}

This code works with simple json, for example (from https://bittrex.com/api/v1.1/public/getmarketsummary?market=btc-ltc):

{
    "success" : true,
    "message" : "",
    "result" : [{
            "MarketName" : "BTC-LTC",
            "High" : 0.01350000,
            "Low" : 0.01200000,
            "Volume" : 3833.97619253,
            "Last" : 0.01349998
        }
    ]
}

It will properly return the "Last" value in the array. However, this cant work when the json has multiple arrays (like in https://bittrex.com/api/v1.1/public/getmarketsummaries):

{
    "success" : true,
    "message" : "",
    "result" : [{
            "MarketName" : "BTC-888",
            "High" : 0.00000919,
            "Low" : 0.00000820,
            "Volume" : 74339.61396015,
            "Last" : 0.00000820
        }, {
            "MarketName" : "BTC-A3C",
            "High" : 0.00000072,
            "Low" : 0.00000001,
            "Volume" : 166340678.42280999,
            "Last" : 0.00000005
        }
    ]
}

So my question is: how can I get the "Last" value by searching for the array by the "MarketName" value?

Upvotes: 0

Views: 306

Answers (1)

Alex Butler
Alex Butler

Reputation: 316

Here is a direct & null-safe way to tackle this using Java 8 library Dynamics. We're going to parse the json into a Map, read that map dynamically to what we want.

So first we can use Jackson, Gson or something to convert json -> map.

// com.fasterxml.jackson.core:jackson-databind json -> map
Map jsonMap = new ObjectMapper()
    .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
    .readValue(jsonStringOrInputSourceEtc, Map.class);

We can now get a Dynamic instance. And, for example, grab the BTC-A3C - Last value.

Dynamic json = Dynamic.from(jsonMap);

BigDecimal a3cLast = json.get("result").children()
    .filter(data -> data.get("MarketName").asString().equals("BTC-A3C"))
    .findAny()
    .flatMap(data -> data.get("Last").maybe().convert().intoDecimal())
    .orElse(BigDecimal.ZERO); 
// 5E-8

Or perhaps convert the whole lot into a map of MarketName -> Last value

Map<String, BigDecimal> marketNameLastValue = json.get("result").children()
    // assume fields are always present, otherwise see #maybe() methods
    .collect(toMap(
        data -> data.get("MarketName").asString(),
        data -> data.get("Last").convert().intoDecimal()
    )); 
// {BTC-A3C=5E-8, BTC-888=0.00000820}

See more examples https://github.com/alexheretic/dynamics

Upvotes: 0

Related Questions