package org.zalando.jackson.datatype.money; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.core.util.VersionUtil; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.module.SimpleDeserializers; import com.fasterxml.jackson.databind.module.SimpleSerializers; import org.apiguardian.api.API; import org.javamoney.moneta.FastMoney; import org.javamoney.moneta.Money; import org.javamoney.moneta.RoundedMoney; import javax.money.CurrencyUnit; import javax.money.MonetaryAmount; import javax.money.MonetaryOperator; import javax.money.MonetaryRounding; import javax.money.format.MonetaryFormats; import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; @API(status = STABLE) public final class MoneyModule extends Module { private final AmountWriter<?> writer; private final FieldNames names; private final MonetaryAmountFormatFactory formatFactory; private final MonetaryAmountFactory<? extends MonetaryAmount> amountFactory; private final MonetaryAmountFactory<FastMoney> fastMoneyFactory; private final MonetaryAmountFactory<Money> moneyFactory; private final MonetaryAmountFactory<RoundedMoney> roundedMoneyFactory; public MoneyModule() { this(new DecimalAmountWriter(), FieldNames.defaults(), MonetaryAmountFormatFactory.NONE, Money::of, FastMoney::of, Money::of, RoundedMoney::of); } private MoneyModule(final AmountWriter<?> writer, final FieldNames names, final MonetaryAmountFormatFactory formatFactory, final MonetaryAmountFactory<? extends MonetaryAmount> amountFactory, final MonetaryAmountFactory<FastMoney> fastMoneyFactory, final MonetaryAmountFactory<Money> moneyFactory, final MonetaryAmountFactory<RoundedMoney> roundedMoneyFactory) { this.writer = writer; this.names = names; this.formatFactory = formatFactory; this.amountFactory = amountFactory; this.fastMoneyFactory = fastMoneyFactory; this.moneyFactory = moneyFactory; this.roundedMoneyFactory = roundedMoneyFactory; } @Override public String getModuleName() { return MoneyModule.class.getSimpleName(); } @Override @SuppressWarnings("deprecation") public Version version() { final ClassLoader loader = MoneyModule.class.getClassLoader(); return VersionUtil.mavenVersionFor(loader, "org.zalando", "jackson-datatype-money"); } @Override public void setupModule(final SetupContext context) { final SimpleSerializers serializers = new SimpleSerializers(); serializers.addSerializer(CurrencyUnit.class, new CurrencyUnitSerializer()); serializers.addSerializer(MonetaryAmount.class, new MonetaryAmountSerializer(names, writer, formatFactory)); context.addSerializers(serializers); final SimpleDeserializers deserializers = new SimpleDeserializers(); deserializers.addDeserializer(CurrencyUnit.class, new CurrencyUnitDeserializer()); deserializers.addDeserializer(MonetaryAmount.class, new MonetaryAmountDeserializer<>(amountFactory, names)); // for reading into concrete implementation types deserializers.addDeserializer(Money.class, new MonetaryAmountDeserializer<>(moneyFactory, names)); deserializers.addDeserializer(FastMoney.class, new MonetaryAmountDeserializer<>(fastMoneyFactory, names)); deserializers.addDeserializer(RoundedMoney.class, new MonetaryAmountDeserializer<>(roundedMoneyFactory, names)); context.addDeserializers(deserializers); } public MoneyModule withDecimalNumbers() { return withNumbers(new DecimalAmountWriter()); } public MoneyModule withQuotedDecimalNumbers() { return withNumbers(new QuotedDecimalAmountWriter()); } @API(status = EXPERIMENTAL) public MoneyModule withNumbers(final AmountWriter<?> writer) { return new MoneyModule(writer, names, formatFactory, amountFactory, fastMoneyFactory, moneyFactory, roundedMoneyFactory); } /** * @see FastMoney * @return new {@link MoneyModule} using {@link FastMoney} */ public MoneyModule withFastMoney() { return withMonetaryAmount(fastMoneyFactory); } /** * @see Money * @return new {@link MoneyModule} using {@link Money} */ public MoneyModule withMoney() { return withMonetaryAmount(moneyFactory); } /** * @see RoundedMoney * @return new {@link MoneyModule} using {@link RoundedMoney} */ public MoneyModule withRoundedMoney() { return withMonetaryAmount(roundedMoneyFactory); } /** * @see RoundedMoney * @param rounding the rounding operator * @return new {@link MoneyModule} using {@link RoundedMoney} with the given {@link MonetaryRounding} */ public MoneyModule withRoundedMoney(final MonetaryOperator rounding) { final MonetaryAmountFactory<RoundedMoney> factory = (amount, currency) -> RoundedMoney.of(amount, currency, rounding); return new MoneyModule(writer, names, formatFactory, factory, fastMoneyFactory, moneyFactory, factory); } public MoneyModule withMonetaryAmount(final MonetaryAmountFactory<? extends MonetaryAmount> amountFactory) { return new MoneyModule(writer, names, formatFactory, amountFactory, fastMoneyFactory, moneyFactory, roundedMoneyFactory); } public MoneyModule withoutFormatting() { return withFormatting(MonetaryAmountFormatFactory.NONE); } public MoneyModule withDefaultFormatting() { return withFormatting(MonetaryFormats::getAmountFormat); } public MoneyModule withFormatting(final MonetaryAmountFormatFactory formatFactory) { return new MoneyModule(writer, names, formatFactory, amountFactory, fastMoneyFactory, moneyFactory, roundedMoneyFactory); } public MoneyModule withAmountFieldName(final String name) { return withFieldNames(names.withAmount(name)); } public MoneyModule withCurrencyFieldName(final String name) { return withFieldNames(names.withCurrency(name)); } public MoneyModule withFormattedFieldName(final String name) { return withFieldNames(names.withFormatted(name)); } private MoneyModule withFieldNames(final FieldNames names) { return new MoneyModule(writer, names, formatFactory, amountFactory, fastMoneyFactory, moneyFactory, roundedMoneyFactory); } }