diff --git a/play-json/jvm/src/main/scala/play/api/libs/json/jackson/JacksonJson.scala b/play-json/jvm/src/main/scala/play/api/libs/json/jackson/JacksonJson.scala index 44f0c090d..dc137c108 100644 --- a/play-json/jvm/src/main/scala/play/api/libs/json/jackson/JacksonJson.scala +++ b/play-json/jvm/src/main/scala/play/api/libs/json/jackson/JacksonJson.scala @@ -6,6 +6,7 @@ package play.api.libs.json.jackson import java.io.InputStream import java.io.StringWriter +import java.math.BigInteger import scala.annotation.switch import scala.annotation.tailrec @@ -26,6 +27,7 @@ import com.fasterxml.jackson.databind._ import com.fasterxml.jackson.databind.`type`.TypeFactory import com.fasterxml.jackson.databind.deser.Deserializers import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.node.BigIntegerNode import com.fasterxml.jackson.databind.ser.Serializers import play.api.libs.json._ @@ -67,12 +69,8 @@ sealed class PlayJsonMapperModule(jsonConfig: JsonConfig) extends SimpleModule(" // -- Serializers. private[jackson] class JsValueSerializer(jsonConfig: JsonConfig) extends JsonSerializer[JsValue] { - import java.math.BigInteger import java.math.{ BigDecimal => JBigDec } - import com.fasterxml.jackson.databind.node.BigIntegerNode - import com.fasterxml.jackson.databind.node.DecimalNode - private def stripTrailingZeros(bigDec: JBigDec): JBigDec = { val stripped = bigDec.stripTrailingZeros if (jsonConfig.bigDecimalSerializerConfig.preserveZeroDecimal && bigDec.scale > 0 && stripped.scale <= 0) { @@ -96,10 +94,11 @@ private[jackson] class JsValueSerializer(jsonConfig: JsonConfig) extends JsonSer val stripped = stripTrailingZeros(v.bigDecimal) val raw = if (shouldWritePlain) stripped.toPlainString else stripped.toString - if (raw.indexOf('E') < 0 && raw.indexOf('.') < 0) + if (raw.indexOf('E') < 0 && raw.indexOf('.') < 0) { json.writeTree(new BigIntegerNode(new BigInteger(raw))) - else - json.writeTree(new DecimalNode(new JBigDec(raw))) + } else { + json.writeTree(StringBasedNumericNode(raw)) + } } case JsString(v) => json.writeString(v) diff --git a/play-json/jvm/src/main/scala/play/api/libs/json/jackson/StringBasedNumericNode.scala b/play-json/jvm/src/main/scala/play/api/libs/json/jackson/StringBasedNumericNode.scala new file mode 100644 index 000000000..d18251738 --- /dev/null +++ b/play-json/jvm/src/main/scala/play/api/libs/json/jackson/StringBasedNumericNode.scala @@ -0,0 +1,46 @@ +/* + * Copyright (C) from 2022 The Play Framework Contributors , 2011-2021 Lightbend Inc. + */ + +package play.api.libs.json.jackson + +import com.fasterxml.jackson.core.{ JsonGenerator, JsonParser, JsonToken } +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.node.NumericNode + +import java.math.{ BigDecimal, BigInteger } + +/** + * A numeric node that is represented as a string. + * + * For internal use only. Some methods are not implemented and will throw an exception. + */ +private[jackson] case class StringBasedNumericNode(text: String) extends NumericNode { + + override def numberType: JsonParser.NumberType = JsonParser.NumberType.BIG_DECIMAL + + override def asText(): String = text + + override def asToken(): JsonToken = JsonToken.VALUE_NUMBER_FLOAT + + override def isIntegralNumber: Boolean = false + + override def serialize(jgen: JsonGenerator, ctxt: SerializerProvider): Unit = + jgen.writeNumber(text) + + override def numberValue: Number = throw new NotImplementedError + + override def intValue: Int = throw new NotImplementedError + + override def longValue: Long = throw new NotImplementedError + + override def doubleValue: Double = throw new NotImplementedError + + override def decimalValue: BigDecimal = throw new NotImplementedError + + override def bigIntegerValue: BigInteger = throw new NotImplementedError + + override def canConvertToInt: Boolean = false + + override def canConvertToLong: Boolean = false +}