dart-league / dson

dart library which converts Dart Objects into their JSON representation
Apache License 2.0
66 stars 14 forks source link

Calling toMap() on an object with null fields throws an error #46

Open lynzrand opened 5 years ago

lynzrand commented 5 years ago

dson version: 0.15.5

dson_core version: 0.15.4

Minimal example to reproduce bug:

/* test.dart */
import 'package:dson/dson.dart';

part 'test.g.dart';

main(List<String> args) {
  toMap(new SimpleTest());
}

@serializable
class SimpleTest {
  String x;
  SimpleTest() {
    x = null;
  }
}

After build_runner build, run the script and the following error was thrown:

Unhandled exception:
NoSuchMethodError: The getter 'isEnum' was called on null.
Receiver: null
Tried calling: isEnum
#0      Object.noSuchMethod (dart:core/runtime/lib/object_patch.dart:50:5)
#1      _serializeObject (file:/// [...] /AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/dson_core-0.15.4/lib/src/serializer.dart:113:18)
#2      objectToSerializable (file:/// [...] /AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/dson_core-0.15.4/lib/src/serializer.dart:69:12)
#3      toMap (file:// [...] /AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/dson_core-0.15.4/lib/src/serializer.dart:42:5)
#4      main ( [...] test.dart:16:3)
#5      _startIsolate.<anonymous closure> (dart:isolate/runtime/lib/isolate_patch.dart:298:32)
#6      _RawReceivePortImpl._handleMessage (dart:isolate/runtime/lib/isolate_patch.dart:171:12)

The error appears to be from this line in dson_core, so I went to see the code. It seems that this instance variable somehow passed the primitive type check at line 11 (which in theory should block this null value):

bool isPrimitive(value) => value is String || value is num || value is bool || value == null;

Then this null value got to _serializeObject() function, passed to the reflect() function in built_mirrors_core and returned as null instead of a ClassMirror object.

I have little idea how this should be fixed though...


update: fixed format error

luisvt commented 5 years ago

your error is because you didn't call _initMirrors() function in your main:

your full code should look as fallow:


library test; // don't forget to change the name of your library

import 'package:dson/dson.dart';

part 'test.g.dart';

main(List<String> args) {
  _initMirrors(); // This call is needed to initialize mirrors before doing serialization/deserialization

  toMap(new SimpleTest());
}

@serializable
class SimpleTest {
  String x;
  SimpleTest() {
    x = null;
  }
}```
lynzrand commented 5 years ago

Oh, my fault. Thanks, and sorry for taking your time!

Rynco Maekawa


From: noreply@github.com noreply@github.com on behalf of Luis Vargas notifications@github.com Sent: Tuesday, March 26, 2019 10:29:44 AM To: dart-league/dson Cc: Rynco Li; Author Subject: Re: [dart-league/dson] Calling toMap() on an object with null fields throws an error (#46)

your error is because you didn't call _initMirrors() function in your main:

your full code should look as fallow:

library test; // don't forget to change the name of your library

import 'package:dson/dson.dart';

part 'test.g.dart';

main(List args) { _initMirrors(); // This call is needed to initialize mirrors before doing serialization/deserialization

toMap(new SimpleTest()); }

@serializable class SimpleTest { String x; SimpleTest() { x = null; } }```

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/dart-league/dson/issues/46#issuecomment-476450004, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AJyKr_kTCDTYpqeq0MoOMR7ZJxnUyxzAks5vaYYYgaJpZM4cFloZ.

luisvt commented 5 years ago

don't worry, it's cool to help users of my library

lynzrand commented 5 years ago

Sorry, but the problem is here again. I have called _initMirrors() in the main isolate, but now I'm working in another isolate where no entry point like main function. Where should I call _initMirrors in this situation?

More precisely, I'm working with the Aqueduct HTTP server package and I need to serialize stuff. The serializer/deserializer coming with the package has not enough features for me to fiddle with (like ignoring fields at runtime). Aqueduct works by using separate isolates to handle HTTP requests, and in one of those Isolates I still got this "not initialized" error.

图片

What should I do now?

luisvt commented 5 years ago

could you show me your full code or a full example?

lynzrand commented 5 years ago

The issue occurs here: https://github.com/01010101lzy/akali/blob/375079783a8168ad2cfc79505f334de3670b6b9f/lib/data/db/mongodb.dart#L145

  Future<ActionResult<Pic>> updateImgInfo(Pic newInfo, String id) async {
    var _id = ObjectId.fromHexString(id);
    var result = await picCollection.update(where.id(_id), newInfo.asMap());
    newInfo.id = _id;
    bool success = result['nModified'] > 0;
    if (success)
      return ActionResult()
        ..success = true
        ..data = newInfo
        ..affected = result['nModified'];
    else
      return ActionResult()..success = false;
}

In this function, the Pic.asMap() method is calling return toMap(this) inside.

This function is called by this line: https://github.com/01010101lzy/akali/blob/375079783a8168ad2cfc79505f334de3670b6b9f/lib/api/imgRequest.dart#L213

This is the handling function of HTTP PUT of /api/v1/img/:id path

  /// PUT `img/:id`
  ///
  /// Updates image [id]'s data by [newInfo].
  /// Requires authorization beforehand.
  @Operation.put('id')
  Future<Response> putImage(
    @Bind.path('id') String id,
    @Bind.body() Pic newInfo, [
    @Bind.query('access_token') String tokenQuery,
    @Bind.header('Access-Token') String tokenHeader,
  ]) async {
    var result;
    try {
      result = await db.updateImgInfo(newInfo, id);
    } catch (e, stack) {
      logger.severe("Error in putImage()", e, stack);
      throw Response.serverError(
          body: {'error': e, 'message': result, 'stackTrace': stack});
    }
    return Response.ok(result);
  }

The rest of the handling process is managed by Aqueduct so I don't have access on them.

The whole repository is here: https://github.com/01010101lzy/akali