[JAVA-3085] Make whitespace in JSON output more consistent with other libraries Created: 09/Nov/18  Updated: 28/Oct/23  Resolved: 07/Jan/19

Status: Closed
Project: Java Driver
Component/s: JSON
Affects Version/s: None
Fix Version/s: 3.10.0

Type: Improvement Priority: Minor - P4
Reporter: Nick [X] Assignee: Jeffrey Yemin
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Backwards Compatibility: Fully Compatible

 Description   

Updated

Rather than add more configuration, we plan to alter the whitespace in the JSON output to be more consistent with other libraries. In particular:

  1. Omit space before ":"
  2. Omit space after "{" and before "}"
  3. Add newline/indent after each array element when indent is enabled

Original

I have been using BSON for a while now for the simple fact that it is easy to get either simple plain text or a small binary format which comes in handy when you need to have both human readable/editable configs and small on disk files or over network transfers.

However when writing out formatted JSON it is useful to be able to replicate formats used by other libraries to prevent excess changes caused purely by formatting due to something like the JSON being exported from a different library/tool.

I have put some examples of JSON output from a couple of the popular libraries I could think of at the end of the description.

 

My proposal is that a couple of very basic settings are added to allow for some flexibility when it comes to the format of the JSON output by StrictCharacterStreamJsonWriter.

I have the code changes done in a fork of the repo and is ready for pull request which I will submit after this ticket.

The changes are fully backwards compatible and do not change the default behaviour from the current.

 

Example JSON outputs:

Library Code Output
JavaScript,
NodeJS,
ECMAScript [1]
 

let doc = {
  "arr": [
    { "a": 1, "b": 2 },
    { "c": 3, "d": 4 }
  ]
};
JSON.stringify(doc, null, 2)

 

{
  "arr": [
    {
      "a": 1,
      "b": 2
    },
    {
      "c": 3,
      "d": 4
    }
  ]
}

serde_json (Rust) [2]  

let doc = json!({
  "arr": [
    { "a": 1, "b": 2 }, 
    { "c": 3, "d": 4 }
  ]
});
serde_json::to_string_pretty(&doc)

 

 

{
  "arr": [
    {
      "a": 1,
      "b": 2
    },
    {
      "c": 3,
      "d": 4
    }
  ]
}

 

Gson

JsonObject obj1 = new JsonObject();
obj1.addProperty("a", 1);
obj1.addProperty("b", 2);
 
JsonObject obj2 = new JsonObject();
obj2.addProperty("c", 3);
obj2.addProperty("d", 4);
 
JsonArray arr = new JsonArray();
arr.add(obj1);
arr.add(obj2);
 
JsonObject doc = new JsonObject();
doc.add("arr", arr);
 
Gson gson = new GsonBuilder()
    .setPrettyPrinting()
    .create();
String str = gson.toJson(doc);

{
  "arr": [
    {
      "a": 1,
      "b": 2
    },
    {
      "c": 3,
      "d": 4
    }
  ]
}

org.bson.json

BsonArray arr = new BsonArray();
arr.add(new BsonDocument()
    .append("a", new BsonInt32(1))
    .append("b", new BsonInt32(2)));
arr.add(new BsonDocument()
    .append("c", new BsonInt32(3))
    .append("d", new BsonInt32(4)));
BsonDocument doc = new BsonDocument()
    .append("arr", arr);
var settings = JsonWriterSettings.builder()
    .indent(true).build();
String str = doc.toJson(settings);

{
  "arr" : [{
      "a" : 1,
      "b" : 2
    }, {
      "c" : 3,
      "d" : 4
    }]
}

 

[1] https://jsfiddle.net/4cjd2eqx/
[2] https://play.rust-lang.org/?gist=5a05fffd61b372c906f40db3ef3859a0 

 



 Comments   
Comment by Githook User [ 14/Jan/19 ]

Author:

{'username': 'jyemin', 'email': 'jeff.yemin@10gen.com', 'name': 'Jeff Yemin'}

Message: Change JSON whitespace generation

To be more consistent with other popular JSON generation libraries:

1. Omit space before ":"
2. Omit space after "

{" and before "}

"
3. Add newline/indent after each array element

JAVA-3085
Branch: 3.10.x
https://github.com/mongodb/mongo-java-driver/commit/8f1fdc239b3962f60b2e8d12fa0db985aa611709

Comment by Githook User [ 07/Jan/19 ]

Author:

{'username': 'jyemin', 'email': 'jeff.yemin@10gen.com', 'name': 'Jeff Yemin'}

Message: Change JSON whitespace generation

To be more consistent with other popular JSON generation libraries:

1. Omit space before ":"
2. Omit space after "

{" and before "}

"
3. Add newline/indent after each array element

JAVA-3085
Branch: master
https://github.com/mongodb/mongo-java-driver/commit/ab667fd32c0bb6eae6bfd33020230e03f6d568dd

Comment by Nick [X] [ 31/Dec/18 ]

The only reason I added the config was to be as unobtrusive as possible to existing usages but if we are ok with changing the default behaviour that is also fine with me. 

The only thing I would ask that both of the misc parts of the PR are also carried over with the changes you made, primarily removing the varargs to prevent any possible wasted Object array allocations.

Comment by Jeffrey Yemin [ 31/Dec/18 ]

I have a patch with the following changes:

  1. Omit space before ":"
  2. Omit space after "{" and before "}"
  3. Add newline/indent after each array element when indent is enabled

ZeroErrors let me know whether it suits you, or whether you think additional configuration (or just not changing the current behavior by default) is important for you.

 

Comment by Jeffrey Yemin [ 28/Dec/18 ]

Let's consider just changing the behavior of the indent property to match these other libraries. The Javadoc of the indent property isn't very specific about exactly what indent does, so we have some license to just change it in a minor release and not consider it backwards breaking. The current behavior is arguably unfriendly for large scalar arrays, e.g.

{
   "a" : [1, 2, 3, 4, 5, 6, ... 10000]
}

all the scalar elements of the array will appear on the same line, instead of one per line as with these other libraries.

Comment by Jeffrey Yemin [ 09/Nov/18 ]

Thanks for the ticket and the pull request.  Adding a link to it here: https://github.com/mongodb/mongo-java-driver/pull/497

Generated at Thu Feb 08 08:58:44 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.