Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@mkljakubowski
Copy link
Contributor

@mkljakubowski mkljakubowski commented Sep 6, 2016

Possible fix for #6530

Fixes serialization of BigDecimals to json in some particular case which was failing

@mkljakubowski mkljakubowski force-pushed the js-big-decimal-serialization branch from f65ef0b to 3b6ef2f Compare September 6, 2016 12:56
@mkljakubowski mkljakubowski changed the title Fixes serialization of big decimals to json (#6420) Fixes serialization of big decimals to json (#6530) Sep 6, 2016
@mkljakubowski mkljakubowski force-pushed the js-big-decimal-serialization branch 2 times, most recently from 1477283 to b0be989 Compare September 6, 2016 13:02
val stripped = v.bigDecimal.stripTrailingZeros
val raw = if (shouldWritePlain) stripped.toPlainString else stripped.toString

if (raw contains ".") json.writeTree(new DecimalNode(new JBigDec(raw)))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this was checking if number contains a . but 2e128 has no dot and still needs to be printed as BigDecimal

Copy link
Member

@gmethvin gmethvin Sep 9, 2016

Choose a reason for hiding this comment

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

I'm suggesting we remove the conditional and write as:

json.writeTree(new DecimalNode(new JBigDec(raw)))

Because of the formatting logic above, raw should be written as a plain string for a number within the range such as 50.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunetly this breaks the tests as well. Whole issue is around jackson not beaing able to print 50 as bigdecimal and that's why we have this if to print it as bigInt.

Copy link
Member

Choose a reason for hiding this comment

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

Oops. I guess I didn't notice that Jackson had that special case.

@gmethvin
Copy link
Member

gmethvin commented Sep 6, 2016

Thanks. Maybe now we should just always use BigDecimal? It would make the logic a lot simpler and I'm not sure if we get much benefit from using BigInteger in some cases, as long as we know the number is being printed properly.

@mkljakubowski
Copy link
Contributor Author

mkljakubowski commented Sep 7, 2016

Yes, this code seems a bit overcomplicated. Let me check if using BigDecimal always will not cause any huge regression.

@mkljakubowski mkljakubowski force-pushed the js-big-decimal-serialization branch from b0be989 to beb751e Compare September 7, 2016 08:48
@mkljakubowski
Copy link
Contributor Author

Ok, simplified code still works, but reintroduces #3784 which is still questionable. Imo makes no difference. 50 == 5e+1

Updating jackson didn't help.

val stripped = v.bigDecimal.stripTrailingZeros
val raw = if (shouldWritePlain) stripped.toPlainString else stripped.toString

if (raw contains ".") json.writeTree(new DecimalNode(new JBigDec(raw)))
Copy link
Member

Choose a reason for hiding this comment

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

We still want to write a DecimalNode though, to preserve the formatting.

@gmethvin
Copy link
Member

gmethvin commented Sep 7, 2016

I don't think it makes a difference either but I'd rather avoid people complaining about the formatting change.

@mkljakubowski mkljakubowski force-pushed the js-big-decimal-serialization branch from beb751e to fa815ae Compare September 8, 2016 08:33
"com.fasterxml.jackson.datatype" % "jackson-datatype-jdk8",
"com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310"
).map(_ % "2.7.6")
).map(_ % "2.8.2")
Copy link
Member

Choose a reason for hiding this comment

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

In master this should be okay but I think minor versions of Jackson can have breaking changes, so I'd rather not upgrade in 2.5.x/2.4.x. I'd suggest we do this change in another PR so we can easily backport this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted. Do you want me move this PR to 2.5.x branch? It's were the bug is after all.

Copy link
Contributor

Choose a reason for hiding this comment

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

actually we backport things by cherry-pick the commit from master. and if that's not possible we manually adjust it.

@mkljakubowski mkljakubowski force-pushed the js-big-decimal-serialization branch from fa815ae to ee653bb Compare September 8, 2016 09:52
"Deserialize integer JsNumber as Jackson number node" in {
val jsNum = JsNumber(new java.math.BigDecimal("50"))
fromJson[JsonNode](jsNum).map(_.toString) must_== JsSuccess("50")
fromJson[JsonNode](jsNum).map(_.toString) must_== JsSuccess("5E+1")
Copy link
Member

@gmethvin gmethvin Sep 8, 2016

Choose a reason for hiding this comment

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

Can you update the code so this passes again? It's fine to only use BigDecimal but I don't want to screw up the formatting behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I'm on it. Will be fixed today.
I also started looking in jackson for the solution but with no luck so far.

@mkljakubowski
Copy link
Contributor Author

mkljakubowski commented Sep 9, 2016

So the issue is I think in Jackson. This is the only piece that seems to fail:
JacksonJson.jsValueToJsonNode(JsNumber(new java.math.BigDecimal("50"))).toString == "5e+1"
But if you read JsNumber instead of JsonNode everything is fine.

@mkljakubowski mkljakubowski force-pushed the js-big-decimal-serialization branch 2 times, most recently from a6e4e10 to 022d6f0 Compare September 9, 2016 11:19
@gmethvin
Copy link
Member

gmethvin commented Sep 9, 2016

@mkljakubowski The reason for reading as JsonNode was to see how it was printed in the JSON. It seems like when Jackson parses back the number it doesn't preserve the formatting.

Can you just put back all of the old code besides the special case for integers that was causing the bug? I think that will fix it.

@mkljakubowski mkljakubowski force-pushed the js-big-decimal-serialization branch from 022d6f0 to d08f674 Compare September 9, 2016 11:27
@mkljakubowski
Copy link
Contributor Author

@gmethvin reverted old code
So in this case, until jackson is fixed we need to have the condition to check how the value should be printed (bigDec or bigInt).

val raw = if (shouldWritePlain) stripped.toPlainString else stripped.toString

if (raw contains ".") json.writeTree(new DecimalNode(new JBigDec(raw)))
if (raw.exists(ch => ".eE".contains(ch))) json.writeTree(new DecimalNode(new JBigDec(raw)))
Copy link
Member

Choose a reason for hiding this comment

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

Given that this is common code path, maybe the most optimal way to write it is:

if (raw.indexOf('E') < 0 && raw.indexOf('.') < 0) {
  json.writeTree(new BigIntegerNode(new JBigInt(raw)))
}
json.writeTree(new DecimalNode(new JBigDec(raw)))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@mkljakubowski mkljakubowski force-pushed the js-big-decimal-serialization branch from d08f674 to c2b82e2 Compare September 9, 2016 12:26
@gmethvin gmethvin merged commit 2a42231 into playframework:master Sep 11, 2016
@gmethvin gmethvin added this to the 2.5.7 milestone Sep 12, 2016
wsargent pushed a commit to wsargent/playframework that referenced this pull request Oct 25, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants