Java to Jackson JSON序列化:Money字段

Con*_*Del 44 java serialization jackson

目前,我正在使用Jackson从我的基于Spring的Web应用程序发送JSON结果.

我遇到的问题是试图将所有货币字段输出为2位小数.我无法解决这个问题setScale(2),因为像25.50这样的数字被截断为25.5等

还有其他人处理过这个问题吗?我正在考虑使用自定义的Jackson序列化程序创建Money类...您可以为字段变量创建自定义序列化程序吗?你可能可以...但即使如此,我怎么能让我的客户序列化器将数字添加为2位小数的数字?

Ste*_*eve 63

您可以在货币领域使用自定义序列化程序.这是MoneyBean的一个例子.字段数量使用@JsonSerialize注释(使用= ...).

public class MoneyBean {
    //...

    @JsonProperty("amountOfMoney")
    @JsonSerialize(using = MoneySerializer.class)
    private BigDecimal amount;

    //getters/setters...
}

public class MoneySerializer extends JsonSerializer<BigDecimal> {
    @Override
    public void serialize(BigDecimal value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
            JsonProcessingException {
        // put your desired money style here
        jgen.writeString(value.setScale(2, BigDecimal.ROUND_HALF_UP).toString());
    }
}
Run Code Online (Sandbox Code Playgroud)

而已.现在以正确的方式打印BigDecimal.我使用一个简单的测试用例来显示它:

@Test
public void jsonSerializationTest() throws Exception {
     MoneyBean m = new MoneyBean();
     m.setAmount(new BigDecimal("20.3"));

     ObjectMapper mapper = new ObjectMapper();
     assertEquals("{\"amountOfMoney\":\"20.30\"}", mapper.writeValueAsString(m));
}
Run Code Online (Sandbox Code Playgroud)

  • 从业务角度来看,这是一种可怕的方法.货币不应该在序列化时间四舍五入.如果你想用尾随零*填充*(不同于盲目设置比例),那么你必须在没有`ROUND_HALF_UP`的情况下这样做.此外,不同的货币预计会有不同数量的尾随小数. (39认同)
  • 很好的方法,但它将其打印为字符串 - 而不是JSON输出中的数字类型. (6认同)
  • jro,如果在Steve的serialize()中使用writeNumber()而不是writeString(),那么该字段将在JSON中显示为数字. (4认同)
  • @MaksymBykovskyy关键不是要舍入,这是因为这些舍入规则是业务逻辑,在序列化时不应应用它们。在进行序列化之前,必须先应用它们,否则您会感到担忧。 (3认同)

Mod*_*odi 26

您可以配置一个使用特定类型的客户序列化程序的模块,而不是在每个成员或getter上设置@JsonSerialize:

SimpleModule module = new SimpleModule();
module.addSerializer(BigInteger.class, new ToStringSerializer());
objectMapper.registerModule(module);
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,我使用字符串序列化器来序列化BigIntegers(因为javascript无法处理这样的数值).


Sah*_*bra 26

您可以使用@JsonFormat批注与shapeSTRING您的BigDecimal变量.参考下文:

 import com.fasterxml.jackson.annotation.JsonFormat;

  class YourObjectClass {

      @JsonFormat(shape=JsonFormat.Shape.STRING)
      private BigDecimal yourVariable;

 }
Run Code Online (Sandbox Code Playgroud)

  • 是的,你是对的.自Jackson 2.9.5起可用此选项:https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.9.5 (3认同)

whi*_*rra 13

我是jackson-datatype-money的维护者之一,所以我可以毫不犹豫地回答这个问题.该模块应该满足您的需求,并且它非常轻量级(没有额外的运行时依赖性).此外它在提到杰克逊文档,春天文档和甚至有一些讨论已经了解如何将它集成到杰克逊的官方生态系统.


des*_*dev 6

正如Sahil Chhabra建议的那样,您可以在变量上@JsonFormat正确使用 with 。shape如果您想将其应用到BigDecimal您的每个字段中,Dto's您可以覆盖给定类的默认格式。

@Configuration
public class JacksonObjectMapperConfiguration {

    @Autowired
    public void customize(ObjectMapper objectMapper) {
         objectMapper
            .configOverride(BigDecimal.class).setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.STRING));
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我遇到了同样的问题,我将其格式化为JSON作为字符串格式。可能有点hack,但是很容易实现。

private BigDecimal myValue = new BigDecimal("25.50");
...
public String getMyValue() {
    return myValue.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
Run Code Online (Sandbox Code Playgroud)