From 9b66e84747131113529f6c59fcc68f27ca33331b Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Tue, 27 Nov 2018 22:18:17 -0800 Subject: [PATCH] Fix #139 --- .../dataformat/cbor/CBORGenerator.java | 8 +++---- .../jackson/dataformat/cbor/CBORParser.java | 3 ++- .../dataformat/cbor/GeneratorSimpleTest.java | 21 +++++++++++++++++++ .../cbor/parse/ParserNumbersTest.java | 19 ++++++++++++++--- release-notes/VERSION | 5 +++++ 5 files changed, 48 insertions(+), 8 deletions(-) diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java index e27eca5dd..ab856d287 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java @@ -1032,11 +1032,11 @@ public void writeNumber(BigDecimal dec) throws IOException { _writeByte(BYTE_TAG_DECIMAL_FRACTION); _writeByte(BYTE_ARRAY_2_ELEMENTS); + // 27-Nov-2019, tatu: As per [dataformats-binary#139] need to change sign here int scale = dec.scale(); - _writeIntValue(scale); - /* Hmmmh. Specification suggest use of regular integer for mantissa. But - * if it doesn't fit, use "bignum" - */ + _writeIntValue(-scale); + // Hmmmh. Specification suggest use of regular integer for mantissa. But + // if it doesn't fit, use "bignum" BigInteger unscaled = dec.unscaledValue(); int bitLength = unscaled.bitLength(); if (bitLength <= 31) { diff --git a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java index 6e29eb3d6..5910f0f99 100644 --- a/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java +++ b/cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java @@ -882,7 +882,8 @@ protected JsonToken _handleTaggedArray(int tag, int len) throws IOException if (t != JsonToken.VALUE_NUMBER_INT) { _reportError("Unexpected token ("+t+") as the first part of 'bigfloat' value: should get VALUE_NUMBER_INT"); } - int exp = getIntValue(); + // 27-Nov-2019, tatu: As per [dataformats-binary#139] need to change sign here + int exp = -getIntValue(); t = nextToken(); // Should get an integer value; int/long/BigInteger diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/GeneratorSimpleTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/GeneratorSimpleTest.java index 017f5b377..662772e11 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/GeneratorSimpleTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/GeneratorSimpleTest.java @@ -197,6 +197,27 @@ public void testFloatValues() throws Exception (byte) rawL); } + // [dataformats-binary#139]: wrong encoding of BigDecimal + public void testBigDecimalValues() throws Exception + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + CBORGenerator gen = cborGenerator(out); + final BigDecimal NR = new BigDecimal("273.15"); + gen.writeNumber(NR); + gen.close(); + byte[] b = out.toByteArray(); + + // [https://tools.ietf.org/html/rfc7049#section-2.4.2] + final byte[] spec = new byte[] { + (byte) 0xC4, // tag 4 + (byte) 0x82, // Array of length 2 + 0x21, // int -- -2 + 0x19, 0x6a, (byte) 0xb3 // int 27315 + }; + assertEquals(spec.length, b.length); + Assert.assertArrayEquals(spec, b); + } + public void testEmptyArray() throws Exception { // First: empty array (2 bytes) diff --git a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/parse/ParserNumbersTest.java b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/parse/ParserNumbersTest.java index 2c4214b2b..13cf42ffa 100644 --- a/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/parse/ParserNumbersTest.java +++ b/cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/parse/ParserNumbersTest.java @@ -328,7 +328,7 @@ public void testFloatNumberType() throws IOException { } public void testBigDecimalType() throws IOException { - final BigDecimal NR = new BigDecimal("273.15"); + final BigDecimal NR = new BigDecimal("172.125"); ByteArrayOutputStream out = new ByteArrayOutputStream(); CBORGenerator generator = cborGenerator(out); generator.writeNumber(NR); @@ -343,7 +343,20 @@ public void testBigDecimalType() throws IOException { assertEquals(NR.intValue(), parser.getIntValue()); assertNull(parser.nextToken()); } - // Almost good. But [dataformats#139] to consider too... - // ... but that'll need to wait for 2.10 + + // Almost good. But [dataformats#139] to consider too, see + // [https://tools.ietf.org/html/rfc7049#section-2.4.2] + final byte[] spec = new byte[] { + (byte) 0xC4, // tag 4 + (byte) 0x82, // Array of length 2 + 0x21, // int -- -2 + 0x19, 0x6a, (byte) 0xb3 // int 27315 + }; + try (CBORParser parser = cborParser(spec)) { + assertEquals(JsonToken.VALUE_NUMBER_FLOAT, parser.nextToken()); + assertEquals(NumberType.BIG_DECIMAL, parser.getNumberType()); + assertEquals(new BigDecimal("273.15"), parser.getDecimalValue()); + assertNull(parser.nextToken()); + } } } diff --git a/release-notes/VERSION b/release-notes/VERSION index 26a030831..82c5c4a79 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -8,6 +8,11 @@ Project: jackson-datatypes-binaryModules: === Releases === ------------------------------------------------------------------------ +2.10.0 (not yet released) + +#139: Incorrect decimal fraction representation + (reported by wlukowicz@github) + 2.9.7 (19-Sep-2018) #142: (ion) `IonParser.getNumberType()` returns `null` for `IonType.FLOAT`