Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ permissions:
jobs:
release:
uses: evolution-gaming/scala-github-actions/.github/workflows/release.yml@999c04ccae0d79a8a0c12ed7d71136762b2ae8c1 # v7.1.0
with:
verify_sbt_command: 'cleanFull; +check; +all testFull package'
Comment on lines +14 to +15

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need this? is it because the common has:

      verify_sbt_command:
        description: 'sbt command for verifying the build before publishing'
        type: string
        default: '+clean; +check; +all test package'

If so, then we must update the Release workflow!

secrets: inherit
58 changes: 41 additions & 17 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import Dependencies.*

import scala.collection.Seq

val Scala213 = "2.13.16"
val Scala3 = "3.3.8"

Expand Down Expand Up @@ -39,9 +37,9 @@ ThisBuild / versionPolicyIntention := Compatibility.BinaryCompatible

val alias: Seq[sbt.Def.Setting[?]] =
// the Scala version is left to the caller, since CI runs `check` once per version in its matrix
addCommandAlias("check", "all scalafmtCheckRepo versionPolicyCheck Compile/doc") ++
addCommandAlias("check", "; scalafmtCheckRepo; all versionPolicyCheck Compile/doc") ++
addCommandAlias("fmt", "scalafmtRepo") ++
addCommandAlias("build", "+all compile test")
addCommandAlias("build", "+all compile testFull")

lazy val root = project
.in(file("."))
Expand All @@ -50,7 +48,7 @@ lazy val root = project
.settings(
commonSettings,
publish / skip := true,
name := "play-json-tools"
name := "play-json-tools "
)
.aggregate(
`play-json-tools`,
Expand Down Expand Up @@ -84,6 +82,17 @@ lazy val `play-json-generic` = crossProject(JVMPlatform, JSPlatform)
Seq()
})).map(excludeLog4j)
)
.jsSettings(
coverageEnabled := false,
versionPolicyIgnored ++= Seq(
"org.scala-lang" %% "scala3-library",
"com.chuusai" %% "shapeless",
"org.playframework" %% "play-json",
"org.playframework" %% "play-functional",
"com.fasterxml.jackson.datatype" % "jackson-datatype-jdk8",
"com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310"
)
)

lazy val `play-json-tools` = project
.settings(
Expand All @@ -107,24 +116,39 @@ lazy val `play-json-jsoniter` = crossProject(JVMPlatform, JSPlatform)
commonSettings,
allowUnsafeScalaLibUpgrade := true,
libraryDependencies ++=
(Seq(
Seq(
playJson,
jackson.core,
jackson.databind,
jsoniter,
collectionCompact,
scalaTest % Test
) ++
(CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, _)) =>
Seq(
jsonGenerator % Test,
jsonValues % Test,
scalacheck % Test
)
case _ =>
Seq()
})).map(excludeLog4j)
).map(excludeLog4j)
)
.jsSettings(
coverageEnabled := false,
versionPolicyIgnored ++= Seq(
"org.scala-lang" %% "scala3-library",
"org.playframework" %% "play-json",
"org.playframework" %% "play-functional",
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core",
"org.scala-lang.modules" %% "scala-collection-compat",
"com.fasterxml.jackson.datatype" % "jackson-datatype-jdk8",
"com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310"
)
)
.jvmSettings(
libraryDependencies ++=
(CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, _)) =>
Seq(
jsonGenerator % Test,
jsonValues % Test,
scalacheck % Test
)
case _ =>
Seq()
}).map(excludeLog4j)
)

// not part of the aggregate, benchmarks are run manually
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object NameCodingStrategy extends LowPriority
object NameCodingStrategies {

private def lowerCaseSepCoding(sep: String): NameCodingStrategy = new NameCodingStrategy() {
override def apply(s: String): String = s.split("(?<!^)(?=[A-Z])").map(_.toLowerCase).mkString(sep)
override def apply(s: String): String = s.split("(?=[A-Z])").map(_.toLowerCase).mkString(sep)
}

implicit val kebabCase: NameCodingStrategy = lowerCaseSepCoding("-")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
/*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall we add the comment that this file is copy-paste from play-json's JsonConfig.scala with dropped deprecations?

and we should explain, why the original isn't enough here!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

* Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
*/

/*
* Copied from play-json 3.0.6 `play-json/jvm/src/main/scala/play/api/libs/json/JsonConfig.scala` with deprecated members dropped.
* play-json keeps it in the JVM-only sources, so its Scala.js artifact lacks it, while the shared `JsonValueCodecJsValue` needs it.
*/

package play.api.libs.json

import play.api.libs.json.JsonConfig.defaultMaxPlain
import play.api.libs.json.JsonConfig.defaultMinPlain
import play.api.libs.json.JsonConfig.defaultDigitsLimit
import play.api.libs.json.JsonConfig.defaultMathContext
import play.api.libs.json.JsonConfig.defaultPreserveZeroDecimal
import play.api.libs.json.JsonConfig.defaultScaleLimit

import java.math.MathContext

import scala.util.control.NonFatal

/** Parse and serialization settings for BigDecimals. Defines limits that will be used when parsing the BigDecimals,
* like how many digits are accepted.
*/
sealed trait BigDecimalParseConfig {

/** The `MathContext` used when parsing, which will be "decimal32", "decimal64", "decimal128" (default),
* or "unlimited".
* This can be set using the [[JsonConfig.mathContextProperty]] system property.
*/
def mathContext: MathContext

/** Limits the scale, and it is related to the math context used.
* The default value is [[JsonConfig.defaultScaleLimit]].
* This can be set using the [[JsonConfig.scaleLimitProperty]] system property.
*/
def scaleLimit: Int

/** How many digits are accepted, also related to the math context used.
* The default value is [[JsonConfig.defaultDigitsLimit]].
* This can be set using the [[JsonConfig.digitsLimitProperty]] system property.
*/
def digitsLimit: Int
}

object BigDecimalParseConfig {
def apply(
mathContext: MathContext = defaultMathContext,
scaleLimit: Int = defaultScaleLimit,
digitsLimit: Int = defaultDigitsLimit
): BigDecimalParseConfig = BigDecimalParseConfigImpl(mathContext, scaleLimit, digitsLimit)
}

private final case class BigDecimalParseConfigImpl(mathContext: MathContext, scaleLimit: Int, digitsLimit: Int)
extends BigDecimalParseConfig

sealed trait BigDecimalSerializerConfig {

/** Minimum magnitude of BigDecimal to write out as a plain string.
* Defaults to [[JsonConfig.defaultMinPlain]].
* This can be set using the [[JsonConfig.minPlainProperty]] system property.
*/
def minPlain: BigDecimal

/** Maximum magnitude of BigDecimal to write out as a plain string.
* Defaults to [[JsonConfig.defaultMaxPlain]].
* This can be set using the [[JsonConfig.maxPlainProperty]] system property.
*/
def maxPlain: BigDecimal

/** True to preserve a zero decimal , or false to drop them (the default).
* For example, 1.00 will be serialized as 1 if false or 1.0 if true (only a single zero is preserved).
* Other trailing zeroes will be dropped regardless of this value.
* For example, 1.1000 will always be serialized as 1.1.
* This can be set using the [[JsonConfig.preserveZeroDecimalProperty]] system property.
*/
def preserveZeroDecimal: Boolean
}

object BigDecimalSerializerConfig {
def apply(
minPlain: BigDecimal = defaultMinPlain,
maxPlain: BigDecimal = defaultMaxPlain,
preserveZeroDecimal: Boolean = defaultPreserveZeroDecimal
): BigDecimalSerializerConfig =
DecimalSerializerSettingsImpl(minPlain, maxPlain, preserveZeroDecimal)
}

private final case class DecimalSerializerSettingsImpl(
minPlain: BigDecimal,
maxPlain: BigDecimal,
preserveZeroDecimal: Boolean
) extends BigDecimalSerializerConfig

sealed trait JsonConfig {
def bigDecimalParseConfig: BigDecimalParseConfig
def bigDecimalSerializerConfig: BigDecimalSerializerConfig
}

object JsonConfig {

/** The default math context ("decimal128").
*/
val defaultMathContext: MathContext = MathContext.DECIMAL128

/** The default limit for the scale considering the default MathContext of decimal128.
* limit for scale for decimal128: BigDecimal("0." + "0" * 33 + "1e-6143", java.math.MathContext.DECIMAL128).scale + 1
*/
val defaultScaleLimit: Int = 6178

/** The default limit for digits considering the default MathContext of decimal128.
* 307 digits should be the correct value for 128 bytes. But we are using 310
* because Play JSON uses BigDecimal to parse any number including Doubles and
* Doubles max value has 309 digits, so we are using 310 here
*/
val defaultDigitsLimit: Int = 310

/** Zero decimal values (e.g. .0 or .00) or dropped by default.
* For example, a value of 1.0 or 1.00 will be serialized as 1.
*/
val defaultPreserveZeroDecimal: Boolean = false

/** The default maximum magnitude of BigDecimal to write out as a plain string.
*/
val defaultMaxPlain: BigDecimal = 1e20

/** The default minimum magnitude of BigDecimal to write out as a plain string.
*/
val defaultMinPlain: BigDecimal = 1e-10

/** The system property to override the scale limit.
*/
val scaleLimitProperty: String = "play.json.parser.scaleLimit"

/** The system property to override the digits limit
*/
val digitsLimitProperty: String = "play.json.parser.digitsLimit"

/** The system property to override the math context. This can be "decimal32", "decimal64", "decimal128" (the default),
* or "unlimited".
*/
val mathContextProperty: String = "play.json.parser.mathContext"

/** The system property to override the minimum magnitude of BigDecimal to write out as a plain string
*/
val minPlainProperty: String = "play.json.serializer.minPlain"

/** The system property to override the maximum magnitude of BigDecimal to write out as a plain string
*/
val maxPlainProperty: String = "play.json.serializer.maxPlain"

/** The system property to override whether zero decimals (e.g. .0 or .00) are written by default. These are dropped by default.
*/
val preserveZeroDecimalProperty: String = "play.json.serializer.preserveZeroDecimal"

private[json] def loadScaleLimit: Int = prop(scaleLimitProperty, defaultScaleLimit)(_.toInt)

private[json] def loadDigitsLimit: Int = prop(digitsLimitProperty, defaultDigitsLimit)(_.toInt)

private[json] def loadMathContext: MathContext = parseMathContext(mathContextProperty)

private[json] def loadMinPlain: BigDecimal = prop(minPlainProperty, defaultMinPlain)(BigDecimal.exact)

private[json] def loadMaxPlain: BigDecimal = prop(maxPlainProperty, defaultMaxPlain)(BigDecimal.exact)

private[json] def loadPreserveZeroDecimal: Boolean =
prop(preserveZeroDecimalProperty, defaultPreserveZeroDecimal)(_.toBoolean)

// Default settings, which can be controlled with system properties.
val settings: JsonConfig =
JsonConfig(
BigDecimalParseConfig(loadMathContext, loadScaleLimit, loadDigitsLimit),
BigDecimalSerializerConfig(loadMinPlain, loadMaxPlain, loadPreserveZeroDecimal)
)

def apply(): JsonConfig = apply(BigDecimalParseConfig(), BigDecimalSerializerConfig())

def apply(
bigDecimalParseConfig: BigDecimalParseConfig,
bigDecimalSerializerConfig: BigDecimalSerializerConfig
): JsonConfig =
JsonConfigImpl(bigDecimalParseConfig, bigDecimalSerializerConfig)

private[json] def parseMathContext(key: String): MathContext = sys.props.get(key).map(_.toLowerCase) match {
case Some("decimal128") => MathContext.DECIMAL128
case Some("decimal64") => MathContext.DECIMAL64
case Some("decimal32") => MathContext.DECIMAL32
case Some("unlimited") => MathContext.UNLIMITED
case _ => defaultMathContext
}

private[json] def prop[T](key: String, default: T)(f: String => T): T =
try {
sys.props.get(key).map(f).getOrElse(default)
} catch {
case NonFatal(_) => default
}
}

private final case class JsonConfigImpl(
bigDecimalParseConfig: BigDecimalParseConfig,
bigDecimalSerializerConfig: BigDecimalSerializerConfig
) extends JsonConfig
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version = 1.13.0
sbt.version = 2.0.10
Loading