David Ashirov
David Ashirov

Reputation: 33

Customizing Databind Json serialization format of MonetaryAmount JSR354 / moneta

I'm trying to Json Serialize a POJO with MonetaryAmount field as a string, but the resulting output does not follow the prescribed shape format.

// org.javamoney:moneta:1.1 
// com.fasterxml.jackson.core:jackson-annotations:2.7.0
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
        "CBNOT_CHARGEBACK_AMOUNT"
})
public class TestMonetaryAmountJsonSerialization {
        @JsonProperty("CBNOT_CHARGEBACK_AMOUNT")
        @NotNull
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "¤#,##0.00", locale = "en_US")
        private final MonetaryAmount chargebackAmount = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(12.50).create();

        private static final ObjectMapper mapper = new ObjectMapper();

        @Test
        public void testThis() throws JsonProcessingException{
            String json = mapper.writeValueAsString(this);
            System.out.println(json);
            Assert.assertEquals("{\"CBNOT_CHARGEBACK_AMOUNT\":\"¤12.50\"}",json);
        }

}

OUTPUT: {"CBNOT_CHARGEBACK_AMOUNT":{"currency":{"context":{"empty":false,"providerName":"java.util.Currency"},"defaultFractionDigits":2,"currencyCode":"USD","numericCode":840},"number":12.5,"factory":{"defaultMonetaryContext":{"precision":0,"fixedScale":false,"amountType":"org.javamoney.moneta.Money","maxScale":63,"empty":false,"providerName":null},"maxNumber":null,"minNumber":null,"amountType":"org.javamoney.moneta.Money","maximalMonetaryContext":{"precision":0,"fixedScale":false,"amountType":"org.javamoney.moneta.Money","maxScale":-1,"empty":false,"providerName":null}},"context":{"precision":0,"fixedScale":false,"amountType":"org.javamoney.moneta.Money","maxScale":63,"empty":false,"providerName":null},"numberStripped":12.5,"zero":false,"negative":false,"negativeOrZero":false,"positive":true,"positiveOrZero":true}}

Any ideas what am I doing wrong? I threw the kitchen sink in this code here, only for illustrative purposes and compact presentation.

Upvotes: 1

Views: 1360

Answers (1)

starikoff
starikoff

Reputation: 1660

JsonFormat is an annotation used in several (de)serializers defined by Jackson (e.g. DateTimeSerializerBase, NumberSerializers.Base and some other, full list here), it's not a general purpose mechanism turning any object into a string:

Unlike most other Jackson annotations, annotation does not have specific universal interpretation: instead, effect depends on datatype of property being annotated (or more specifically, deserializer and serializer being used).

Specifying it won't have any effect unless you create a custom serializer for MonetaryAmount or use one that makes use of this annotation (and also its pattern property), but if you create a custom serializer, chances are you won't need that level of flexibility as to specify different patterns for different fields and could just use a fixed MonetaryAmountFormat or build the necessary string from the MonetaryAmount object otherwise.

For example

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
        "CBNOT_CHARGEBACK_AMOUNT"
})
public class TestMonetaryAmountJsonSerialization {
    @JsonProperty("CBNOT_CHARGEBACK_AMOUNT")
    @NotNull
    private final MonetaryAmount chargebackAmount = Monetary.getDefaultAmountFactory().setCurrency("USD").setNumber(12.50).create();

    private static final ObjectMapper mapper = new ObjectMapper();
    static {
        SimpleModule monetaryModule = new SimpleModule();
        monetaryModule.addSerializer(MonetaryAmount.class, new MonetaryAmountSerializer());
        mapper.registerModule(monetaryModule);
    }

    @Test
    public void testThis() throws JsonProcessingException {
        String json = mapper.writeValueAsString(this);
        System.out.println(json);
        Assert.assertEquals("{\"CBNOT_CHARGEBACK_AMOUNT\":\"$12.50\"}", json);
    }

    public static class MonetaryAmountSerializer extends JsonSerializer<MonetaryAmount> {
        public void serialize(MonetaryAmount monetaryAmount,
                              JsonGenerator jsonGenerator,
                              SerializerProvider serializerProvider) throws IOException {
            StringBuilder sb = new StringBuilder();
            MonetaryAmountDecimalFormatBuilder
                    .of("¤#,##0.00").withCurrencyUnit(monetaryAmount.getCurrency()).build()
                    .print(sb, monetaryAmount);
            jsonGenerator.writeString(sb.toString());
        }
    }
}

Upvotes: 1

Related Questions