Serialize a Double to 2 decimal places using Jackson
Solution 1:
I know that
Double
should not be used as a monetary amount. However, this is not my code.
Indeed, it should not. BigDecimal
is a much better choice for storing monetary amounts because it is lossless and provides more control of the decimal places.
So for people who do have control over the code, it can be used like this:
double amount = 111.222;
setAmount(new BigDecimal(amount).setScale(2, BigDecimal.ROUND_HALF_UP));
That will serialize as 111.22
. No custom serializers needed.
Solution 2:
I had a similar situation in my project. I had added the formatting code to the setter method of the POJO. DecimalFormatter, Math and other classes ended up rounding off the value, however, my requirement was not to round off the value but only to limit display to 2 decimal places.
I recreated this scenario.
Product is a POJO which has a member Double amount
.
JavaToJSON is a class that will create an instance of Product and convert it to JSON.
The setter setAmount
in Product
will take care of formatting to 2 decimal places.
Here is the complete code.
Product.java
package com;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Product {
private String name;
private Double amount;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
BigDecimal bd = new BigDecimal(amount).setScale(2, RoundingMode.FLOOR);
this.amount = bd.doubleValue();
}
@Override
public String toString() {
return "Product [name=" + name + ", amount=" + amount + "]";
}
}
JavaToJSON.java
package com;
import java.io.File;
import java.io.IOException;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
public class JavaToJSON {
public static void main(String[] args){
ObjectMapper mapper = new ObjectMapper();
try {
Product product = new Product();
product.setName("TestProduct");
product.setAmount(Double.valueOf("459.99999999999994"));
// Convert product to JSON and write to file
mapper.writeValue(new File("d:\\user.json"), product);
// display to console
System.out.println(product);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I haven't accumulated enough points so I am not able to upload the screenshots to show you the output.
Hope this helps.
Solution 3:
Regarding what was stated above, I just wanted to fix a little something, so that people won't waste time on it as I did. One should actually use
BigDecimal.valueOf(amount).xxx
instead of
new BigDecimal(amount).xxx
and this is actually somehow critical. Because if you don't, your decimal amount will be messed up. This is a limitation of floating point representation, as stated here.