Skip to content

Commit 9cc0e2c

Browse files
Merge pull request #147 from kaleido-io/large-num-test
Add support for 256 bit JSON numbers (vs. strings)
2 parents c214085 + 3165432 commit 9cc0e2c

File tree

3 files changed

+60
-2
lines changed

3 files changed

+60
-2
lines changed

pkg/fftypes/jsonany.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2023 Kaleido, Inc.
1+
// Copyright © 2024 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -21,6 +21,7 @@ import (
2121
"crypto/sha256"
2222
"database/sql/driver"
2323
"encoding/json"
24+
"strings"
2425

2526
"github.com/hyperledger/firefly-common/pkg/i18n"
2627
"github.com/hyperledger/firefly-common/pkg/log"
@@ -76,7 +77,18 @@ func (h *JSONAny) Unmarshal(ctx context.Context, v interface{}) error {
7677
if h == nil {
7778
return i18n.NewError(ctx, i18n.MsgNilOrNullObject)
7879
}
79-
return json.Unmarshal([]byte(*h), v)
80+
81+
if _, ok := v.(*float64); ok {
82+
return i18n.NewError(ctx, i18n.MsgUnmarshalToFloat64NotSupported)
83+
}
84+
85+
d := json.NewDecoder(strings.NewReader(h.String()))
86+
d.UseNumber()
87+
if err := d.Decode(v); err != nil {
88+
return err
89+
}
90+
91+
return nil
8092
}
8193

8294
func (h *JSONAny) Hash() *Bytes32 {

pkg/fftypes/jsonany_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,51 @@ func TestUnmarshal(t *testing.T) {
181181
assert.Equal(t, "value1", myObj.Key1)
182182
}
183183

184+
func TestUnmarshalHugeNumber(t *testing.T) {
185+
186+
var myInt64Variable int64
187+
var myFloat64Variable float64
188+
ctx := context.Background()
189+
var h *JSONAny
190+
var myObj struct {
191+
Key1 interface{} `json:"key1"`
192+
Key2 JSONAny `json:"key2"`
193+
Key3 JSONAny `json:"key3"`
194+
}
195+
196+
h = JSONAnyPtr(`{"key1":123456789123456789123456789, "key2":123456789123456789123456789, "key3":1234}`)
197+
err := h.Unmarshal(ctx, &myObj)
198+
assert.NoError(t, err)
199+
assert.Equal(t, json.Number("123456789123456789123456789"), myObj.Key1)
200+
201+
assert.NoError(t, err)
202+
assert.Equal(t, "123456789123456789123456789", myObj.Key2.String())
203+
204+
err = myObj.Key2.Unmarshal(ctx, &myInt64Variable)
205+
assert.Error(t, err)
206+
assert.Regexp(t, "cannot unmarshal number 123456789123456789123456789 into Go value of type int64", err)
207+
208+
err = myObj.Key3.Unmarshal(ctx, &myInt64Variable)
209+
assert.NoError(t, err)
210+
assert.Equal(t, int64(1234), myInt64Variable)
211+
212+
err = myObj.Key2.Unmarshal(ctx, &myFloat64Variable)
213+
assert.Error(t, err)
214+
assert.Regexp(t, "FF00249", err)
215+
}
216+
217+
func TestUnmarshalHugeNumberError(t *testing.T) {
218+
219+
var h *JSONAny
220+
var myObj struct {
221+
Key1 interface{} `json:"key1"`
222+
}
223+
224+
h = JSONAnyPtr(`{"key1":1234567891invalidchars234569}`)
225+
err := h.Unmarshal(context.Background(), &myObj)
226+
assert.Error(t, err)
227+
}
228+
184229
func TestNilHash(t *testing.T) {
185230
assert.Nil(t, (*JSONAny)(nil).Hash())
186231
}

pkg/i18n/en_base_error_messages.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,5 @@ var (
183183
MsgDBExecFailed = ffe("FF00245", "Database update failed")
184184
MsgDBErrorBuildingStatement = ffe("FF00247", "Error building statement: %s")
185185
MsgDBReadInsertTSFailed = ffe("FF00248", "Failed to read timestamp from database optimized upsert: %s")
186+
MsgUnmarshalToFloat64NotSupported = ffe("FF00249", "Unmarshalling to a float64 is not supported due to possible precision loss. Consider unmarshalling to an interface, json.Number or fftypes.JSONAny instead")
186187
)

0 commit comments

Comments
 (0)