feat: add PrettyFormatInlineArrays option to keep arrays on single line #2972#3930
feat: add PrettyFormatInlineArrays option to keep arrays on single line #2972#3930coffeeandwork wants to merge 3 commits intoalibaba:mainfrom
Conversation
|
|
99c9610 to
150f8e4
Compare
|
I have signed the CLA. Not sure why its still showing as not signed yet. @wenshao help, what am i doing wrong? |
|
Hi @coffeeandwork , However, we are currently facing a tricky architectural limitation. In order to pursue ultimate performance, Fastjson2 uses a long (64-bit) to store all JSONWriter.Feature values. Currently, the available bits for this long are already very tight (only a dozen left). Considering future scalability, we need to reserve these remaining bits for features that are practical, related to functional correctness, security, or core performance. Since PrettyFormatInlineArrays is primarily a formatting beautification feature, which is more of an "addition to excellence", we are hesitant to consume a permanent Feature bit. |
Hi @jujn, Thank you for the detailed feedback! Your concern about preserving the limited Feature bits makes complete sense. I've updated the PR to address this. The latest commit removes PrettyFormatInlineArrays from the Feature enum and instead uses Context configuration, following the same pattern as other non-Feature options like setDateFormat(), setZoneId(), and setMaxLevel(). The new API: // Per-call configuration
JSONWriter.Context context = new JSONWriter.Context(JSONWriter.Feature.PrettyFormat);
context.setPrettyFormatInlineArrays(true);
String json = JSON.toJSONString(obj, context);
// Or set global default
JSONFactory.setDefaultWriterPrettyFormatInlineArrays(true);This approach preserves all existing Feature bits while still providing the functionality. Let me know if you'd like any further changes! |
|
Thank you for your quick modification. |
Hi @jujn, Here are specific scenarios where inline array formatting provides significant value: 1. Primitive/Simple Value ArraysArrays of IDs, numbers, or simple values become excessively verbose when expanded: Without inline arrays (15 lines): {
"type": 1001,
"job_id": [
0,
45732
],
"user_ids": [
1297059520,
4117498193,
8291829301
],
"is_active": true
}With inline arrays (6 lines): {
"type": 1001,
"job_id": [0,45732],
"user_ids": [1297059520,4117498193,8291829301],
"is_active": true
}
GeoJSON is a widely-used standard for geographic data. Coordinates are conventionally written inline - expanded format makes it nearly impossible to visualize the shape: Without inline arrays (25 lines for a simple polygon): {
"type": "Polygon",
"coordinates": [
[
[
100.0,
0.0
],
[
101.0,
0.0
],
[
101.0,
1.0
],
[
100.0,
0.0
]
]
]
}With inline arrays (8 lines): {
"type": "Polygon",
"coordinates": [
[[100.0,0.0],[101.0,0.0],[101.0,1.0],[100.0,0.0]]
]
}
Scientific computing, game development, and data processing often use matrices. Inline arrays preserve the visual structure: Without inline arrays (38 lines for a 3x3 matrix): {
"name": "rotation_matrix",
"data": [
[
1,
0,
0
],
[
0,
0.866,
-0.5
],
[
0,
0.5,
0.866
]
]
}With inline arrays (7 lines): {
"name": "rotation_matrix",
"data": [
[1,0,0],
[0,0.866,-0.5],
[0,0.5,0.866]
]
}
When config files are stored in git, inline arrays produce cleaner diffs: Expanded format diff (adding one port): "allowed_ports": [
8080,
8443,
+ 9000
]Shows 4 lines changed, harder to review in large configs. Inline format diff:
When logging JSON for debugging, inline arrays make logs scannable: Expanded (requires scrolling, loses context): 2024-01-15 10:23:45 DEBUG Response:
{
"status": "success",
"error_codes": [
0,
0,
0
],
"processed_ids": [
101,
102,
103,
104,
105
]
}
2024-01-15 10:23:46 DEBUG Next request...Inline (compact, preserves log context): 2024-01-15 10:23:45 DEBUG Response:
{
"status": "success",
"error_codes": [0,0,0],
"processed_ids": [101,102,103,104,105]
}
2024-01-15 10:23:46 DEBUG Next request...
Test data and API documentation examples are more maintainable: Without inline arrays (test file becomes hundreds of lines): {
"test_input": {
"rgb_color": [
255,
128,
0
],
"position": [
10.5,
20.3,
5.0
],
"tags": [
"active",
"premium",
"verified"
]
}
}With inline arrays (concise, easy to maintain): {
"test_input": {
"rgb_color": [255,128,0],
"position": [10.5,20.3,5.0],
"tags": ["active","premium","verified"]
}
}The common thread across all these scenarios is that arrays often represent atomic data units (a coordinate pair, a color, a row of values) that are more meaningful when kept together, while objects represent structured entities that benefit from expanded formatting. I understand the desire to keep fastjson2 lean. If you feel these use cases aren't common enough to warrant inclusion, I respect that decision. |
|
This will cause problems if the array length is too large. |
Yeah that's a fair point. Though in practice, I think it's less of an issue than it might seem - the use cases where you'd want inline arrays (coordinates, RGB values, matrix rows, small ID lists) tend to be small arrays anyway. Anyone working with huge arrays probably wouldn't enable this option. Also worth noting that without pretty printing, arrays already end up on a single line regardless of size - so this isn't introducing new behavior, just giving users a middle ground between fully expanded and fully compact. That said, if you think it's important, I could add a max length threshold where arrays beyond N elements fall back to the expanded format. Let me know if you'd want that for the initial implementation or if it's fine as-is. |
|
For primitive type arrays with a length less than 5, it might be better to put them on a single line by default. |
I can implement this if this is truly what we want. Are you sure we want to change the default behavior in this way? Wouldn't it impact projects that rely on it? Please advise. |
Fixes alibaba#2972 Added new JSONWriter.Feature.PrettyFormatInlineArrays that, when used with PrettyFormat, keeps array elements on a single line instead of expanding each element to its own line. This matches the original fastjson behavior. Changes: - Added PrettyFormatInlineArrays feature flag (bit 46) - Added levelArray bitmask to track array vs object context at each level - Modified startArray/endArray/writeComma in JSONWriterUTF8 and JSONWriterUTF16 - Added comprehensive tests for edge cases
…ead of Feature bit Address review feedback about limited bits in 64-bit Feature bitmask. Move inline arrays configuration from JSONWriter.Feature enum to JSONWriter.Context, following the pattern used by other non-Feature configuration like dateFormat, zoneId, and maxLevel. API changes: - Remove PrettyFormatInlineArrays from JSONWriter.Feature enum - Add Context.setPrettyFormatInlineArrays(boolean) for per-call config - Add JSONFactory.setDefaultWriterPrettyFormatInlineArrays(boolean) for global default The implementation uses a levelArray bitmask to track array vs object context at each nesting level, enabling proper indentation behavior where objects remain pretty-printed while arrays stay inline.
c4ab04d to
2f807d5
Compare
Short primitive arrays (int[], byte[], short[], long[], float[], double[], boolean[]) with fewer than 5 elements now render on a single line when pretty-printing, improving readability for common cases like coordinates [1, 2, 3]. Arrays with 5+ elements use proper multi-line formatting.
|
Short primitive arrays (< 5 elements) now render inline in pretty-print mode by default. Arrays with 5+ elements use multi-line formatting. The existing Benchmarks (JDK 22, Apple M4 Max, 1 fork, 3 warmup / 5 measurement iterations):
Differences are within error margins. No measurable impact on the non-pretty hot path. |
What this PR does / why we need it?
Fixes #2972
Added a new Context configuration option that, when used with PrettyFormat, keeps array elements on a single line instead of expanding each element to its own line. This matches the original fastjson behavior.
Summary of your change
Context.setPrettyFormatInlineArrays(boolean)for per-call configurationJSONFactory.setDefaultWriterPrettyFormatInlineArrays(boolean)for global defaultlevelArraybitmask to track array vs object context at each levelstartArray/endArray/writeCommain JSONWriterUTF8 and JSONWriterUTF16Usage
Example output
Uses Context configuration instead of a Feature bit to conserve the limited bits in the 64-bit Feature bitmask.
Please indicate you've done the following: