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..9c7d1edce 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,7 +27,9 @@ 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 com.fasterxml.jackson.databind.util.TokenBuffer import play.api.libs.json._ @@ -67,12 +70,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 +95,15 @@ 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) - json.writeTree(new BigIntegerNode(new BigInteger(raw))) + if (raw.exists(c => c == 'E' || c == '.')) + json.writeNumber(raw) else - json.writeTree(new DecimalNode(new JBigDec(raw))) + json match { + case _: TokenBuffer => + json.writeTree(new BigIntegerNode(new BigInteger(raw))) + case _ => + json.writeNumber(raw) + } } case JsString(v) => json.writeString(v) diff --git a/play-json/jvm/src/test/scala/play/api/libs/json/JsonSpec.scala b/play-json/jvm/src/test/scala/play/api/libs/json/JsonSpec.scala index 8411c61ea..03bf83184 100644 --- a/play-json/jvm/src/test/scala/play/api/libs/json/JsonSpec.scala +++ b/play-json/jvm/src/test/scala/play/api/libs/json/JsonSpec.scala @@ -4,6 +4,7 @@ package play.api.libs.json +import java.math.BigInteger import java.util.Calendar import java.util.Date import java.util.TimeZone @@ -477,6 +478,55 @@ class JsonSpec extends org.specs2.mutable.Specification { fromJson[JsonNode](jsNum).map(_.toString).must_==(JsSuccess("12.345")) } + "Serialize JsNumbers with integers correctly" in { + val numStrings = Seq( + "0", + "1", + "-1", + Int.MaxValue.toString, + Int.MinValue.toString, + Long.MaxValue.toString, + Long.MinValue.toString, + BigInteger.valueOf(Long.MaxValue).add(BigInteger.ONE).toString, + BigInteger.valueOf(Long.MinValue).add(BigInteger.valueOf(-1)).toString + ) + numStrings.map { numString => + val bigDec = new java.math.BigDecimal(numString) + Json.stringify(JsNumber(bigDec)).must_==(bigDec.toString) + } + } + + "Serialize JsNumbers with decimal points correctly" in { + val numStrings = Seq( + "0.123", + "1.23456789", + "-1.23456789", + Float.MaxValue.toString, + Float.MinValue.toString, + Double.MaxValue.toString, + Double.MinValue.toString, + java.math.BigDecimal.valueOf(Double.MaxValue).add(java.math.BigDecimal.valueOf(1)).toString, + java.math.BigDecimal.valueOf(Double.MinValue).add(java.math.BigDecimal.valueOf(-1)).toString + ) + numStrings.map { numString => + val bigDec = new java.math.BigDecimal(numString) + Json.stringify(JsNumber(bigDec)).must_==(bigDec.toString) + } + } + + "Serialize JsNumbers with e notation correctly" in { + val numStrings = Seq( + "1.23456789012345679012345679e999", + "-1.23456789012345679012345679e999", + "1.23456789012345679012345679e-999", + "-1.23456789012345679012345679e-999" + ) + numStrings.map { numString => + val bigDec = new java.math.BigDecimal(numString) + Json.stringify(JsNumber(bigDec)).must_==(bigDec.toString) + } + } + "parse from InputStream" in { val js = Json.obj( "key1" -> "value1",