jsonEncode is converting `double` to `int` when used in Web
osaxma opened this issue · 2 comments
In the Web, jsonEncode
is converting double
to int
when the fractional part is zero.
Given that Dart/Flutter is being used in multi-platform projects, this behavior becomes problematic for serializable data classes as shown in the example below:
// DartPad - Based on Flutter 1.26.0-17.8.pre Dart SDK 2.10.4
import 'dart:convert';
void main() {
final data = Data(x: 3.0, y: 3.1);
final jsonString = data.toJson();
print(jsonString); // prints {"x":3,"y":3.1}
// works on web, throws in iOS/Android when trying to decode the printed string above.
final dataFromJson = Data.fromJson(jsonString);
}
class Data {
final double x;
final double y;
Data({this.x, this.y});
Map<String, dynamic> toMap() {
return {
'x': x,
'y': y,
};
}
factory Data.fromMap(Map<String, dynamic> map) {
if (map == null) return null;
return Data(
x: map['x'],
y: map['y'],
);
}
String toJson() => json.encode(toMap());
factory Data.fromJson(String source) => Data.fromMap(json.decode(source));
}
Is there a way to keep the fractional part when converting a double
to json?
No.
On the web there is only one 1
value, not distinct integer 1
and double 1.0
values.
The JSON encoding does not provide a way to specify a format, so it has to pick a representation for the value 1
blindly. It choses 1
because that can still be parsed as both int
(using int.parse
) and double
(using double.parse
) at the other end.
The default JSON decoder will parse it as an int
because that's what it does.
I recommend treating all JSON number values as having type num
. The JSON format is a text format, it does not specify the meaning of a numeral. Each parser can do what it wants. So, when you get a number our, you should convert it to what you want (using .toDouble()
if you want a double, or .toInt()
if you want an int).
So:
return Data(
x: map['x'].toDouble(),
y: map['y'].toDouble(),
);
Don't assume anything about the source or the representation, because the JSON might have been generated in a completely different language, or it might have been read and re-written by a third-party tool. All JSON promises is that it's a numeral.