Search code examples
javajsonrest-assuredweb-api-testingorg.json

Java: org.json.JSONObject - creating a new instance removes trailing zeros from big decimals


Take for example this short JSON taken as a String from an API response using RestAssured:

{
    "id": "4d27afb18bfa4eb5917beee9aaddfa76",
    "hedgeId": 205598,
    "sellCurrency": "USD",
    "buyCurrency": "EUR",
    "buyAmount": 473935.00,
    "sellAmount": 585538.30,
}

Whenever I do JSONObject foo = new JSONObject(thatStringAbove);, this instance is created:

{
  "hedgeId": 205598,
  "buyAmount": 473935,
  "sellAmount": 585538.3,
  "id": "4d27afb18bfa4eb5917beee9aaddfa76",
  "sellCurrency": "USD",
  "buyCurrency": "EUR"
}

Notice the trailing zeros from amount nodes are stripped. This looks like a bug to me but does anyone know of a workaround / solution how to prevent this from happening?

Few notes:

  • I'd like to solve this using same library (org.json)
  • If at all possible, I'd like to construct the instance from a string like how I'm doing it currently

    Maven dependency:

            <dependency>
                <groupId>org.json</groupId>
                <artifactId>json</artifactId>
                <version>20170516</version>
            </dependency>
    

    Appreciate the help!


  • Solution

  • You won't be able to do this with the org.json library. It deliberately strips trailing zeros during serialisation.

    From the relevant method JSONObject.numberToString():

    public static String numberToString(Number number) throws JSONException {
        if (number == null) {
            throw new JSONException("Null pointer");
        }
        testValidity(number);
    
        // Shave off trailing zeros and decimal point, if possible.
    
        String string = number.toString();
        if (string.indexOf('.') > 0 && string.indexOf('e') < 0
                && string.indexOf('E') < 0) {
            while (string.endsWith("0")) {
                string = string.substring(0, string.length() - 1);
            }
            if (string.endsWith(".")) {
                string = string.substring(0, string.length() - 1);
            }
        }
        return string;
    }
    

    I'd suggest using a more customisable library like jackson or gson.

    Gson will respect the scale on the number, allowing you to perform your round trip without losing trailing zeros:

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    JsonObject jsonObject = gson.fromJson(in, JsonObject.class);
    System.out.println(gson.toJson(jsonObject));
    

    Output:

    {
        "id": "4d27afb18bfa4eb5917beee9aaddfa76",
        "hedgeId": 205598,
        "sellCurrency": "USD",
        "buyCurrency": "EUR",
        "buyAmount": 473935.00,
        "sellAmount": 585538.30
    }
    

    It will also do mapping to Objects if you desire.