-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for canonical JSON output in Jackson 2.16 #3967
Closed
Closed
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
7b9cf6a
Support for canonical JSON output in Jackson.
digulla e5ebecb
Extracted setup code into CanonicalJsonMapper plus a few helper classes.
digulla b5b5fee
Merge branch 'FasterXML:2.16' into canonical_json_2_16
digulla c89e22f
Use JsonGenerator decorator to avoid extending JsonFactory. This way,…
digulla 62882cc
Code cleanup
digulla 978afd2
Merge branch 'FasterXML:2.16' into canonical_json_2_16
digulla f2881df
Replaced custom pretty printer with one that uses the new spacing API.
digulla 26b881c
Documentation.
digulla 1690cf7
One TODO fixed, two new ones.
digulla 1e2cd6a
StdSerializer isn't necessary anymore.
digulla e83a68c
Test rounding
digulla File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
43 changes: 43 additions & 0 deletions
43
src/test/java/com/fasterxml/jackson/databind/ser/CanonicalBigDecimalToString.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package com.fasterxml.jackson.databind.ser; | ||
|
||
import java.math.BigDecimal; | ||
|
||
public class CanonicalBigDecimalToString implements ValueToString<BigDecimal> { | ||
|
||
public static final CanonicalBigDecimalToString INSTANCE = new CanonicalBigDecimalToString(); | ||
|
||
@Override | ||
public String convert(BigDecimal value) { | ||
BigDecimal stripped = value.stripTrailingZeros(); | ||
int scale = stripped.scale(); | ||
String text = stripped.toPlainString(); | ||
if (scale == 0) { | ||
return text; | ||
} | ||
|
||
int pos = text.indexOf('.'); | ||
int exp; | ||
if (pos >= 0) { | ||
exp = pos - 1; | ||
|
||
if (exp == 0) { | ||
return text; | ||
} | ||
|
||
text = text.substring(0, pos) + text.substring(pos + 1); | ||
} else { | ||
exp = -scale; | ||
int end = text.length(); | ||
while (end > 0 && text.charAt(end - 1) == '0') { | ||
end --; | ||
} | ||
text = text.substring(0, end); | ||
} | ||
|
||
if (text.length() == 1) { | ||
return text + 'E' + exp; | ||
} | ||
|
||
return text.substring(0, 1) + '.' + text.substring(1) + 'E' + exp; | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
src/test/java/com/fasterxml/jackson/databind/ser/CanonicalBigDecimalToStringTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.fasterxml.jackson.databind.ser; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
import java.math.BigDecimal; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
public class CanonicalBigDecimalToStringTest { | ||
|
||
@Test | ||
void testCanonicalDecimalHandling_1() throws Exception { | ||
assertSerialized("1", new BigDecimal("1")); | ||
} | ||
|
||
@Test | ||
void testCanonicalDecimalHandling_1_000() throws Exception { | ||
assertSerialized("1", new BigDecimal("1.000")); | ||
} | ||
|
||
@Test | ||
void testCanonicalDecimalHandling_10_1000() throws Exception { | ||
assertSerialized("1.01E1", new BigDecimal("10.1000")); | ||
} | ||
|
||
@Test | ||
void testCanonicalDecimalHandling_1000() throws Exception { | ||
assertSerialized("1E3", new BigDecimal("1000")); | ||
} | ||
|
||
@Test | ||
void testCanonicalDecimalHandling_0_00000000010() throws Exception { | ||
assertSerialized("0.0000000001", new BigDecimal("0.00000000010")); | ||
} | ||
|
||
@Test | ||
void testCanonicalDecimalHandling_1000_00010() throws Exception { | ||
assertSerialized("1.0000001E3", new BigDecimal("1000.00010")); | ||
} | ||
|
||
@Test | ||
void testCanonicalHugeDecimalHandling() throws Exception { | ||
BigDecimal actual = new BigDecimal("123456789123456789123456789123456789.123456789123456789123456789123456789123456789000"); | ||
assertSerialized("1.23456789123456789123456789123456789123456789123456789123456789123456789123456789E35", actual); | ||
} | ||
|
||
private void assertSerialized(String expected, BigDecimal actual) { | ||
CanonicalBigDecimalToString serializer = new CanonicalBigDecimalToString(); | ||
assertEquals(expected, serializer.convert(actual)); | ||
} | ||
|
||
} |
21 changes: 21 additions & 0 deletions
21
src/test/java/com/fasterxml/jackson/databind/ser/CanonicalJsonGeneratorDecorator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.fasterxml.jackson.databind.ser; | ||
|
||
import java.math.BigDecimal; | ||
|
||
import com.fasterxml.jackson.core.JsonFactory; | ||
import com.fasterxml.jackson.core.JsonGenerator; | ||
import com.fasterxml.jackson.core.JsonGeneratorDecorator; | ||
|
||
public class CanonicalJsonGeneratorDecorator implements JsonGeneratorDecorator { | ||
|
||
private ValueToString<BigDecimal> _serializer; | ||
|
||
public CanonicalJsonGeneratorDecorator(ValueToString<BigDecimal> serializer) { | ||
this._serializer = serializer; | ||
} | ||
|
||
@Override | ||
public JsonGenerator decorate(JsonFactory factory, JsonGenerator generator) { | ||
return new CanonicalNumberGenerator(generator, _serializer); | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
src/test/java/com/fasterxml/jackson/databind/ser/CanonicalJsonMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package com.fasterxml.jackson.databind.ser; | ||
|
||
import java.math.BigDecimal; | ||
|
||
import com.fasterxml.jackson.core.JsonFactory; | ||
import com.fasterxml.jackson.core.JsonGeneratorDecorator; | ||
import com.fasterxml.jackson.core.PrettyPrinter; | ||
import com.fasterxml.jackson.core.StreamWriteFeature; | ||
import com.fasterxml.jackson.core.util.DefaultIndenter; | ||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; | ||
import com.fasterxml.jackson.core.util.Separators; | ||
import com.fasterxml.jackson.core.util.Separators.Spacing; | ||
import com.fasterxml.jackson.databind.MapperFeature; | ||
import com.fasterxml.jackson.databind.SerializationFeature; | ||
import com.fasterxml.jackson.databind.cfg.JsonNodeFeature; | ||
import com.fasterxml.jackson.databind.json.JsonMapper; | ||
|
||
public class CanonicalJsonMapper { | ||
public static final DefaultIndenter CANONICAL_INDENTEER = new DefaultIndenter(" ", "\n"); | ||
|
||
public static final PrettyPrinter CANONICAL_PRETTY_PRINTER = new DefaultPrettyPrinter() | ||
.withObjectIndenter(CANONICAL_INDENTEER) | ||
.withSeparators(Separators.createDefaultInstance().withObjectFieldValueSpacing(Spacing.AFTER)); | ||
|
||
public static class Builder { | ||
private ValueToString<BigDecimal> _numberToString = CanonicalBigDecimalToString.INSTANCE; | ||
private boolean _enablePrettyPrinting = false; | ||
|
||
private Builder() { | ||
// Don't allow to create except via builder method | ||
} | ||
|
||
public Builder prettyPrint() { | ||
_enablePrettyPrinting = true; | ||
_numberToString = PrettyBigDecimalToString.INSTANCE; | ||
return this; | ||
} | ||
|
||
public JsonMapper build() { | ||
JsonGeneratorDecorator decorator = new CanonicalJsonGeneratorDecorator(_numberToString); | ||
|
||
JsonFactory factory = JsonFactory.builder() // | ||
.decorateWith(decorator) | ||
.build(); | ||
JsonMapper.Builder builder = JsonMapper.builder(factory) // | ||
.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS) // | ||
.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY) // | ||
.enable(JsonNodeFeature.WRITE_PROPERTIES_SORTED); // | ||
|
||
if (_enablePrettyPrinting) { | ||
builder = builder // | ||
.enable(SerializationFeature.INDENT_OUTPUT) // | ||
.enable(StreamWriteFeature.WRITE_BIGDECIMAL_AS_PLAIN) // | ||
.defaultPrettyPrinter(CANONICAL_PRETTY_PRINTER) // | ||
; | ||
} | ||
|
||
return builder.build(); | ||
} | ||
} | ||
|
||
public static CanonicalJsonMapper.Builder builder() { | ||
return new Builder(); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should probably be put under new package (not sure if
databind.canonical
ordatabind.ser.canonical
).I realize all code is under
src/test
and not necessarily meant to be in specific location.