Настройка формата сериализации Databind Json для MonetaryAmount JSR354 / moneta

Я пытаюсь Json сериализовать POJO с полем MonetaryAmount в виде строки, но полученный результат не соответствует заданному формату формы.

// 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}}

Есть идеи, что я делаю не так? Я добавил сюда кухонную раковину в этом коде, только для наглядности и компактности.

1 ответ

Решение

JsonFormat - это аннотация, используемая в нескольких (де) сериализаторах, определенных Джексоном (например, DateTimeSerializerBase, NumberSerializers.Base и некоторые другие, полный список здесь), это не механизм общего назначения, превращающий любой объект в строку:

В отличие от большинства других аннотаций Джексона, аннотация не имеет определенной универсальной интерпретации: вместо этого эффект зависит от типа данных аннотируемого свойства (или, более конкретно, используемых десериализатора и сериализатора).

Указание этого не будет иметь никакого эффекта, если вы не создадите пользовательский сериализатор для MonetaryAmount или используйте тот, который использует эту аннотацию (а также его pattern свойство), но если вы создадите пользовательский сериализатор, скорее всего, вам не понадобится такой уровень гибкости, чтобы указывать разные шаблоны для разных полей, и он мог бы просто использовать фиксированный MonetaryAmountFormat или построить необходимую строку из MonetaryAmount возразить иначе.

Например

@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());
        }
    }
}
Другие вопросы по тегам