Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
lynzrand opened this issue Mar 24, 2019 · 6 comments
Open

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

lynzrand opened this issue Mar 24, 2019 · 6 comments

Comments

@lynzrand
Copy link

lynzrand commented Mar 24, 2019

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
Copy link
Collaborator

luisvt commented Mar 26, 2019

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
Copy link
Author

lynzrand commented Mar 26, 2019 via email

@luisvt luisvt closed this as completed Mar 26, 2019
@luisvt
Copy link
Collaborator

luisvt commented Mar 26, 2019

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

@lynzrand
Copy link
Author

lynzrand commented Mar 27, 2019

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
Copy link
Collaborator

luisvt commented Mar 27, 2019

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

@luisvt luisvt reopened this Mar 27, 2019
@lynzrand
Copy link
Author

lynzrand commented Mar 28, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants