redstone-dart / redstone

A metadata driven microframework for Dart.
http://redstone-dart.github.io/redstone
MIT License
342 stars 42 forks source link

Crash with mapper transformer, OK without #39

Closed RobertBlackhart closed 10 years ago

RobertBlackhart commented 10 years ago

I am writing the client side of my application. In it I am requesting from the server a list of Auctions which are being encoded like this:

@app.Route('/list', methods: const[app.POST])
@Encode()
Future<List<Auction>> getAuctions(@app.Body(app.JSON) Map parameters)
{
    String queryString = "select * from auctions";
    return postgreSql.query(queryString, Auction);
}

The Auction class looks like this (on both ends):

class Auction
{
    @Field()
    String item_name;

    @Field()
    int item_count;

    @Field()
    int total_cost;

    @Field()
    String username;

    @Field()
    DateTime start_time;

    @Field()
    DateTime end_time;
}

The client-side code looks like this:

import 'package:redstone_mapper/mapper.dart';
import 'package:redstone_mapper/mapper_factory.dart';
import 'dart:convert';
import 'dart:html';

void main()
{
    bootstrapMapper();

    HttpRequest.request('http://localhost:8181/ah/list',
            method: "POST", requestHeaders: {"content-type": "application/json"},
            sendData: JSON.encode({'username':{'operator':'=','value':'thad'}}))
        .then((HttpRequest req)
        {
                List<Auction> auctions = decode(JSON.decode(req.responseText),Auction);
                print(auctions);
        });
}

My pubspec.yaml file has the redstone_mapper transformer listed (as suggested):

name: ah_test
description: A sample web application
dependencies:
  browser: any
  redstone: any
  redstone_mapper: any
  intl: any
transformers:
- redstone_mapper

However, when running the client, it throws an exception:

Exception: Uncaught Error: MapperException:  Failed to decode: {item_name: Pick, item_count: 5, total_cost: 1000, username: thad, start_time: 2014-08-27T19:15:00.000, end_time: 2014-08-29T19:15:00.000} 
reason: Class 'String' has no instance method 'toIso8601String'.

NoSuchMethodError: method not found: 'toIso8601String'
Receiver: "2014-08-27T19:15:00.000"
Arguments: []
Stack Trace:
#0      _getOrCreateMapper.<anonymous closure> (package:redstone_mapper/mapper_factory_static.dart:220:13)
#1      _ListDecoder.call.<anonymous closure> (package:redstone_mapper/mapper_factory_static.dart:167:21)
#2      MappedListIterable.elementAt (dart:_internal/iterable.dart:397)
#3      ListIterator.moveNext (dart:_internal/iterable.dart:325)
#4      List.List.from (dart:core/list.dart:95)
#5      _ListDecoder.call (package:redstone_mapper/mapper_factory_static.dart:166:16)
#6      _getOrCreateMapper.<anonymous closure> (package:redstone_mapper/mapper_factory_static.dart:213:52)
#7      _TypeDecoder.convert (package:redstone_mapper/src/mapper_impl.dart:32:26)
#8      GenericTypeCodec.decode (package:redstone_mapper/mapper.dart:282:28)
#9      decode (package:redstone_mapper/mapper.dart:30:29)
#10     main.<anonymous closure> (http://localhost:8080/ah_test.dart:40:38)
#11     _RootZone.runUnary (dart:async/zone.dart:1082)
#12     _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:488)
#13     _Future._propagateToListeners (dart:async/future_impl.dart:571)
#14     _Future._completeWithValue (dart:async/future_impl.dart:331)
#15     _Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:393)
#16     _asyncRunCallbackLoop (dart:async/schedule_microtask.dart:41)
#17     _asyncRunCallback (dart:async/schedule_microtask.dart:48)
#18     _handleMutation (dart:html:39006)

It looks like it's trying to parse the right thing, but it's failing to do the DateTime's correctly. The odd thing to me is that if I remove the redstone_mapper transformer, it runs without error and produces a correct result (I can manipulate the DateTime objects that are returned). Unfortunately, when compiling via pub build it does not run either way (with or without the transformer).

Am I doing something wrong with my code or is there a problem where the transformer is stripping out some class that is needed to decode the DateTime objects?

luizmineo commented 10 years ago

It seems the static implementation of mapper is not decoding DateTime objects correctly. I'll take a look at that.

When you run your code in Dartium, without running the transformer, it uses a different (dynamic) implementation, which seems to not be affected by this problem. Although, this implementation relies on the mirrors API, which can cause problems when compiled to Javascript.

luizmineo commented 10 years ago

I've just published redstone_mapper v0.1.6 with a fix for this problem. Can you try it again?

RobertBlackhart commented 10 years ago

I've just been able to try it again. I did a pub upgrade on both the server and the client and pulled in the new mapper package (0.1.6). Re-ran the code with the same results (same error message and stack trace). The problem still appears when using the transformer and disappears when removing the transformer.

RobertBlackhart commented 10 years ago

I take that last comment back. For whatever reason it is now working as expected (while having the transformer active). I can't really explain why it didn't work before other than something must have been cached.

I can also confirm that it works correctly when compiled to JS (and does not produce a bloated JS file).

luizmineo commented 10 years ago

Thanks! I'm trying to figure out how to automate tests for the static implementation (currently, only the dynamic implementation is covered by unit tests) so we can avoid errors like this.