diff --git a/joda-money/README.md b/joda-money/README.md
index 8892c650..ec377411 100644
--- a/joda-money/README.md
+++ b/joda-money/README.md
@@ -44,3 +44,21 @@ Money amount = mapper.readValue("{\"currency\":\"EUR\",\"amount\":19.99}", Money
assertEquals("EUR", amount.getCurrencyUnit().getCode())
assertEquals(BigDecimal.valueOf(19.99), amount.getAmount())
```
+
+### Configuring the module
+
+#### Amount representation
+
+Representation of the amount for the (de)serialized `Money` instances can be configured via the `JodaMoneyModule.withAmountRepresentation(AmountRepresentation)` method. The available representations are:
+
+* `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 or `12` for JPY 12.
+
+Example usage:
+
+```java
+ObjectMapper mapper = JsonMapper.builder()
+ .addModule(new JodaMoneyModule().withAmountRepresentation(AmountRepresentation.DECIMAL_STRING))
+ .build();
+```
diff --git a/joda-money/pom.xml b/joda-money/pom.xml
index 687915d5..abbc39b8 100644
--- a/joda-money/pom.xml
+++ b/joda-money/pom.xml
@@ -30,6 +30,12 @@
joda-money
1.0.1
+
+ pl.pragmatists
+ JUnitParams
+ 1.1.1
+ test
+
diff --git a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/AmountConverter.java b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/AmountConverter.java
new file mode 100644
index 00000000..0c341f02
--- /dev/null
+++ b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/AmountConverter.java
@@ -0,0 +1,18 @@
+package com.fasterxml.jackson.datatype.jodamoney;
+
+import org.joda.money.CurrencyUnit;
+import org.joda.money.Money;
+
+import java.math.BigDecimal;
+
+/**
+ * Common interface for amount conversion strategies used by {@link Money} (de)serializer.
+ * Allows conversion of {@code Money} to implementation-specific representation of its amount,
+ * and back to {@code Money}.
+ */
+interface AmountConverter {
+
+ Object fromMoney(Money money);
+
+ Money toMoney(CurrencyUnit currencyUnit, BigDecimal amount);
+}
diff --git a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/AmountRepresentation.java b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/AmountRepresentation.java
new file mode 100644
index 00000000..abd2ef84
--- /dev/null
+++ b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/AmountRepresentation.java
@@ -0,0 +1,36 @@
+package com.fasterxml.jackson.datatype.jodamoney;
+
+/**
+ * Enumeration of available strategies used by {@link MoneySerializer} and {@link MoneyDeserializer}
+ * to represent amounts of {@link org.joda.money.Money Money}.
+ */
+public enum AmountRepresentation {
+
+ /**
+ * Decimal number representation, where amount is (de)serialized as decimal number equal
+ * to {@link org.joda.money.Money Money}'s amount, e.g. {@code 12.34} for
+ * {@code Money.parse("EUR 12.34")}.
+ *
+ * @see DecimalNumberAmountConverter
+ */
+ DECIMAL_NUMBER,
+
+ /**
+ * Decimal string representation, where amount is (de)serialized as string containing decimal
+ * number equal to {@link org.joda.money.Money Money}'s amount, e.g. {@code "12.34"} for
+ * {@code Money.parse("EUR 12.34")}.
+ *
+ * @see DecimalStringAmountConverter
+ */
+ DECIMAL_STRING,
+
+ /**
+ * Minor currency unit representation, where amount is (de)serialized as long integer equal
+ * to {@link org.joda.money.Money Money}'s amount expressed in minor currency unit, e.g.
+ * {@code 1234} for {@code Money.parse("EUR 12.34")}, {@code 12345} for
+ * {@code Money.parse("KWD 12.345")} or {@code 12} for {@code Money.parse("JPY 12")}.
+ *
+ * @see MinorCurrencyUnitAmountConverter
+ */
+ MINOR_CURRENCY_UNIT,
+}
diff --git a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/DecimalNumberAmountConverter.java b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/DecimalNumberAmountConverter.java
new file mode 100644
index 00000000..7f4aa940
--- /dev/null
+++ b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/DecimalNumberAmountConverter.java
@@ -0,0 +1,37 @@
+package com.fasterxml.jackson.datatype.jodamoney;
+
+import org.joda.money.CurrencyUnit;
+import org.joda.money.Money;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+/**
+ * An {@link AmountConverter} converting {@link Money} to its amount represented as
+ * {@link BigDecimal decimal number} (such as {@code 12.34} for {@code Money.parse("USD 12.34")}),
+ * and back to {@code Money} from this representation.
+ */
+final class DecimalNumberAmountConverter implements AmountConverter {
+
+ private static final DecimalNumberAmountConverter INSTANCE = new DecimalNumberAmountConverter();
+
+ static DecimalNumberAmountConverter getInstance() {
+ return INSTANCE;
+ }
+
+ private DecimalNumberAmountConverter() {
+ }
+
+ @Override
+ public BigDecimal fromMoney(final Money money) {
+ final BigDecimal decimal = money.getAmount();
+ final int decimalPlaces = money.getCurrencyUnit().getDecimalPlaces();
+ final int scale = Math.max(decimal.scale(), decimalPlaces);
+ return decimal.setScale(scale, RoundingMode.UNNECESSARY);
+ }
+
+ @Override
+ public Money toMoney(final CurrencyUnit currencyUnit, final BigDecimal amount) {
+ return Money.of(currencyUnit, amount);
+ }
+}
diff --git a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/DecimalStringAmountConverter.java b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/DecimalStringAmountConverter.java
new file mode 100644
index 00000000..5a5e4c90
--- /dev/null
+++ b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/DecimalStringAmountConverter.java
@@ -0,0 +1,33 @@
+package com.fasterxml.jackson.datatype.jodamoney;
+
+import org.joda.money.CurrencyUnit;
+import org.joda.money.Money;
+
+import java.math.BigDecimal;
+
+/**
+ * An {@link AmountConverter} converting {@link Money} to its amount represented as decimal string
+ * (such as {@code "12.34"} for {@code Money.parse("USD 12.34")}), and back to {@code Money} from
+ * this representation.
+ */
+final class DecimalStringAmountConverter implements AmountConverter {
+
+ private static final DecimalStringAmountConverter INSTANCE = new DecimalStringAmountConverter();
+
+ static DecimalStringAmountConverter getInstance() {
+ return INSTANCE;
+ }
+
+ private DecimalStringAmountConverter() {
+ }
+
+ @Override
+ public String fromMoney(final Money money) {
+ return DecimalNumberAmountConverter.getInstance().fromMoney(money).toPlainString();
+ }
+
+ @Override
+ public Money toMoney(final CurrencyUnit currencyUnit, final BigDecimal amount) {
+ return Money.of(currencyUnit, amount);
+ }
+}
diff --git a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/JodaMoneyModule.java b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/JodaMoneyModule.java
index f811bed8..5be884d3 100644
--- a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/JodaMoneyModule.java
+++ b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/JodaMoneyModule.java
@@ -14,7 +14,15 @@ public class JodaMoneyModule extends Module
{
private static final long serialVersionUID = 1L;
- public JodaMoneyModule() { }
+ private final AmountConverter amountConverter;
+
+ private JodaMoneyModule(AmountConverter amountConverter) {
+ this.amountConverter = amountConverter;
+ }
+
+ public JodaMoneyModule() {
+ this(DecimalNumberAmountConverter.getInstance());
+ }
@Override
public String getModuleName() {
@@ -34,12 +42,24 @@ public void setupModule(SetupContext context)
{
final SimpleDeserializers desers = new SimpleDeserializers();
desers.addDeserializer(CurrencyUnit.class, new CurrencyUnitDeserializer());
- desers.addDeserializer(Money.class, new MoneyDeserializer());
+ desers.addDeserializer(Money.class, new MoneyDeserializer(amountConverter));
context.addDeserializers(desers);
final SimpleSerializers sers = new SimpleSerializers();
sers.addSerializer(CurrencyUnit.class, new CurrencyUnitSerializer());
- sers.addSerializer(Money.class, new MoneySerializer());
+ sers.addSerializer(Money.class, new MoneySerializer(amountConverter));
context.addSerializers(sers);
}
+
+ public JodaMoneyModule withAmountRepresentation(final AmountRepresentation representation) {
+ switch (representation) {
+ case DECIMAL_NUMBER:
+ return new JodaMoneyModule(DecimalNumberAmountConverter.getInstance());
+ case DECIMAL_STRING:
+ return new JodaMoneyModule(DecimalStringAmountConverter.getInstance());
+ case MINOR_CURRENCY_UNIT:
+ return new JodaMoneyModule(MinorCurrencyUnitAmountConverter.getInstance());
+ }
+ throw new IllegalArgumentException("Unrecognized amount representation: " + representation);
+ }
}
diff --git a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MinorCurrencyUnitAmountConverter.java b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MinorCurrencyUnitAmountConverter.java
new file mode 100644
index 00000000..cd89f235
--- /dev/null
+++ b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MinorCurrencyUnitAmountConverter.java
@@ -0,0 +1,34 @@
+package com.fasterxml.jackson.datatype.jodamoney;
+
+import org.joda.money.CurrencyUnit;
+import org.joda.money.Money;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+/**
+ * An {@link AmountConverter} converting {@link Money} to its amount represented in
+ * {@link Money#getAmountMinorLong() minor units as a long} (such as {@code 1234} for
+ * {@code Money.parse("USD 12.34")}), and back to {@code Money} from this representation.
+ */
+final class MinorCurrencyUnitAmountConverter implements AmountConverter {
+
+ private static final MinorCurrencyUnitAmountConverter INSTANCE = new MinorCurrencyUnitAmountConverter();
+
+ static MinorCurrencyUnitAmountConverter getInstance() {
+ return INSTANCE;
+ }
+
+ private MinorCurrencyUnitAmountConverter() {
+ }
+
+ @Override
+ public Long fromMoney(final Money money) {
+ return money.getAmountMinorLong();
+ }
+
+ @Override
+ public Money toMoney(final CurrencyUnit currencyUnit, final BigDecimal amount) {
+ return Money.of(currencyUnit, amount.movePointLeft(currencyUnit.getDecimalPlaces()), RoundingMode.UNNECESSARY);
+ }
+}
diff --git a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MoneyDeserializer.java b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MoneyDeserializer.java
index bcc222f6..91256242 100644
--- a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MoneyDeserializer.java
+++ b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MoneyDeserializer.java
@@ -16,15 +16,25 @@
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
+import static java.util.Objects.requireNonNull;
+
public class MoneyDeserializer extends StdDeserializer
{
private static final long serialVersionUID = 1L;
private final String F_AMOUNT = "amount";
private final String F_CURRENCY = "currency";
+ private final AmountConverter amountConverter;
+ // Kept to maintain backward compatibility with 2.x
+ @SuppressWarnings("unused")
public MoneyDeserializer() {
+ this(DecimalNumberAmountConverter.getInstance());
+ }
+
+ MoneyDeserializer(final AmountConverter amountConverter) {
super(Money.class);
+ this.amountConverter = requireNonNull(amountConverter, "amount converter cannot be null");
}
@Override
@@ -75,7 +85,7 @@ public Money deserialize(final JsonParser p, final DeserializationContext ctxt)
} else if (currencyUnit == null) {
missingName = F_CURRENCY;
} else {
- return Money.of(currencyUnit, amount);
+ return amountConverter.toMoney(currencyUnit, amount);
}
return ctxt.reportPropertyInputMismatch(getValueType(ctxt), missingName,
diff --git a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MoneySerializer.java b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MoneySerializer.java
index de93db0b..ed46d3c8 100644
--- a/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MoneySerializer.java
+++ b/joda-money/src/main/java/com/fasterxml/jackson/datatype/jodamoney/MoneySerializer.java
@@ -1,23 +1,31 @@
package com.fasterxml.jackson.datatype.jodamoney;
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-
-import org.joda.money.Money;
-
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
+import org.joda.money.Money;
+
+import java.io.IOException;
+
+import static java.util.Objects.requireNonNull;
public class MoneySerializer extends JodaMoneySerializerBase
{
private static final long serialVersionUID = 1L;
+ private final AmountConverter amountConverter;
+
+ // Kept to maintain backward compatibility with 2.x
+ @SuppressWarnings("unused")
public MoneySerializer() {
+ this(DecimalNumberAmountConverter.getInstance());
+ }
+
+ MoneySerializer(final AmountConverter amountConverter) {
super(Money.class);
+ this.amountConverter = requireNonNull(amountConverter, "amount converter cannot be null");
}
@Override
@@ -45,16 +53,12 @@ public void serializeWithType(Money value, JsonGenerator g,
typeSer.writeTypeSuffix(g, typeIdDef);
}
- private final void _writeFields(final Money money,
+ private void _writeFields(final Money money,
final JsonGenerator g,
final SerializerProvider context)
throws IOException
{
- final BigDecimal decimal = money.getAmount();
- final int decimalPlaces = money.getCurrencyUnit().getDecimalPlaces();
- final int scale = Math.max(decimal.scale(), decimalPlaces);
- g.writeNumberField("amount", decimal.setScale(scale, RoundingMode.UNNECESSARY));
- g.writeFieldName("currency");
- context.defaultSerializeValue(money.getCurrencyUnit(), g);
+ context.defaultSerializeField("amount", amountConverter.fromMoney(money), g);
+ context.defaultSerializeField("currency", money.getCurrencyUnit(), g);
}
}
diff --git a/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/ModuleTestBase.java b/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/ModuleTestBase.java
index 39ff7b65..e73a6344 100644
--- a/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/ModuleTestBase.java
+++ b/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/ModuleTestBase.java
@@ -1,17 +1,13 @@
package com.fasterxml.jackson.datatype.jodamoney;
-import java.text.DateFormat;
-import java.util.Arrays;
-import java.util.TimeZone;
-
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.MapperBuilder;
import com.fasterxml.jackson.databind.json.JsonMapper;
-
import junit.framework.TestCase;
-import static org.junit.Assert.*;
+import java.util.Arrays;
+import java.util.function.Function;
public abstract class ModuleTestBase extends TestCase
{
@@ -30,28 +26,14 @@ protected static MapperBuilder,?> mapperWithModuleBuilder() {
.addModule(new JodaMoneyModule());
}
- protected static MapperBuilder,?> jodaMapperBuilder(DateFormat df) {
- return mapperWithModuleBuilder()
- .defaultDateFormat(df);
- }
-
- protected static MapperBuilder,?> jodaMapperBuilder(TimeZone tz) {
- return mapperWithModuleBuilder()
- .defaultTimeZone(tz);
- }
-
protected static ObjectMapper mapperWithModule() {
return mapperWithModuleBuilder().build();
}
- protected static ObjectMapper mapperWithModule(DateFormat df) {
- return jodaMapperBuilder(df)
- .build();
- }
-
- protected static ObjectMapper mapperWithModule(TimeZone tz) {
- return jodaMapperBuilder(tz)
- .build();
+ protected static ObjectMapper mapperWithModule(Function customizations) {
+ return JsonMapper.builder()
+ .addModule(customizations.apply(new JodaMoneyModule()))
+ .build();
}
/*
@@ -60,10 +42,6 @@ protected static ObjectMapper mapperWithModule(TimeZone tz) {
/**********************************************************************
*/
- protected void assertEquals(int[] exp, int[] act) {
- assertArrayEquals(exp, act);
- }
-
/*
/**********************************************************************
/* Helper methods
@@ -76,7 +54,7 @@ protected void verifyException(Throwable e, String... matches)
String lmsg = (msg == null) ? "" : msg.toLowerCase();
for (String match : matches) {
String lmatch = match.toLowerCase();
- if (lmsg.indexOf(lmatch) >= 0) {
+ if (lmsg.contains(lmatch)) {
return;
}
}
@@ -84,11 +62,7 @@ protected void verifyException(Throwable e, String... matches)
+Arrays.asList(matches)+"): got one with message \""+msg+"\"");
}
- public String q(String str) {
- return '"'+str+'"';
- }
-
- protected String a2q(String json) {
- return json.replace("'", "\"");
+ protected String json(String format, Object... args) {
+ return String.format(format, args).replace('\'', '"');
}
}
diff --git a/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/MoneyDeserializerTest.java b/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/MoneyDeserializerTest.java
index 5a638420..743af287 100644
--- a/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/MoneyDeserializerTest.java
+++ b/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/MoneyDeserializerTest.java
@@ -9,47 +9,134 @@
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import static com.fasterxml.jackson.datatype.jodamoney.AmountRepresentation.*;
+
+@RunWith(JUnitParamsRunner.class)
public final class MoneyDeserializerTest extends ModuleTestBase
{
- private final ObjectMapper MAPPER = mapperWithModule();
- private final ObjectReader R = MAPPER.readerFor(Money.class);
/*
/**********************************************************************
/* Tests, happy path
/**********************************************************************
*/
-
- public void testShouldDeserialize() throws IOException
- {
-
- final String content = "{\"amount\":19.99,\"currency\":\"EUR\"}";
- final Money actualAmount = R.readValue(content);
- assertEquals(Money.of(CurrencyUnit.EUR, BigDecimal.valueOf(19.99)), actualAmount);
- assertEquals(BigDecimal.valueOf(19.99), actualAmount.getAmount());
- assertEquals(actualAmount.getCurrencyUnit().getCode(), "EUR");
+ @Test
+ @Parameters({
+ "{'amount':19.99\\,'currency':'EUR'}, EUR, 19.99",
+ "{'amount':19.999\\,'currency':'KWD'}, KWD, 19.999",
+ "{'amount':19\\,'currency':'JPY'}, JPY, 19",
+ "{'amount':19.9\\,'currency':'EUR'}, EUR, 19.90",
+ "{'amount':-19.5\\,'currency':'EUR'}, EUR, -19.50",
+ "{'amount':0\\,'currency':'EUR'}, EUR, 0",
+ "{'amount':'19.99'\\,'currency':'EUR'}, EUR, 19.99",
+ "{'amount':'19.0'\\,'currency':'EUR'}, EUR, 19.00",
+ "{'amount':'19'\\,'currency':'EUR'}, EUR, 19.00",
+ "{'currency':'EUR'\\,'amount':'19.50'}, EUR, 19.50",
+ })
+ @TestCaseName("should deserialize {0} as {1} {2}")
+ public void testShouldDeserialize(
+ String json,
+ String currencyCode,
+ BigDecimal amount
+ ) throws Exception {
+
+ final ObjectMapper mapper = mapperWithModule();
+ final ObjectReader reader = mapper.readerFor(Money.class);
+
+ final Money actual = reader.readValue(json(json));
+
+ assertEquals(Money.of(CurrencyUnit.of(currencyCode), amount), actual);
}
- public void testShouldDeserializeWhenAmountIsAStringValue() throws IOException
- {
- final String content = "{\"currency\":\"EUR\",\"amount\":\"19.99\"}";
- final Money actualAmount = R.readValue(content);
-
- assertEquals(BigDecimal.valueOf(19.99), actualAmount.getAmount());
- assertEquals(actualAmount.getCurrencyUnit().getCode(), "EUR");
+ @Test
+ @Parameters({
+ "{'amount':19.99\\,'currency':'EUR'}, EUR, 19.99",
+ "{'amount':19.999\\,'currency':'KWD'}, KWD, 19.999",
+ "{'amount':19\\,'currency':'JPY'}, JPY, 19",
+ "{'amount':19.9\\,'currency':'EUR'}, EUR, 19.90",
+ "{'amount':-19.5\\,'currency':'EUR'}, EUR, -19.50",
+ "{'amount':0\\,'currency':'EUR'}, EUR, 0",
+ "{'amount':'19.99'\\,'currency':'EUR'}, EUR, 19.99",
+ "{'amount':'19.0'\\,'currency':'EUR'}, EUR, 19.00",
+ "{'amount':'19'\\,'currency':'EUR'}, EUR, 19.00",
+ "{'currency':'EUR'\\,'amount':'19.50'}, EUR, 19.50",
+ })
+ @TestCaseName("should deserialize {0} as {1} {2}")
+ public void testShouldDeserializeDecimalNumberAmount(
+ String json,
+ String currencyCode,
+ BigDecimal amount
+ ) throws Exception {
+
+ final ObjectMapper mapper = mapperWithModule(m -> m.withAmountRepresentation(DECIMAL_NUMBER));
+ final ObjectReader reader = mapper.readerFor(Money.class);
+
+ final Money actual = reader.readValue(json(json));
+
+ assertEquals(Money.of(CurrencyUnit.of(currencyCode), amount), actual);
}
- public void testShouldDeserializeWhenOrderIsDifferent() throws IOException
- {
- final String content = "{\"currency\":\"EUR\",\"amount\":19.99}";
- final Money actualAmount = R.readValue(content);
+ @Test
+ @Parameters({
+ "{'amount':'19.99'\\,'currency':'EUR'}, EUR, 19.99",
+ "{'amount':'19.999'\\,'currency':'KWD'}, KWD, 19.999",
+ "{'amount':'19'\\,'currency':'JPY'}, JPY, 19",
+ "{'amount':'19.9'\\,'currency':'EUR'}, EUR, 19.90",
+ "{'amount':'-19.5'\\,'currency':'EUR'}, EUR, -19.50",
+ "{'amount':'0'\\,'currency':'EUR'}, EUR, 0",
+ "{'amount':'19.0'\\,'currency':'EUR'}, EUR, 19.00",
+ "{'amount':'19'\\,'currency':'EUR'}, EUR, 19.00",
+ "{'currency':'EUR'\\,'amount':'19.50'}, EUR, 19.50",
+ })
+ @TestCaseName("should deserialize {0} as {1} {2}")
+ public void testShouldDeserializeDecimalStringAmount(
+ String json,
+ String currencyCode,
+ BigDecimal amount
+ ) throws Exception {
+
+ final ObjectMapper mapper = mapperWithModule(m -> m.withAmountRepresentation(DECIMAL_STRING));
+ final ObjectReader reader = mapper.readerFor(Money.class);
+
+ final Money actual = reader.readValue(json(json));
+
+ assertEquals(Money.of(CurrencyUnit.of(currencyCode), amount), actual);
+ }
- assertEquals(BigDecimal.valueOf(19.99), actualAmount.getAmount());
- assertEquals(actualAmount.getCurrencyUnit().getCode(), "EUR");
+ @Test
+ @Parameters({
+ "{'amount':1999\\,'currency':'EUR'}, EUR, 19.99",
+ "{'amount':19999\\,'currency':'KWD'}, KWD, 19.999",
+ "{'amount':19\\,'currency':'JPY'}, JPY, 19",
+ "{'amount':1990\\,'currency':'EUR'}, EUR, 19.90",
+ "{'amount':-1950\\,'currency':'EUR'}, EUR, -19.50",
+ "{'amount':0\\,'currency':'EUR'}, EUR, 0",
+ "{'amount':'-1950'\\,'currency':'EUR'}, EUR, -19.50",
+ "{'amount':'1900.00'\\,'currency':'EUR'}, EUR, 19.00",
+ "{'currency':'EUR'\\,'amount':1950}, EUR, 19.50",
+ })
+ @TestCaseName("should deserialize {0} as {1} {2}")
+ public void testShouldDeserializeAmountInMinorCurrencyUnit(
+ String json,
+ String currencyCode,
+ BigDecimal amount
+ ) throws Exception {
+
+ final ObjectMapper mapper = mapperWithModule(m -> m.withAmountRepresentation(MINOR_CURRENCY_UNIT));
+ final ObjectReader reader = mapper.readerFor(Money.class);
+
+ final Money actual = reader.readValue(json(json));
+
+ assertEquals(Money.of(CurrencyUnit.of(currencyCode), amount), actual);
}
/*
@@ -58,6 +145,9 @@ public void testShouldDeserializeWhenOrderIsDifferent() throws IOException
/**********************************************************************
*/
+ private final ObjectMapper MAPPER = mapperWithModule();
+ private final ObjectReader R = MAPPER.readerFor(Money.class);
+
public void testShouldFailDeserializationWithoutAmount() throws Exception
{
final String content = "{\"currency\":\"EUR\"}";
@@ -101,7 +191,7 @@ public void testShouldPerformDeserializationWithUnknownProperties() throws IOExc
{
final ObjectReader r = MAPPER.readerFor(Money.class)
.without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
- final String content = a2q("{'amount':5000,'currency':'EUR','unknown':'test'}");
+ final String content = json("{'amount':5000,'currency':'EUR','unknown':'test'}");
final Money actualAmount = r.readValue(content);
assertEquals(Money.of(CurrencyUnit.EUR, BigDecimal.valueOf(5000)), actualAmount);
}
diff --git a/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/MoneySerializerTest.java b/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/MoneySerializerTest.java
index d53be992..0401c08e 100644
--- a/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/MoneySerializerTest.java
+++ b/joda-money/src/test/java/com/fasterxml/jackson/datatype/jodamoney/MoneySerializerTest.java
@@ -4,14 +4,105 @@
import com.fasterxml.jackson.databind.ObjectMapper;
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+import junitparams.naming.TestCaseName;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import static com.fasterxml.jackson.datatype.jodamoney.AmountRepresentation.*;
+
+@RunWith(JUnitParamsRunner.class)
public final class MoneySerializerTest extends ModuleTestBase
{
- public void testShouldSerialize() throws Exception {
+
+ @Test
+ @Parameters({
+ "EUR, 19.99, 19.99",
+ "KWD, 19.999, 19.999",
+ "JPY, 19, 19",
+ "EUR, 19.9, 19.90",
+ "EUR, -19.5, -19.50",
+ "EUR, 0, 0.00",
+ })
+ @TestCaseName("should serialize {0} {1} with amount representation {2}")
+ public void testShouldSerialize(
+ String currencyCode,
+ BigDecimal amount,
+ String amountInJson
+ ) throws Exception {
+
final ObjectMapper mapper = mapperWithModule();
- assertEquals("{\"amount\":19.99,\"currency\":\"EUR\"}",
- mapper.writeValueAsString(Money.of(CurrencyUnit.EUR, BigDecimal.valueOf(19.99))));
+
+ assertEquals(json("{'amount':%s,'currency':'%s'}", amountInJson, currencyCode),
+ mapper.writeValueAsString(Money.of(CurrencyUnit.of(currencyCode), amount)));
+ }
+
+ @Test
+ @Parameters({
+ "EUR, 19.99, 19.99",
+ "KWD, 19.999, 19.999",
+ "JPY, 19, 19",
+ "EUR, 19.9, 19.90",
+ "EUR, -19.5, -19.50",
+ "EUR, 0, 0.00",
+ })
+ @TestCaseName("should serialize {0} {1} with amount representation {2}")
+ public void testShouldSerializeAmountAsDecimalNumber(
+ String currencyCode,
+ BigDecimal amount,
+ String amountInJson
+ ) throws Exception {
+
+ final ObjectMapper mapper = mapperWithModule(m -> m.withAmountRepresentation(DECIMAL_NUMBER));
+
+ assertEquals(json("{'amount':%s,'currency':'%s'}", amountInJson, currencyCode),
+ mapper.writeValueAsString(Money.of(CurrencyUnit.of(currencyCode), amount)));
+ }
+
+ @Test
+ @Parameters({
+ "EUR, 19.99, 19.99",
+ "KWD, 19.999, 19.999",
+ "JPY, 19, 19",
+ "EUR, 19.9, 19.90",
+ "EUR, -19.5, -19.50",
+ "EUR, 0, 0.00",
+ })
+ @TestCaseName("should serialize {0} {1} with amount representation {2}")
+ public void testShouldSerializeAmountAsDecimalString(
+ String currencyCode,
+ BigDecimal amount,
+ String amountInJson
+ ) throws Exception {
+
+ final ObjectMapper mapper = mapperWithModule(m -> m.withAmountRepresentation(DECIMAL_STRING));
+
+ assertEquals(json("{'amount':'%s','currency':'%s'}", amountInJson, currencyCode),
+ mapper.writeValueAsString(Money.of(CurrencyUnit.of(currencyCode), amount)));
+ }
+
+ @Test
+ @Parameters({
+ "EUR, 19.99, 1999",
+ "KWD, 19.999, 19999",
+ "JPY, 19, 19",
+ "EUR, 19.9, 1990",
+ "EUR, -19.5, -1950",
+ "EUR, 0, 0",
+ })
+ @TestCaseName("should serialize {0} {1} with amount representation {2}")
+ public void testShouldSerializeAmountInMinorCurrencyUnit(
+ String currencyCode,
+ BigDecimal amount,
+ String amountInJson
+ ) throws Exception {
+
+ final ObjectMapper mapper = mapperWithModule(m -> m.withAmountRepresentation(MINOR_CURRENCY_UNIT));
+
+ assertEquals(json("{'amount':%s,'currency':'%s'}", amountInJson, currencyCode),
+ mapper.writeValueAsString(Money.of(CurrencyUnit.of(currencyCode), amount)));
}
}