Skip to content

Commit a187cec

Browse files
Move jackson-datatype-money module from zalando
1 parent 8dd3087 commit a187cec

29 files changed

+1854
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ datatype modules to support 3rd party libraries.
66
Currently included are:
77

88
* [jackson-datatype-joda-money](joda-money/) for [Joda-Money](https://www.joda.org/joda-money/) datatypes
9+
* [jackson-datatype-money](javax-money/) for [JavaMoney](https://javamoney.github.io/) datatypes (starting with Jackson 2.19)
910
* JSR-353/JSON-P: 2 variants (starting with Jackson 2.12.2)
1011
* [jackson-datatype-jsr353](jsr-353/) for older "javax.json" [JSR-353](https://www.jcp.org/en/jsr/detail?id=353) (aka JSON-P) datatypes (package `javax.json`)
1112
* [jackson-datatype-jakarta-jsonp](jakarta-jsonp/) for newer "Jakarta" JSON-P datatypes (package `jakarta.json`)
@@ -16,6 +17,7 @@ Currently included are:
1617
Note that this repo was created for Jackson 2.11: prior to this, individual datatype
1718
modules had their own repositories.
1819

20+
1921
## License
2022

2123
All modules are licensed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt).
@@ -62,6 +64,7 @@ mapper.registerModule(new JSONPModule()); // new (jakarta) json-P API
6264
ObjectMapper mapper = JsonMapper.builder()
6365
.addModule(new JsonOrgModule())
6466
.addModule(new JodaMoneyModule())
67+
.addModule(new MoneyModule())
6568
// ONE of these (not both):
6669
.addModule(new JSR353Module()) // old (javax) json-p API
6770
.addModule(new JSONPModule()) // new (jakarta) json-P API

javax-money/README.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
# Jackson Datatype Money
2+
3+
*Jackson Datatype Money* is a [Jackson](https://github.com/codehaus/jackson) module to support JSON serialization and
4+
deserialization of [JavaMoney](https://github.com/JavaMoney/jsr354-api) data types. It fills a niche, in that it
5+
integrates JavaMoney and Jackson so that they work seamlessly together, without requiring additional
6+
developer effort. In doing so, it aims to perform a small but repetitive task — once and for all.
7+
8+
With this library, it is possible to represent monetary amounts in JSON as follows:
9+
10+
```json
11+
{
12+
"amount": 29.95,
13+
"currency": "EUR"
14+
}
15+
```
16+
17+
## Features
18+
19+
- enables you to express monetary amounts in JSON
20+
- can be used in a REST APIs
21+
- customized field names
22+
- localization of formatted monetary amounts
23+
- allows you to implement RESTful API endpoints that format monetary amounts based on the Accept-Language header
24+
- is unique and flexible
25+
26+
## Dependencies
27+
28+
- Java 8 or higher
29+
- Any build tool using Maven Central, or direct download
30+
- Jackson
31+
- JavaMoney
32+
33+
## Installation
34+
35+
Add the following dependency to your project:
36+
37+
```xml
38+
39+
<dependency>
40+
<groupId>com.fasterxml.jackson.datatype</groupId>
41+
<artifactId>jackson-datatype-money</artifactId>
42+
<version>${jackson-datatype-money.version}</version>
43+
</dependency>
44+
```
45+
46+
For ultimate flexibility, this module is compatible with the official version as well as the backport of JavaMoney. The
47+
actual version will be selected by a profile based on the current JDK version.
48+
49+
## Configuration
50+
51+
Register the module with your `ObjectMapper`:
52+
53+
```java
54+
ObjectMapper mapper = new ObjectMapper()
55+
.registerModule(new MoneyModule());
56+
```
57+
58+
Alternatively, you can use the SPI capabilities:
59+
60+
```java
61+
ObjectMapper mapper = new ObjectMapper()
62+
.findAndRegisterModules();
63+
```
64+
65+
### Serialization
66+
67+
For serialization this module currently supports
68+
[
69+
`javax.money.MonetaryAmount`](https://github.com/JavaMoney/jsr354-api/blob/master/src/main/java/javax/money/MonetaryAmount.java)
70+
and will, by default, serialize it as:
71+
72+
```json
73+
{
74+
"amount": 99.95,
75+
"currency": "EUR"
76+
}
77+
```
78+
79+
To serialize number as a JSON string, you have to configure the quoted decimal number value serializer:
80+
81+
```java
82+
ObjectMapper mapper = new ObjectMapper()
83+
.registerModule(new MoneyModule().withQuotedDecimalNumbers());
84+
```
85+
86+
```json
87+
{
88+
"amount": "99.95",
89+
"currency": "EUR"
90+
}
91+
```
92+
93+
### Formatting
94+
95+
A special feature for serializing monetary amounts is *formatting*, which is **disabled by default**. To enable it, you
96+
have to either enable default formatting:
97+
98+
```java
99+
ObjectMapper mapper = new ObjectMapper()
100+
.registerModule(new MoneyModule().withDefaultFormatting());
101+
```
102+
103+
... or pass in a `MonetaryAmountFormatFactory` implementation to the `MoneyModule`:
104+
105+
```java
106+
ObjectMapper mapper = new ObjectMapper()
107+
.registerModule(new MoneyModule()
108+
.withFormatting(new CustomMonetaryAmountFormatFactory()));
109+
```
110+
111+
The default formatting delegates directly to `MonetaryFormats.getAmountFormat(Locale, String...)`.
112+
113+
Formatting only affects the serialization and can be customized based on the *current* locale, as defined by the
114+
[
115+
`SerializationConfig`](https://fasterxml.github.io/jackson-databind/javadoc/2.0.0/com/fasterxml/jackson/databind/SerializationConfig.html#with\(java.util.Locale\)).
116+
This allows to implement RESTful API endpoints
117+
that format monetary amounts based on the `Accept-Language` header.
118+
119+
The first example serializes a monetary amount using the `de_DE` locale:
120+
121+
```java
122+
ObjectWriter writer = mapper.writer().with(Locale.GERMANY);
123+
writer.
124+
125+
writeValueAsString(Money.of(29.95, "EUR"));
126+
```
127+
128+
```json
129+
{
130+
"amount": 29.95,
131+
"currency": "EUR",
132+
"formatted": "29,95 EUR"
133+
}
134+
```
135+
136+
The following example uses `en_US`:
137+
138+
```java
139+
ObjectWriter writer = mapper.writer().with(Locale.US);
140+
writer.
141+
142+
writeValueAsString(Money.of(29.95, "USD"));
143+
```
144+
145+
```json
146+
{
147+
"amount": 29.95,
148+
"currency": "USD",
149+
"formatted": "USD29.95"
150+
}
151+
```
152+
153+
More sophisticated formatting rules can be supported by implementing `MonetaryAmountFormatFactory` directly.
154+
155+
### Deserialization
156+
157+
This module will use `org.javamoney.moneta.Money` as an implementation for `javax.money.MonetaryAmount` by default when
158+
deserializing money values. If you need a different implementation, you can pass a different `MonetaryAmountFactory`
159+
to the `MoneyModule`:
160+
161+
```java
162+
ObjectMapper mapper = new ObjectMapper()
163+
.registerModule(new MoneyModule()
164+
.withMonetaryAmount(new CustomMonetaryAmountFactory()));
165+
```
166+
167+
You can also pass in a method reference:
168+
169+
```java
170+
ObjectMapper mapper = new ObjectMapper()
171+
.registerModule(new MoneyModule()
172+
.withMonetaryAmount(FastMoney::of));
173+
```
174+
175+
*Jackson Datatype Money* comes with support for all `MonetaryAmount` implementations from Moneta, the reference
176+
implementation of JavaMoney:
177+
178+
| `MonetaryAmount` Implementation | Factory |
179+
|-------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
180+
| `org.javamoney.moneta.FastMoney` | [`new MoneyModule().withFastMoney()`](src/main/java/com/fasterxml/jackson/datatype/money/FastMoneyFactory.java) |
181+
| `org.javamoney.moneta.Money` | [`new MoneyModule().withMoney()`](src/main/java/com/fasterxml/jackson/datatype/money/MoneyFactory.java) |
182+
| `org.javamoney.moneta.RoundedMoney` | [`new MoneyModule().withRoundedMoney()`](src/main/java/com/fasterxml/jackson/datatype/money/RoundedMoneyFactory.java) | |
183+
184+
Module supports deserialization of amount number from JSON number as well as from JSON string without any special
185+
configuration required.
186+
187+
### Custom Field Names
188+
189+
As you have seen in the previous examples the `MoneyModule` uses the field names `amount`, `currency` and `formatted`
190+
by default. Those names can be overridden if desired:
191+
192+
```java
193+
ObjectMapper mapper = new ObjectMapper()
194+
.registerModule(new MoneyModule()
195+
.withAmountFieldName("value")
196+
.withCurrencyFieldName("unit")
197+
.withFormattedFieldName("pretty"));
198+
```
199+
200+
## Usage
201+
202+
After registering and configuring the module you're now free to directly use `MonetaryAmount` in your data types:
203+
204+
```java
205+
import javax.money.MonetaryAmount;
206+
207+
public class Product {
208+
private String sku;
209+
private MonetaryAmount price;
210+
...
211+
}
212+
```

javax-money/pom.xml

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<!-- This module was also published with a richer model, Gradle metadata, -->
3+
<!-- which should be used instead. Do not delete the following line which -->
4+
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
5+
<!-- that they should prefer consuming it instead. -->
6+
<!-- do_not_remove: published-with-gradle-metadata -->
7+
<modelVersion>4.0.0</modelVersion>
8+
<parent>
9+
<groupId>com.fasterxml.jackson.datatype</groupId>
10+
<artifactId>jackson-datatypes-misc-parent</artifactId>
11+
<version>2.19.0-SNAPSHOT</version>
12+
</parent>
13+
<artifactId>jackson-datatype-money</artifactId>
14+
<name>Jackson datatype: javax-money</name>
15+
<packaging>jar</packaging>
16+
<version>2.19.0-SNAPSHOT</version>
17+
<description>Support for datatypes of Javax Money library (https://javamoney.github.io/)
18+
</description>
19+
<url>https://github.com/FasterXML/jackson-datatypes-misc</url>
20+
<licenses>
21+
<license>
22+
<name>The Apache Software License, Version 2.0</name>
23+
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
24+
<distribution>repo</distribution>
25+
</license>
26+
</licenses>
27+
<properties>
28+
<!-- Generate PackageVersion.java into this directory. -->
29+
<packageVersion.dir>com/fasterxml/jackson/datatype/money</packageVersion.dir>
30+
<packageVersion.package>${project.groupId}.money</packageVersion.package>
31+
<slf4j.version>2.0.6</slf4j.version>
32+
<junit-jupiter.version>5.9.2</junit-jupiter.version>
33+
</properties>
34+
35+
<dependencies>
36+
<dependency>
37+
<groupId>javax.money</groupId>
38+
<artifactId>money-api</artifactId>
39+
<version>1.1</version>
40+
</dependency>
41+
42+
<dependency>
43+
<groupId>org.javamoney.moneta</groupId>
44+
<artifactId>moneta-core</artifactId>
45+
<version>1.4.2</version>
46+
</dependency>
47+
48+
<dependency>
49+
<groupId>org.apiguardian</groupId>
50+
<artifactId>apiguardian-api</artifactId>
51+
<version>1.1.2</version>
52+
</dependency>
53+
<dependency>
54+
<groupId>com.google.code.findbugs</groupId>
55+
<artifactId>jsr305</artifactId>
56+
<version>3.0.2</version>
57+
<scope>provided</scope>
58+
</dependency>
59+
<dependency>
60+
<groupId>org.projectlombok</groupId>
61+
<artifactId>lombok</artifactId>
62+
<version>1.18.34</version>
63+
<scope>provided</scope>
64+
</dependency>
65+
66+
<!-- test -->
67+
<dependency>
68+
<groupId>org.slf4j</groupId>
69+
<artifactId>slf4j-nop</artifactId>
70+
<version>${slf4j.version}</version>
71+
<scope>test</scope>
72+
</dependency>
73+
<dependency>
74+
<groupId>org.assertj</groupId>
75+
<artifactId>assertj-core</artifactId>
76+
<version>3.24.2</version>
77+
<scope>test</scope>
78+
</dependency>
79+
<dependency>
80+
<groupId>org.mockito</groupId>
81+
<artifactId>mockito-core</artifactId>
82+
<version>4.5.1</version>
83+
<scope>test</scope>
84+
</dependency>
85+
<dependency>
86+
<groupId>com.fasterxml.jackson.module</groupId>
87+
<artifactId>jackson-module-jsonSchema</artifactId>
88+
<scope>test</scope>
89+
</dependency>
90+
<dependency>
91+
<groupId>com.kjetland</groupId>
92+
<artifactId>mbknor-jackson-jsonschema_2.12</artifactId>
93+
<version>1.0.39</version>
94+
<scope>test</scope>
95+
</dependency>
96+
<dependency>
97+
<groupId>javax.validation</groupId>
98+
<artifactId>validation-api</artifactId>
99+
<version>2.0.1.Final</version>
100+
<scope>test</scope>
101+
</dependency>
102+
103+
<dependency>
104+
<groupId>pl.pragmatists</groupId>
105+
<artifactId>JUnitParams</artifactId>
106+
<version>1.1.1</version>
107+
<scope>test</scope>
108+
</dependency>
109+
</dependencies>
110+
111+
<build>
112+
<plugins>
113+
<plugin>
114+
<groupId>com.google.code.maven-replacer-plugin</groupId>
115+
<artifactId>replacer</artifactId>
116+
</plugin>
117+
<plugin>
118+
<groupId>org.moditect</groupId>
119+
<artifactId>moditect-maven-plugin</artifactId>
120+
</plugin>
121+
</plugins>
122+
</build>
123+
124+
</project>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.fasterxml.jackson.datatype.money;
2+
3+
import org.apiguardian.api.API;
4+
5+
import javax.money.MonetaryAmount;
6+
7+
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
8+
9+
@API(status = EXPERIMENTAL)
10+
public interface AmountWriter<T> {
11+
12+
Class<T> getType();
13+
14+
T write(MonetaryAmount amount);
15+
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.fasterxml.jackson.datatype.money;
2+
3+
import org.apiguardian.api.API;
4+
5+
import java.math.BigDecimal;
6+
7+
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
8+
9+
@API(status = EXPERIMENTAL)
10+
public interface BigDecimalAmountWriter extends AmountWriter<BigDecimal> {
11+
12+
@Override
13+
default Class<BigDecimal> getType() {
14+
return BigDecimal.class;
15+
}
16+
17+
}

0 commit comments

Comments
 (0)