simc / crimson

Fast, efficient and easy-to-use JSON parser and serializer for Dart.
Apache License 2.0
229 stars 6 forks source link

Using Crimson with a generic class #9

Open simc opened 1 year ago

simc commented 1 year ago

Discussed in https://github.com/simc/crimson/discussions/8

Originally posted by **Reprevise** December 31, 2022 I have a class like this: ```dart class ApiResponse extends Equatable { final List? errors; final T? data; const ApiResponse({ this.errors, this.data, }); T get dataOrThrow => data ?? (throw error!); CustomError? get error { // ... } factory ApiResponse.fromJson( Map map, T Function(Map json) create, ) { return ApiResponse( errors: map['errors'] != null ? List.from( map['errors']?.map((x) => CustomError.fromJson(x)), ) : null, data: map['data'] != null ? create(map['data']) : null, ); } factory ApiResponse.fromJsonList( Map map, T Function(List>) create, { List Function(Map json)? list, }) { T? getData() { if (map['data'] == null) return null; final items = List.from( list?.call(map['data'] as Map) ?? map['data'] as List, ); return create( items.whereNotNull().map((e) => e as Map).toList(), ); } return ApiResponse( errors: map['errors'] != null ? List.from( map['errors'].map((x) => CustomError.fromJson(x)), ) : null, data: getData(), ); } @override List get props => [errors, data]; } ``` I use it as so: ```dart return ApiResponse.fromJsonList( response.data as Map, (json) => json.map(MyModel.fromJson).toList(), list: (json) => List.from(json['items']), ).data!; ``` How can I do this with Crimson?
simc commented 1 year ago

This is not possible to support currently unfortuantely. The reason is that Crimson needs to know all possible types of T at compile time to generate optimized code.

Do you think something like this would be helpful:

// define possible types of T

@json
typedef StringApiResponse = ApiResponse<String>;

@json
typedef ListApiResponse = ApiResponse<List<String>>;

void main() {
  // use one of the generated decoders
  Crimson(bytes).readStringApiResponse();
}

Another option would be waiting for sealed class support in dart and requiring generic types to be subtypes of sealed classes. That would be problematic with String for example however.

What do you think @Reprevise?

Reprevise commented 1 year ago

For my case specifically, it's not like I'm giving it a type and expecting it to parse it on its own as I'm providing it the method that it can parse it with as you can see with my create callback passed into my fromJson factory method. So how it works with my usecase is that it would parse the errors field and then use the method returned from the create callback to parse the data field. The issue that I'm facing is that Crimson only parses things via bytes (which I presume is where it gets its performance from).

simc commented 1 year ago

Is there a reason you want to write the fromJson method yourself? It's not doing anything special and could be created by either Crimson or json_serializable.

Reprevise commented 1 year ago

If you're talking about ApiResponse's fromJson method, then yeah, it can be generated.