diff --git a/json/json-core/src/main/scala/io/sphere/json/SphereJsonParser.scala b/json/json-core/src/main/scala/io/sphere/json/SphereJsonParser.scala new file mode 100644 index 00000000..0f6bcff0 --- /dev/null +++ b/json/json-core/src/main/scala/io/sphere/json/SphereJsonParser.scala @@ -0,0 +1,16 @@ +package io.sphere.json + +import com.fasterxml.jackson.databind.DeserializationFeature.{USE_BIG_DECIMAL_FOR_FLOATS, USE_BIG_INTEGER_FOR_INTS} +import com.fasterxml.jackson.databind.ObjectMapper +import org.json4s.jackson.{Json4sScalaModule, JsonMethods} + +// extends the default JsonMethods to configure a different default jackson parser +private object SphereJsonParser extends JsonMethods { + override val mapper: ObjectMapper = { + val m = new ObjectMapper() + m.registerModule(new Json4sScalaModule) + m.configure(USE_BIG_INTEGER_FOR_INTS, false) + m.configure(USE_BIG_DECIMAL_FOR_FLOATS, false) + m + } +} diff --git a/json/json-core/src/main/scala/io/sphere/json/ToJSON.scala b/json/json-core/src/main/scala/io/sphere/json/ToJSON.scala index e3fa0d8a..e2308e4b 100644 --- a/json/json-core/src/main/scala/io/sphere/json/ToJSON.scala +++ b/json/json-core/src/main/scala/io/sphere/json/ToJSON.scala @@ -59,7 +59,7 @@ object ToJSON { } implicit val intWriter: ToJSON[Int] = new ToJSON[Int] { - def write(i: Int): JValue = JInt(i) + def write(i: Int): JValue = JLong(i) } implicit val stringWriter: ToJSON[String] = new ToJSON[String] { @@ -71,11 +71,11 @@ object ToJSON { } implicit val shortWriter: ToJSON[Short] = new ToJSON[Short] { - def write(s: Short): JValue = JInt(s) + def write(s: Short): JValue = JLong(s) } implicit val longWriter: ToJSON[Long] = new ToJSON[Long] { - def write(l: Long): JValue = JInt(l) + def write(l: Long): JValue = JLong(l) } implicit val floatWriter: ToJSON[Float] = new ToJSON[Float] { diff --git a/json/json-core/src/main/scala/io/sphere/json/package.scala b/json/json-core/src/main/scala/io/sphere/json/package.scala index 5c9c322e..90581802 100644 --- a/json/json-core/src/main/scala/io/sphere/json/package.scala +++ b/json/json-core/src/main/scala/io/sphere/json/package.scala @@ -3,8 +3,8 @@ package io.sphere import cats.data.Validated.{Invalid, Valid} import cats.data.{NonEmptyList, ValidatedNel} import com.fasterxml.jackson.core.JsonParseException +import com.fasterxml.jackson.core.exc.InputCoercionException import com.fasterxml.jackson.databind.JsonMappingException - import io.sphere.util.Logging import org.json4s.{DefaultFormats, JsonInput, StringInput} import org.json4s.JsonAST._ @@ -19,10 +19,11 @@ package object json extends Logging { type JValidation[A] = ValidatedNel[JSONError, A] def parseJSON(json: JsonInput): JValidation[JValue] = - try Valid(parseJson(json)) catch { + try Valid(SphereJsonParser.parse(json, useBigDecimalForDouble = false, useBigIntForLong = false)) catch { case e: ParseException => jsonParseError(e.getMessage) case e: JsonMappingException => jsonParseError(e.getOriginalMessage) case e: JsonParseException => jsonParseError(e.getOriginalMessage) + case e: InputCoercionException => jsonParseError(e.getOriginalMessage) } def parseJSON(json: String): JValidation[JValue] = diff --git a/json/json-core/src/test/scala/io/sphere/json/BigNumberParsingSpec.scala b/json/json-core/src/test/scala/io/sphere/json/BigNumberParsingSpec.scala new file mode 100644 index 00000000..e2a4f15d --- /dev/null +++ b/json/json-core/src/test/scala/io/sphere/json/BigNumberParsingSpec.scala @@ -0,0 +1,24 @@ +package io.sphere.json + +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec + +class BigNumberParsingSpec extends AnyWordSpec with Matchers { + import BigNumberParsingSpec._ + + "parsing a big number" should { + "not take much time when parsed as Double" in { + fromJSON[Double](bigNumberAsString).isValid should be (false) + } + "not take much time when parsed as Long" in { + fromJSON[Long](bigNumberAsString).isValid should be (false) + } + "not take much time when parsed as Int" in { + fromJSON[Int](bigNumberAsString).isValid should be (false) + } + } +} + +object BigNumberParsingSpec { + private val bigNumberAsString = "9" * 10000000 +} diff --git a/json/json-core/src/test/scala/io/sphere/json/ToJSONSpec.scala b/json/json-core/src/test/scala/io/sphere/json/ToJSONSpec.scala index 38280a38..42e11b62 100644 --- a/json/json-core/src/test/scala/io/sphere/json/ToJSONSpec.scala +++ b/json/json-core/src/test/scala/io/sphere/json/ToJSONSpec.scala @@ -25,7 +25,7 @@ class ToJSONSpec extends AnyWordSpec with Matchers { json must be (JObject(List( "id" -> JString(id.toString), "first_name" -> JString("bidule"), - "age" -> JInt(109) + "age" -> JLong(109) ))) } } diff --git a/json/json-derivation/src/test/scala/io/sphere/json/ForProductNSpec.scala b/json/json-derivation/src/test/scala/io/sphere/json/ForProductNSpec.scala index 073fbc62..ab081d8a 100644 --- a/json/json-derivation/src/test/scala/io/sphere/json/ForProductNSpec.scala +++ b/json/json-derivation/src/test/scala/io/sphere/json/ForProductNSpec.scala @@ -26,7 +26,7 @@ class ForProductNSpec extends AnyWordSpec with Matchers { json must be (JObject(List( "id" -> JString(id.toString), "first_name" -> JString("bidule"), - "age" -> JInt(109) + "age" -> JLong(109) ))) } } diff --git a/json/json-derivation/src/test/scala/io/sphere/json/TypesSwitchSpec.scala b/json/json-derivation/src/test/scala/io/sphere/json/TypesSwitchSpec.scala index 6cccab53..ab41a520 100644 --- a/json/json-derivation/src/test/scala/io/sphere/json/TypesSwitchSpec.scala +++ b/json/json-derivation/src/test/scala/io/sphere/json/TypesSwitchSpec.scala @@ -18,7 +18,7 @@ class TypesSwitchSpec extends AnyWordSpec with Matchers { val jsons = m.map(Message.json.write) jsons must be (List( - JObject("number" -> JInt(23), "type" -> JString("ClassA1")), + JObject("number" -> JLong(23), "type" -> JString("ClassA1")), JObject("name" -> JString("world"), "type" -> JString("ClassA2")), JObject("valid" -> JBool(false), "type" -> JString("ClassB1")), JObject("references" -> JArray(List(JString("a23"), JString("c62"))), "type" -> JString("ClassB2"))))