Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing class static factory as method parameter in Dart

Tags:

flutter

dart

I'm currently attempting to abstract making different HTTP requests by using generics. I'm using json_serializale for generating fromJson() and toJson() methods.

Here is a simple model file:

import 'package:json_annotation/json_annotation.dart';

part 'article.g.dart';

@JsonSerializable()
class Article {
  int id = 0;
  String title = "";

  Article({this.id, this.title});

  factory Article.fromJson(Map<String, dynamic> json) =>
      _$ArticleFromJson(json);
  Map<String, dynamic> toJson() => _$ArticleToJson(this);
}

I have a generic class that needs to be passed the fromJson-method, see:

typedef CreateModelFromJson = dynamic Function(Map<String, dynamic> json);

class HttpGet<Model> {
  CreateModelFromJson createModelFromJson;

  HttpGet({
    this.createModelFromJson,
  });

  Future<Model> do() async {
    // [... make HTTP request and do stuff ...]
    return createModelFromJson(jsonData);
  }
}

And finally, here is the ArticleService:

class ArticleService {
  Future<Model> read() => HttpGet<Article>({
    createModelFromJson: Article.fromJson,
  }).do();
}

This underlines-in-red fromJson in createModelFromJson: Article.fromJson,, with the error being:

The getter 'fromJson' isn't defined for the class 'Article'. Try importing the library that defines 'fromJson', correcting the name to the name of an existing getter, or defining a getter or field named 'fromJson'.dart(undefined_getter)

Obviously the compiler believes .fromJson to be a static field. However, it's, as can be seen above, a static factory method.

1.) Can you help with how to pass the constructor to the generic class?

ALSO:
2.) I'm not sure whether I'll actually get an Article back, or if I have to type cast it first? I'm kind of worried about the dynamic return type of the typedef.

3.) I'm also open for better ideas for what I'm attempting to do.

like image 866
Sven Avatar asked May 03 '19 01:05

Sven


1 Answers

As of Dart 2.15, Dart now supports constructor tear-offs. Named constructors can be used as expected. The default, unnamed constructor for a class named ClassName can be referenced with ClassName.new. (ClassName by itself would be a reference to the corresponding Type object.)


Dart 2.14 and earlier did not allow using constructors as tear-offs. For those versions, I recommend using a static method instead.

Alternatively you could just create an explicit closure:

class ArticleService {
  Future<Model> read() => HttpGet<Article>({
    createModelFromJson: (json) => Article.fromJson(json),
  }).do();
}
like image 65
jamesdlin Avatar answered Oct 28 '22 09:10

jamesdlin