IGNITE-5335: Binary serialization: fixed reading of negative decimal values. This closes #2034.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/fd838d5e Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/fd838d5e Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/fd838d5e Branch: refs/heads/ignite-5075 Commit: fd838d5e2d29d6b1a0d0b68bef013013030c8275 Parents: fbf0e35 Author: Sergey Kalashnikov <[email protected]> Authored: Fri Jun 2 14:28:41 2017 +0300 Committer: devozerov <[email protected]> Committed: Fri Jun 2 14:28:41 2017 +0300 ---------------------------------------------------------------------- .../ignite/internal/binary/BinaryFieldImpl.java | 10 ++-- .../internal/binary/BinaryObjectImpl.java | 10 ++-- .../binary/BinaryObjectOffheapImpl.java | 10 ++-- .../binary/BinaryFieldExtractionSelfTest.java | 52 ++++++++++++++++++++ .../binary/BinaryMarshallerSelfTest.java | 36 ++++++++++++-- 5 files changed, 101 insertions(+), 17 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/fd838d5e/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java index 477ae37..c318397 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryFieldImpl.java @@ -222,13 +222,15 @@ public class BinaryFieldImpl implements BinaryFieldEx { buf.get(data); - BigInteger intVal = new BigInteger(data); + boolean negative = data[0] < 0; + + if (negative) + data[0] &= 0x7F; - if (scale < 0) { - scale &= 0x7FFFFFFF; + BigInteger intVal = new BigInteger(data); + if (negative) intVal = intVal.negate(); - } val = new BigDecimal(intVal, scale); http://git-wip-us.apache.org/repos/asf/ignite/blob/fd838d5e/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java index adbb9cb..1e706ae 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java @@ -474,13 +474,15 @@ public final class BinaryObjectImpl extends BinaryObjectExImpl implements Extern int dataLen = BinaryPrimitives.readInt(arr, fieldPos + 5); byte[] data = BinaryPrimitives.readByteArray(arr, fieldPos + 9, dataLen); - BigInteger intVal = new BigInteger(data); + boolean negative = data[0] < 0; + + if (negative) + data[0] &= 0x7F; - if (scale < 0) { - scale &= 0x7FFFFFFF; + BigInteger intVal = new BigInteger(data); + if (negative) intVal = intVal.negate(); - } val = new BigDecimal(intVal, scale); http://git-wip-us.apache.org/repos/asf/ignite/blob/fd838d5e/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java index 3e73e58..05f6963 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java @@ -369,13 +369,15 @@ public class BinaryObjectOffheapImpl extends BinaryObjectExImpl implements Exter int dataLen = BinaryPrimitives.readInt(ptr, fieldPos + 5); byte[] data = BinaryPrimitives.readByteArray(ptr, fieldPos + 9, dataLen); - BigInteger intVal = new BigInteger(data); + boolean negative = data[0] < 0; + + if (negative) + data[0] &= 0x7F; - if (scale < 0) { - scale &= 0x7FFFFFFF; + BigInteger intVal = new BigInteger(data); + if (negative) intVal = intVal.negate(); - } val = new BigDecimal(intVal, scale); http://git-wip-us.apache.org/repos/asf/ignite/blob/fd838d5e/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryFieldExtractionSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryFieldExtractionSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryFieldExtractionSelfTest.java index 5721128..9f39746 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryFieldExtractionSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryFieldExtractionSelfTest.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.binary; +import java.math.BigDecimal; import java.nio.ByteBuffer; import java.util.concurrent.ThreadLocalRandom; import org.apache.ignite.configuration.BinaryConfiguration; @@ -97,6 +98,40 @@ public class BinaryFieldExtractionSelfTest extends GridCommonAbstractTest { } /** + * @throws Exception If failed. + */ + public void testDecimalFieldMarshalling() throws Exception { + BinaryMarshaller marsh = createMarshaller(); + + BigDecimal values[] = new BigDecimal[] { BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN, + new BigDecimal("-100.5"), BigDecimal.valueOf(Long.MAX_VALUE, 0), + BigDecimal.valueOf(Long.MIN_VALUE, 0), BigDecimal.valueOf(Long.MAX_VALUE, 8), + BigDecimal.valueOf(Long.MIN_VALUE, 8)}; + + DecimalValue decVal = new DecimalValue(values[0]); + + BinaryObjectImpl binObj = toBinary(decVal, marsh); + + BinaryFieldEx field = (BinaryFieldEx)binObj.type().field("decVal"); + + ByteBuffer buf = ByteBuffer.allocate(64); + + for (BigDecimal value : values) { + decVal = new DecimalValue(value); + + binObj = toBinary(decVal, marsh); + + field.writeField(binObj, buf); + + buf.flip(); + + assertEquals(field.value(binObj), field.readField(buf)); + + buf.clear(); + } + } + + /** * @param obj Object to transform to a binary object. * @param marsh Binary marshaller. * @return Binary object. @@ -158,4 +193,21 @@ public class BinaryFieldExtractionSelfTest extends GridCommonAbstractTest { dVal = seed; } } + + /** + * + */ + @SuppressWarnings("UnusedDeclaration") + private static class DecimalValue { + /** */ + private BigDecimal decVal; + + /** + * + * @param decVal Value to use + */ + private DecimalValue(BigDecimal decVal) { + this.decVal = decVal; + } + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/fd838d5e/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryMarshallerSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryMarshallerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryMarshallerSelfTest.java index ee72919..a4ace13 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryMarshallerSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryMarshallerSelfTest.java @@ -2626,16 +2626,29 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest { // 1. Test reflective stuff. DecimalReflective obj1 = new DecimalReflective(); - obj1.val = BigDecimal.ZERO; - obj1.valArr = new BigDecimal[] {BigDecimal.ONE, BigDecimal.TEN}; + BigDecimal valArr[] = new BigDecimal[] {BigDecimal.ONE, BigDecimal.TEN, new BigDecimal("-100.5"), + BigDecimal.valueOf(Long.MAX_VALUE, 0), BigDecimal.valueOf(Long.MIN_VALUE, 0), + BigDecimal.valueOf(Long.MAX_VALUE, 8), BigDecimal.valueOf(Long.MIN_VALUE, 8)}; + obj1.val = BigDecimal.ZERO; + obj1.valArr = valArr; BinaryObjectImpl portObj = marshal(obj1, marsh); - assertEquals(obj1.val, portObj.field("val")); assertArrayEquals(obj1.valArr, portObj.<BigDecimal[]>field("valArr")); - - assertEquals(obj1.val, portObj.<DecimalReflective>deserialize().val); assertArrayEquals(obj1.valArr, portObj.<DecimalReflective>deserialize().valArr); + assertArrayEquals(obj1.valArr, (BigDecimal[])portObj.type().field("valArr").value(portObj)); + + obj1.valArr = null; + + for (BigDecimal v: valArr) { + obj1.val = v; + + portObj = marshal(obj1, marsh); + + assertEquals(obj1.val, portObj.field("val")); + assertEquals(obj1.val, portObj.<DecimalReflective>deserialize().val); + assertEquals(obj1.val, portObj.type().field("val").value(portObj)); + } // 2. Test marshal aware stuff. DecimalMarshalAware obj2 = new DecimalMarshalAware(); @@ -2654,6 +2667,19 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest { assertArrayEquals(obj2.valArr, portObj.<DecimalMarshalAware>deserialize().valArr); assertEquals(obj2.rawVal, portObj.<DecimalMarshalAware>deserialize().rawVal); assertArrayEquals(obj2.rawValArr, portObj.<DecimalMarshalAware>deserialize().rawValArr); + + assertEquals(obj2.val, portObj.type().field("val").value(portObj)); + assertArrayEquals(obj2.valArr, (BigDecimal[])portObj.type().field("valArr").value(portObj)); + + for (BigDecimal v: valArr) { + obj2.val = v; + + portObj = marshal(obj2, marsh); + + assertEquals(obj2.val, portObj.field("val")); + assertEquals(obj2.val, portObj.<DecimalMarshalAware>deserialize().val); + assertEquals(obj2.val, portObj.type().field("val").value(portObj)); + } } /**
