-
Notifications
You must be signed in to change notification settings - Fork 23
Add configurable amount representations for Joda Money module #17
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
Add configurable amount representations for Joda Money module #17
Conversation
joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/ModuleTestBase.java
Show resolved
Hide resolved
|
||
public interface AmountRepresenter<T> { | ||
|
||
T write(Money money); |
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.
Either name is sub-optimal (nothing gets written), or (more likely I think) this should do actual writing via JsonGenerator
directly. If former, I think this is something like AmountConverter
, and methods could be something like fromMoney()
and toMoney()
.
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.
yeah, I struggled with the name so it's definitely sub-optimal. your proposal is great, I will use it, thanks
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.
Sounds good!
g.writeNumberField("amount", decimal.setScale(scale, RoundingMode.UNNECESSARY)); | ||
g.writeFieldName("currency"); | ||
context.defaultSerializeValue(money.getCurrencyUnit(), g); | ||
g.writeObjectField("amount", amountRepresenter.write(money)); |
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.
But doesn't this always chnge value from JSON Number into JSON String? And be essentially backwards-incompatible change?
This is why I think instead of write()
conversion method it should be method that does write.
So, first g.writeFieldName("amount")
, then value write by helper object.
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.
it isn't output as JSON string. it goes like this:
BigDecimal
is serialized usingNumberSerializer
(which doesJsonGenerator.writeNumber(BigDecimal)
just as we would do directly),String
is serialized usingStringSerializer
,Long
- usingNumberSerializers.LongSerializer
.
this seems to be confirmed by both manual tests and automatic tests in MoneySerializerTest.java
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.
Ah. I did miss the paramaterization, yes, Long
and BigDecimal
will then be written using configured serializer which is fine.
First of all: thank you for contributing this patch! I haven't as much time to spend on things as I'd like, but I hope to provide some feedback. I think the goals make sense, and I appreciate care taken. I did have some concerns (which may be due to my misreading?), added comments. One practical thing is that due to changes to API, this would need to go in 2.14. I haven't yet created a branch for it, though, so for time being Another thing is that more commonly formatting aspects would be handled via
The main benefits would be that everything (?) would be configurable by type and/or property; you can annotate properties explicitly, or indicate default for given type. So this would be something to consider if you have time. I can try to help fill in blanks on usage; there isn't much tutorial on how to do these unfortunately. |
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.
thank you for the pointers, I've answered the comments and pushed an update 🙂
regarding:
more commonly formatting aspects would be handled via @jsonformat annotation (esp. its shape), but I realize it may not be extensible enough here. It would allow differentiating between Number and String representation. It might work, since we do have:
- Shape.STRING
- Shape.NUMBER_FLOAT
- Shape.NUMBER_INT (for "minor")
- Shape.NUMBER would be ambiguous; I assume that'd be same as (2)
The main benefits would be that everything (?) would be configurable by type and/or property; you can annotate properties explicitly, or indicate default for given type.
I actually wanted to approach something similar in a follow-up PR (to keep them smaller), but I can do it in this one if you prefer.
what I wasn't sure was if it will be natural for users (or: won't they be surprised) that a Money
field is always serialized as JSON object, but @JsonFormat(shape = )
on such field controls not serialization of the field itself, but just the "amount" field inside of it. (I guess we could just document it of course.)
second thing I was considering was a dedicated annotation, something like:
@JsonMoney(amountRepresentation = MINOR_CURRENCY_UNIT)
Money grandTotal;
but I'm not sure if reading such custom annotation is feasible in (de)serializers, won't break something (e.g. caching of (de)serializers), etc.
what do you think is the way to go in Jackson's world? 🙂
|
||
public interface AmountRepresenter<T> { | ||
|
||
T write(Money money); |
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.
yeah, I struggled with the name so it's definitely sub-optimal. your proposal is great, I will use it, thanks
g.writeNumberField("amount", decimal.setScale(scale, RoundingMode.UNNECESSARY)); | ||
g.writeFieldName("currency"); | ||
context.defaultSerializeValue(money.getCurrencyUnit(), g); | ||
g.writeObjectField("amount", amountRepresenter.write(money)); |
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.
it isn't output as JSON string. it goes like this:
BigDecimal
is serialized usingNumberSerializer
(which doesJsonGenerator.writeNumber(BigDecimal)
just as we would do directly),String
is serialized usingStringSerializer
,Long
- usingNumberSerializers.LongSerializer
.
this seems to be confirmed by both manual tests and automatic tests in MoneySerializerTest.java
hey @cowtowncoder, friendly ping 🙂 would be great if you could state what you prefer as outlined in this comment. then I could align this PR with whatever we agree 🙂 |
Yeah sorry have had bit of burnout wrt OSS work so feedback has been slow. But I do want to help here as this looks like a good improvement. So: on On getting this merged: with 2.13.0 this needs to go in 2.14; I haven't yet created 2.14 branches but hope to do that soon. I'll add this on my TODO list and try to remember update once I get 2.14 branch set up for |
no worries @cowtowncoder, I get it 🙂 let's wait for 2.14 and do let me know if you spot anything that I should change 👍 |
2.14 branches exists for all repos now. |
…ney module to module's README
b7c562a
to
d789f73
Compare
@cowtowncoder roger, rebased on top of 2.14, verified all tests pass and updated PR 👍 |
Ok still being slow -- this is on top of my review list, hoping to get it merged this week. |
@apankowski Apologies for yet more delays, but I'm back. I think things are good; only had couple of suggestions / questions:
These are fully optional; just LMK what you think and I can merge things as-is or if you want to add/change something let me know when things are ready. Actually -- after thinking about this bit more, no, maybe NOT exposing AmountConverters initially is better. It also reduces need to describe implementations: so just adding Javadocs to enum values would be sufficient. |
joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/AmountRepresentation.java
Show resolved
Hide resolved
joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MoneyDeserializer.java
Outdated
Show resolved
Hide resolved
joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MoneySerializer.java
Outdated
Show resolved
Hide resolved
joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/AmountConverter.java
Outdated
Show resolved
Hide resolved
@cowtowncoder no worries - thank you for the feedback 🙂 Will apply all agreed changes and let you know soon. I could use some guidance with visibility of the
I can't decide how much we'd like to make public at first and could use your experience here |
Good questions! Since we do not really expose any way to use them except via enums, my slight preference would be for (3). That leaves us freedom to change things more should there be need for more customizations, in ways that we haven't anticipated. |
…kward compatibility
…of amount representation enum
@cowtowncoder PR updated and ready for next round of feedback 🙂 Summary of changes:
|
Looks good! I'll try to add some |
Thank you again @apankowski ! |
This PR adds the possibility to configure desired representation of (de)serialized
Money
instances to the Joda Money Jackson module.It allows selection of one of 3 representations via the
JodaMoneyModule.withAmountRepresentation(AmountRepresentation)
method:DECIMAL_NUMBER
- the default; amounts are (de)serialized as decimal numbers equal to the monetary amount, e.g.12.34
for EUR 12.34,DECIMAL_STRING
- amounts are (de)serialized as strings containing decimal number equal to the monetary amount, e.g."12.34"
for EUR 12.34,MINOR_CURRENCY_UNIT
- amounts are (de)serialized as long integers equal to the monetary amount expressed in minor currency unit, e.g.1234
for EUR 12.34,12345
for KWD 12.345 or12
for JPY 12.The motivation for having such feature is that:
Noteworthy points:
2.13
(since it was the default) and made changes to code on that branch - not sure if that's correct.Objects.requireNonNull
and lambdas.I will be helpful for pointers, suggestions and remarks and will try to align with all of them 🙂