Conversation
src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializer.java
Outdated
Show resolved
Hide resolved
|
Ah. Thank you for contributing this! One quick note: we'd need unit tests to show how this works; class Javadocs would be useful too, to indicate expectation of using format notation of |
| switch (format.getShape()) { | ||
| case STRING: | ||
| if (format.hasPattern()) { | ||
| return new NumberSerializer(handledType(), new DecimalFormat(format.getPattern())); |
There was a problem hiding this comment.
Probably needs a try-catch block for invalid format (and probably unit test to show handling), re-throw exception (using one of methods from SerializerProvider).
src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializer.java
Outdated
Show resolved
Hide resolved
|
I realized that there is a good reason why I'd like to see tests: I am pretty sure this will not work for most numeric fields :) |
|
|
||
| public void testInvalidPattern() throws Exception { | ||
| ObjectMapper mapper = newJsonMapper(); | ||
| Assert.assertThrows(JsonMappingException.class, () -> { |
There was a problem hiding this comment.
Could you check the exception message too (so it's the expected exception)
|
@hurelhuyag I think we can made this work. I hope you don't mind my pushing couple of changes to streamline things. The next thing, I think, is adding bit more testing -- tests you added look good! -- for other number types; And then I think we need to resolve use of |
| } | ||
| } catch (IllegalArgumentException e) { | ||
| return prov.reportBadDefinition(handledType(), | ||
| String.format("Invalid `DecimalFormat`: \"%s\"", format.getPattern())); |
There was a problem hiding this comment.
| String.format("Invalid `DecimalFormat`: \"%s\"", format.getPattern())); | |
| String.format("Invalid 'DecimalFormat': \"%s\"", format.getPattern())); |
Can we use single quote instead of backtick? I looked around the codebase and in most cases (not all) single quote is used.
| public void testTypeDefaults() throws Exception | ||
| { | ||
| ObjectMapper mapper = newJsonMapper(); | ||
| mapper.configOverride(BigDecimal.class) | ||
| .setFormat(new JsonFormat.Value("00,000.00", JsonFormat.Shape.STRING, (Locale) null, (TimeZone) null, null, null)); | ||
| String json = mapper.writeValueAsString(new NumberWrapper(new BigDecimal("1234"))); | ||
| assertEquals(a2q("{'value':'01,234.00'}"), json); | ||
|
|
||
| // and then read back is not supported yet. | ||
| /*NumberWrapper w = mapper.readValue(a2q("{'value':'01,234.00'}"), NumberWrapper.class); | ||
| assertNotNull(w); | ||
| assertEquals(new BigDecimal("1234"), w.value);*/ | ||
| } | ||
|
|
||
| protected static class InvalidPatternWrapper { | ||
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "#,##0.#.#") | ||
| public BigDecimal value; | ||
|
|
||
| public InvalidPatternWrapper(BigDecimal value) { | ||
| this.value = value; | ||
| } | ||
| } | ||
|
|
||
| public void testInvalidPattern() throws Exception { | ||
| ObjectMapper mapper = newJsonMapper(); | ||
| Assert.assertThrows(JsonMappingException.class, () -> { | ||
| mapper.writeValueAsString(new InvalidPatternWrapper(BigDecimal.ZERO)); | ||
| }); | ||
| } |
There was a problem hiding this comment.
| public void testTypeDefaults() throws Exception | |
| { | |
| ObjectMapper mapper = newJsonMapper(); | |
| mapper.configOverride(BigDecimal.class) | |
| .setFormat(new JsonFormat.Value("00,000.00", JsonFormat.Shape.STRING, (Locale) null, (TimeZone) null, null, null)); | |
| String json = mapper.writeValueAsString(new NumberWrapper(new BigDecimal("1234"))); | |
| assertEquals(a2q("{'value':'01,234.00'}"), json); | |
| // and then read back is not supported yet. | |
| /*NumberWrapper w = mapper.readValue(a2q("{'value':'01,234.00'}"), NumberWrapper.class); | |
| assertNotNull(w); | |
| assertEquals(new BigDecimal("1234"), w.value);*/ | |
| } | |
| protected static class InvalidPatternWrapper { | |
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "#,##0.#.#") | |
| public BigDecimal value; | |
| public InvalidPatternWrapper(BigDecimal value) { | |
| this.value = value; | |
| } | |
| } | |
| public void testInvalidPattern() throws Exception { | |
| ObjectMapper mapper = newJsonMapper(); | |
| Assert.assertThrows(JsonMappingException.class, () -> { | |
| mapper.writeValueAsString(new InvalidPatternWrapper(BigDecimal.ZERO)); | |
| }); | |
| } | |
| protected static class InvalidPatternWrapper { | |
| @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "#,##0.#.#") | |
| public BigDecimal value; | |
| public InvalidPatternWrapper(BigDecimal value) { | |
| this.value = value; | |
| } | |
| } | |
| @Test | |
| public void testTypeDefaults() throws Exception | |
| { | |
| ObjectMapper mapper = newJsonMapper(); | |
| mapper.configOverride(BigDecimal.class) | |
| .setFormat(new JsonFormat.Value("00,000.00", JsonFormat.Shape.STRING, (Locale) null, (TimeZone) null, null, null)); | |
| String json = mapper.writeValueAsString(new NumberWrapper(new BigDecimal("1234"))); | |
| assertEquals(a2q("{'value':'01,234.00'}"), json); | |
| // and then read back is not supported yet. | |
| /*NumberWrapper w = mapper.readValue(a2q("{'value':'01,234.00'}"), NumberWrapper.class); | |
| assertNotNull(w); | |
| assertEquals(new BigDecimal("1234"), w.value);*/ | |
| } | |
| @Test | |
| public void testInvalidPattern() throws Exception { | |
| ObjectMapper mapper = newJsonMapper(); | |
| try { | |
| mapper.writeValueAsString(new InvalidPatternWrapper(BigDecimal.ZERO)); | |
| fail(); | |
| } catch (JsonMappingException e) { | |
| verifyException(e, "expected message part 1/2"); // | |
| verifyException(e, "expected message part 2/2"); | |
| } | |
| } |
Couple of suggestion on test if that's okay with you 🙂
- Let's use JUnit 5, (meaning remove
extends BaseMapTest - Class declaration comes first then test methods (Check suggestion)
- As suggested above, check message by using
try-catchandverifyException(fromDatabindTestUtil) combo
There was a problem hiding this comment.
Above comment seems like Jackson Coding Style convention idea 🤔... WDYT, @cowtowncoder ?
| if (format != null) { | ||
| switch (format.getShape()) { | ||
| case STRING: | ||
| if (format.hasPattern()) { |
There was a problem hiding this comment.
| if (format.hasPattern()) { | |
| // [databind#1114] since 2.17 : Support @JsonFormat for String, numbers, using String.format() | |
| if (format.hasPattern()) { |
| @Override | ||
| public void serialize(Number value, JsonGenerator g, SerializerProvider provider) throws IOException | ||
| { | ||
| if (_format != null) { |
There was a problem hiding this comment.
| if (_format != null) { | |
| // [databind#1114] since 2.17 : Support @JsonFormat for String, numbers, using String.format() | |
| if (_format != null) { |
Why would you think that? Isn't the JDK doc clear? |
I think he's hinting that |
|
Just want to note that current PR covers subset of #1114:
Misc things that we may/may not want to also support:
But I think it's a good start. I do think that using
I'd suggest to only deal with |
Question for core maintainers: where is the doc explaining the kind of
Is the full list kept somewhere else, or they have yet to exist? |
Such a definition does not yet exist. Part of this is the practical challenge of location. For example, while it would be sort of natural from User POV to find the definition in But at the same time, finding definitions from -- say -- individual deserializers' Javadocs would not be useful at all. So I think this should probably be a combination of:
So the first thing would be to decide on (1) I think, and create a skeletal page with some of known cases, general idea behind annotations. |
No, this has nothing to do with Formatter being used, but rather that If you test, for example you will notice that nothing added via |
Fixes #1114.