はじめに
SpringBootを用いたWebAPIの開発において、Jacksonを用いているのですが、BigDecimal型の値をレスポンスとして返却する際に課題に直面しました。
それは、小数点以下の連続した0が残ったまま表示されてしまうということです。
例えばPostgresSQLのnumeric型(10, 5)のカラムに「99.9」と値が登録されているとして、この値を取得してJSONで返す場合、BigDecimal型で扱い返却すると「99.90000」と表示されてしまいます。
今回はこの事象を解決したので、記事にしました。
解決法
まず、下記のBigDecimalSerializer.javaのようなBigDecimal型に対するシリアライザーを作成します。作成時にはStdSerializer
クラスを継承し、ジェネリクスに値を操作する対象のクラスを指定する必要があります。
public class BigDecimalSerializer extends StdSerializer<BigDecimal> {
public BigDecimalSerializer() {
this(null);
}
public BigDecimalSerializer(Class<BigDecimal> c) {
super(c);
}
@Override
public void serialize(BigDecimal bigDecimal, JsonGenerator generator, SerializerProvider provider) throws IOException {
generator.writeNumber(new BigDecimal(bigDecimal.stripTrailingZeros().toPlainString()));
}
}
serialize
メソッドの中で、JsonGenerator
クラスのwriteNumber
メソッドを用いることによって、BigDecimal型の値に対してどのような値に変換するかを指定してあげることができます。
今回はBigDecimal
クラスのstripTrailingZeros
メソッドを用いて小数点以下の0を削除しました。
ただし、このメソッドは公式ドキュメントにもあるように、例えば600.0に対して用いた場合、結果が6E2と指数標記になってしまいます。
そこで、さらにBigDecimal
クラスのtoPlainString
メソッドを用いることで指数標記ではない形式にしました。
あとは下記のように先程作成したBigDecimalSerializer
クラスを用いたJsonSerialize
アノテーションをレスポンスとして返却するクラスのフィールドに付与してあげれば、小数点以下の0を取り除いた状態で表示してくれます。
public class CalculationResult {
@JsonSerialize(using = BigDecimalSerializer.class)
private BigDecimal value;
}
まとめ
StdSerializer
クラスを継承するクラスを作成し、serialize
メソッドに変換ロジックを記載することで、独自のシリアライザーを作成することができます。
レスポンスとして返却するクラスのフィールドにJsonSerialize
アノテーションを付与し、作成したシリアライザーを指定することで、返却する値をカスタムすることができます。
この記事が少しでも誰かのお役に立てれば幸いです。
最後までお読みいただきありがとうございました。
参考文献
シリアライザーをカスタムする方法
https://www.baeldung.com/jackson-custom-serialization
toPlainStringについて
https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/math/BigDecimal.html#toPlainString()
https://qiita.com/shotana/items/e02357516798e6bc658e