61

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

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

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

4

7 回答 7

84

您可以在资金字段中使用自定义序列化程序。这是一个使用 MoneyBean 的示例。字段数量使用@JsonSerialize(using=...)进行注释。

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());
    }
}

就是这样。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));
}
于 2012-07-18T12:03:43.423 回答
42

您可以在变量上使用带有as的@JsonFormat注释。参考以下:shapeSTRINGBigDecimal

 import com.fasterxml.jackson.annotation.JsonFormat;

  class YourObjectClass {

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

 }
于 2018-08-04T09:29:29.790 回答
36

除了在每个成员或 getter 上设置 @JsonSerialize 之外,您还可以配置一个使用特定类型的自定义序列化程序的模块:

SimpleModule module = new SimpleModule();
module.addSerializer(BigInteger.class, new ToStringSerializer());
objectMapper.registerModule(module);

在上面的例子中,我使用了 to string 序列化器来序列化 BigIntegers(因为 javascript 不能处理这样的数值)。

于 2013-08-14T08:36:35.280 回答
15

我是jackson-datatype-money的维护者之一,所以我对这个答案持保留态度,因为我当然有偏见。该模块应该满足您的需求并且它非常轻量级(没有额外的运行时依赖项)。此外,Jackson 文档Spring 文档中都提到了它,甚至已经讨论了如何将其集成到 Jackson 的官方生态系统中。

于 2016-06-05T23:53:09.760 回答
5

我有同样的问题,我把它格式化为 JSON 作为一个字符串。可能有点小技巧,但很容易实现。

private BigDecimal myValue = new BigDecimal("25.50");
...
public String getMyValue() {
    return myValue.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
于 2012-08-15T11:11:35.220 回答
2

正如Sahil Chhabra建议的那样,您可以在变量上使用@JsonFormat适当的。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));
    }
}
于 2020-02-27T18:50:41.500 回答
1

Steve启发,并作为 Java 11 的更新。这是我们如何进行 BigDecimal 重新格式化以避免科学记数法。

public class PriceSerializer extends JsonSerializer<BigDecimal> {
    @Override
    public void serialize(BigDecimal value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        // Using writNumber and removing toString make sure the output is number but not String.
        jgen.writeNumber(value.setScale(2, RoundingMode.HALF_UP));
    }
}
于 2020-12-01T01:59:55.330 回答