-
-
Notifications
You must be signed in to change notification settings - Fork 134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add option to preserve zero decimals #831
Merged
Merged
Changes from 12 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
892ad8c
Add option to preserve zero decimals
1917857
scalafmt
1694da9
JDK 11 binary compatibility check
bfdf86c
revert last commit
8b17d32
fix binary compatibility, add tests for zero
6f3c176
cleanup imports, use atomic ref
2a9615e
remove import
8840aae
restore import
932f02d
fix binary compatibility, formatting
a3189c5
rename constants for consistency
004edea
fix formatting
f731f20
fix bug stripping zeros for powers of ten, add tests
6d4ac29
formatting
894ba30
explicitly throw exception from try-finally
1c4f325
remove atomic reference, document configuration
f024b1b
Update play-json/jvm/src/main/scala/play/api/libs/json/JsonConfig.scala
b64a605
fix build, rename method
5ad9f53
formatting
ae7912f
update deprecated since values
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
210 changes: 210 additions & 0 deletions
210
play-json/jvm/src/main/scala/play/api/libs/json/JsonConfig.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
/* | ||
* Copyright (C) 2009-2021 Lightbend Inc. <https://www.lightbend.com> | ||
*/ | ||
|
||
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 play.api.libs.json.JsonConfig.loadDigitsLimit | ||
import play.api.libs.json.JsonConfig.loadMathContext | ||
import play.api.libs.json.JsonConfig.loadMaxPlain | ||
import play.api.libs.json.JsonConfig.loadMinPlain | ||
import play.api.libs.json.JsonConfig.loadScaleLimit | ||
|
||
import java.math.MathContext | ||
|
||
import scala.util.control.NonFatal | ||
|
||
/** | ||
* Parse 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. */ | ||
def mathContext: MathContext | ||
|
||
/** Limits the scale, and it is related to the math context used. */ | ||
def scaleLimit: Int | ||
|
||
/** How many digits are accepted, also related to the math context used. */ | ||
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. */ | ||
def minPlain: BigDecimal | ||
|
||
/** Maximum magnitude of BigDecimal to write out as a plain string. */ | ||
def maxPlain: BigDecimal | ||
|
||
/** True to preserve zero decimals (false by default). */ | ||
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 { | ||
val defaultMathContext: MathContext = MathContext.DECIMAL128 | ||
|
||
// Limit for the scale considering the MathContext of 128 | ||
// limit for scale for decimal128: BigDecimal("0." + "0" * 33 + "1e-6143", java.math.MathContext.DECIMAL128).scale + 1 | ||
val defaultScaleLimit: Int = 6178 | ||
|
||
// 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 | ||
|
||
// Drop zero decimal by default. | ||
val defaultPreserveZeroDecimal: Boolean = false | ||
|
||
// Maximum magnitude of BigDecimal to write out as a plain string | ||
val defaultMaxPlain: BigDecimal = 1E20 | ||
|
||
// Minimum magnitude of BigDecimal to write out as a plain string | ||
val defaultMinPlain: BigDecimal = 1E-10 | ||
|
||
private[json] def loadScaleLimit: Int = parseNum("play.json.parser.scaleLimit", defaultScaleLimit)(_.toInt) | ||
|
||
private[json] def loadDigitsLimit: Int = parseNum("play.json.parser.digitsLimit", defaultDigitsLimit)(_.toInt) | ||
|
||
private[json] def loadMathContext: MathContext = parseMathContext("play.json.parser.mathContext") | ||
|
||
private[json] def loadMinPlain: BigDecimal = | ||
parseNum("play.json.serializer.minPlain", defaultMinPlain)(BigDecimal.exact) | ||
|
||
private[json] def loadMaxPlain: BigDecimal = | ||
parseNum("play.json.serializer.maxPlain", defaultMaxPlain)(BigDecimal.exact) | ||
|
||
private[json] def loadPreserveZeroDecimal: Boolean = | ||
parseNum("play.json.serializer.preserveZeroDecimal", defaultPreserveZeroDecimal)(_.toBoolean) | ||
|
||
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 parseNum[T](key: String, default: T)(f: String => T): T = | ||
trbogart marked this conversation as resolved.
Show resolved
Hide resolved
|
||
try { | ||
sys.props.get(key).map(f).getOrElse(default) | ||
} catch { | ||
case NonFatal(_) => default | ||
} | ||
} | ||
|
||
private final case class JsonConfigImpl( | ||
bigDecimalParseConfig: BigDecimalParseConfig, | ||
bigDecimalSerializerConfig: BigDecimalSerializerConfig | ||
) extends JsonConfig | ||
|
||
@deprecated("Use BigDecimalParseConfig instead", "2.10.0") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What should I use for the 2nd argument of these deprecated annotations? |
||
final case class BigDecimalParseSettings( | ||
mathContext: MathContext = MathContext.DECIMAL128, | ||
scaleLimit: Int, | ||
digitsLimit: Int | ||
) extends BigDecimalParseConfig | ||
|
||
@deprecated("Use BigDecimalSerializerConfig instead", "2.10.0") | ||
final case class BigDecimalSerializerSettings( | ||
minPlain: BigDecimal, | ||
maxPlain: BigDecimal | ||
) extends BigDecimalSerializerConfig { | ||
override def preserveZeroDecimal: Boolean = defaultPreserveZeroDecimal | ||
} | ||
|
||
@deprecated("Use JsonConfig instead", "2.10.0") | ||
final case class JsonParserSettings( | ||
bigDecimalParseSettings: BigDecimalParseSettings, | ||
bigDecimalSerializerSettings: BigDecimalSerializerSettings | ||
) extends JsonConfig { | ||
override def bigDecimalParseConfig: BigDecimalParseConfig = bigDecimalParseSettings | ||
|
||
override def bigDecimalSerializerConfig: BigDecimalSerializerConfig = bigDecimalSerializerSettings | ||
} | ||
|
||
object JsonParserSettings { | ||
val defaultMathContext: MathContext = JsonConfig.defaultMathContext | ||
|
||
// Limit for the scale considering the MathContext of 128 | ||
// limit for scale for decimal128: BigDecimal("0." + "0" * 33 + "1e-6143", java.math.MathContext.DECIMAL128).scale + 1 | ||
val defaultScaleLimit: Int = JsonConfig.defaultScaleLimit | ||
|
||
// 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 = JsonConfig.defaultDigitsLimit | ||
|
||
// Maximum magnitude of BigDecimal to write out as a plain string | ||
val MaxPlain: BigDecimal = JsonConfig.defaultMaxPlain | ||
|
||
// Minimum magnitude of BigDecimal to write out as a plain string | ||
val MinPlain: BigDecimal = JsonConfig.defaultMinPlain | ||
|
||
def apply(): JsonParserSettings = JsonParserSettings( | ||
BigDecimalParseSettings(defaultMathContext, defaultScaleLimit, defaultDigitsLimit), | ||
BigDecimalSerializerSettings(minPlain = MinPlain, maxPlain = MaxPlain) | ||
) | ||
|
||
/** | ||
* Return the default settings configured from System properties. | ||
*/ | ||
val settings: JsonParserSettings = { | ||
JsonParserSettings( | ||
BigDecimalParseSettings(loadMathContext, loadScaleLimit, loadDigitsLimit), | ||
BigDecimalSerializerSettings(loadMinPlain, loadMaxPlain) | ||
) | ||
} | ||
} |
98 changes: 0 additions & 98 deletions
98
play-json/jvm/src/main/scala/play/api/libs/json/JsonParserSettings.scala
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed from
JsonParserSettings
.I ended up using sealed traits, which I called
JsonConfig
,BigDecimalParseConfig
, andBigDecimalSerializerConfig
.