简体   繁体   English

Java 到 Jackson JSON 序列化:货币字段

[英]Java to Jackson JSON serialization: Money fields

Currently, I'm using Jackson to send out JSON results from my Spring-based web application.目前,我正在使用 Jackson 从基于 Spring 的 Web 应用程序发送 JSON 结果。

The problem I'm having is trying to get all money fields to output with 2 decimal places.我遇到的问题是试图让所有货币字段以 2 位小数输出。 I wasn't able to solve this problem using setScale(2) , as numbers like 25.50 are truncated to 25.5 etc我无法使用setScale(2)解决此问题,因为像 25.50 这样的数字被截断为 25.5 等

Has anyone else dealt with this problem?还有其他人处理过这个问题吗? I was thinking about making a Money class with a custom Jackson serializer... can you make a custom serializer for a field variable?我正在考虑使用自定义 Jackson 序列化程序制作 Money 类......你可以为字段变量制作自定义序列化程序吗? You probably can... But even still, how could I get my customer serializer to add the number as a number with 2 decimal places?你可能可以......但即便如此,我如何让我的客户序列化程序将数字添加为小数点后两位的数字?

You can use a custom serializer at your money field.您可以在 money 字段中使用自定义序列化程序。 Here's an example with a MoneyBean.下面是 MoneyBean 的示例。 The field amount gets annotated with @JsonSerialize(using=...) .字段数量@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());
    }
}

That's it.而已。 A BigDecimal is now printed in the right way.现在以正确的方式打印 BigDecimal。 I used a simple testcase to show it:我用一个简单的测试用例来展示它:

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

You can use @JsonFormat annotation with shape as STRING on your BigDecimal variables.您可以在BigDecimal变量上使用带有shape@JsonFormat注释作为STRING Refer below:参考以下:

 import com.fasterxml.jackson.annotation.JsonFormat;

  class YourObjectClass {

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

 }

Instead of setting the @JsonSerialize on each member or getter you can configure a module that use a custome serializer for a certain type:无需在每个成员或 getter 上设置 @JsonSerialize,您可以配置一个模块,该模块使用特定类型的自定义序列化程序:

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

In the above example, I used the to string serializer to serialize BigIntegers (since javascript can not handle such numeric values).在上面的例子中,我使用了 to string serializer 来序列化 BigIntegers(因为 javascript 不能处理这样的数值)。

I'm one of the maintainers of jackson-datatype-money , so take this answer with a grain of salt since I'm certainly biased.我是jackson-datatype-money的维护者之一,所以对这个答案持保留态度,因为我肯定有偏见。 The module should cover your needs and it's pretty light-weight (no additional runtime dependencies).该模块应该满足您的需求,而且它非常轻巧(没有额外的运行时依赖项)。 In addition it's mentioned in the Jackson docs , Spring docs and there were even some discussions already about how to integrate it into the official ecosystem of Jackson.此外, Jackson 文档Spring 文档中也提到了它,甚至已经有一些关于如何将其集成到 Jackson 官方生态系统中的讨论。

I had the same issue and i had it formatted into JSON as a String instead.我有同样的问题,我将它格式化为 JSON 作为字符串。 Might be a bit of a hack but it's easy to implement.可能有点 hack,但很容易实现。

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

As Sahil Chhabra suggested you can use @JsonFormat with proper shape on your variable.正如Sahil Chhabra建议的那样,您可以在变量上使用具有适当shape@JsonFormat In case you would like to apply it on every BigDecimal field you have in your Dto's you can override default format for given class.如果您想将它应用于Dto's每个BigDecimal字段,您可以覆盖给定类的默认格式。

@Configuration
public class JacksonObjectMapperConfiguration {

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

Inspired by Steve , and as the updates for Java 11. Here's how we did the BigDecimal reformatting to avoid scientific notation.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));
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM