k-paxian / dart-json-mapper

Serialize / Deserialize Dart Objects to / from JSON
https://pub.dev/packages/dart_json_mapper
Other
399 stars 33 forks source link

Incorrect detection of circular reference if hashCode has been overridden #191

Closed umasagashi closed 1 year ago

umasagashi commented 1 year ago

If different objects return the same hashCode, it may cause circular reference detection.

Here is a reproducible example.

import 'package:dart_json_mapper/dart_json_mapper.dart';

import 'main.mapper.g.dart';

@jsonSerializable
class A {
  final int a;

  A(this.a);

  @override
  bool operator ==(Object other) => runtimeType == other.runtimeType && a == (other as A).a;

  @override
  int get hashCode => a.hashCode;
}

@jsonSerializable
class B {
  final A a;

  B(this.a);
}

void main() {
  initializeJsonMapper();

  JsonMapper.serialize([
    A(1),
    A(1),
    B(A(1)),
  ]);
}
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Circular reference detected. Instance of 'A'
#0      JsonMapper._serializeObject (package:dart_json_mapper/src/mapper.dart:825:9)
#1      JsonMapper._serializeObject.<anonymous closure> (package:dart_json_mapper/src/mapper.dart:858:26)
#2      JsonMapper._enumeratePublicProperties (package:dart_json_mapper/src/mapper.dart:547:14)
#3      JsonMapper._serializeObject (package:dart_json_mapper/src/mapper.dart:829:5)
#4      JsonMapper._configureConverter.<anonymous closure> (package:dart_json_mapper/src/mapper.dart:776:27)
#5      DefaultIterableConverter.toJSON.<anonymous closure> (package:dart_json_mapper/src/model/converters.dart:466:47)
#6      MappedListIterable.elementAt (dart:_internal/iterable.dart:413:31)
#7      ListIterator.moveNext (dart:_internal/iterable.dart:342:26)
#8      new _GrowableList._ofEfficientLengthIterable (dart:core-patch/growable_array.dart:189:27)
#9      new _GrowableList.of (dart:core-patch/growable_array.dart:150:28)
#10     new List.of (dart:core-patch/array_patch.dart:51:28)
#11     ListIterable.toList (dart:_internal/iterable.dart:213:44)
#12     DefaultIterableConverter.toJSON (package:dart_json_mapper/src/model/converters.dart:466:64)
#13     JsonMapper._getConvertedValue (package:dart_json_mapper/src/mapper.dart:417:21)
#14     JsonMapper._serializeObject (package:dart_json_mapper/src/mapper.dart:793:14)
#15     JsonMapper.serialize (package:dart_json_mapper/src/mapper.dart:27:27)
#16     main (package:json_mapper_test/main.dart:29:14)
#17     _runMain.<anonymous closure> (dart:ui/hooks.dart:132:23)
#18     _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#19     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)

Since this error only occurs when hashCode has been overridden, I assume it is related to the following object key generation code.

https://github.com/k-paxian/dart-json-mapper/blob/bfc5f55fa8e52414e6d9bd841bca55314d3e22ca/mapper/lib/src/mapper.dart#L266

So, changing this to identityHashCode may be enough to solve this problem, but I am not sure.

k-paxian commented 1 year ago

Awesome catch! Thank you for reporting it and suggesting solution 🎉