schultek / dart_mappable

Improved json serialization and data classes with full support for generics, inheritance, customization and more.
https://pub.dev/packages/dart_mappable
MIT License
145 stars 21 forks source link

Migrating from 1.x to 2.x #46

Open schultek opened 1 year ago

schultek commented 1 year ago

The following breaking changes need to be migrated when upgrading to version 2.x:

Code Generation Setup

Additional files are now generated for each file containing annotated classes. This removes the need to specify entry points in the build.yaml.

This is now similar to how packages like json_serializable or freezed generate code.

  1. Remove the entrypoints inside build.yaml:
targets:
  $default:
    builders:
      dart_mappable_builder:
-        generate_for:
-          - lib/main.dart
          options:
            ...

If you don't have any other configuration inside build.yaml, you can delete the file completely.

  1. In each file where you use annotations, add the respective part directive:
// This file is main.dart
import 'package:dart_mappable/dart_mappable.dart'

- import 'main.mapper.g.dart';
+ part 'main.mapper.dart';

@MappableClass()
class MyClass with MyClassMappable {}

If you haven't already, add the <ClassName>Mappable mixin to each annotated class.

  1. In each file where you imported the generated mapper file, import the original file instead:
// This file is some file inside your project.
- import 'main.mapper.g.dart';
+ import 'main.dart';

Mapper Generation

Instead of generating a general Mapper class for everything, now each annotated class has its own <ClassName>Mapper. Also the generated mixin <ClassName>Mappable is now required to be used.

  1. Add the generated <ClassName>Mappable mixin to each annotated class:
@MappableClass()
- class Person {
+ class Person with PersonMappable {
  ...
}
  1. In your code, replace any call to Mapper with the class-specific <ClassName>Mapper:
void main() {
-   var person = Mapper.fromJson<Person>('{...}');
+   var person = PersonMapper.fromJson('{...}');
}

Generic Deserialization

A powerful feature of dart_mappable was and is generic deserialization, where you can deserialize any model based on a generic type parameter. This changes in v2 with the use of MapperContainers:

+ @MappableLib(createCombinedContainer: true)
+ library main;

- import 'main.mapper.g.dart';
+ import 'main.container.dart'; 

T deserialize<T>(String json) {
-  return Mapper.fromJson<T>(value>);
+  return mainContainer.fromJson<T>(value);
}

For the documentation of @MappableLib(createCombinedContainer: true) see here

Mapping Hooks

The MappingHooks class is renamed to MappingHook (singular). Similarly all hooks properties are renamed to hook.

- @MappableClass(hooks: SomeHooks())
+ @MappableClass(hook: SomeHook())
class ...

- class SomeHooks extends MappingHooks { ... }
+ class SomeHook extends MappingHook { ... }
point-source commented 1 year ago

It would be helpful to mention the equivalent code to replace something like this:

T deserialize<T>(String value) {
    return Mapper.fromJson<T>(value);
}

In the current docs, the breaking change seemingly removes the ability to have a generic deserializer. If this is actually the case, I can open a new issue/discussion about that since it is a very powerful feature that at least I rely pretty heavily on.

Edit: This seems possible via documentation here. It would just be nice to have that one specific substitution mentioned in this migration guide since it does affect migration.

point-source commented 1 year ago

I just realized this also required migrating custom mappers. Not sure if you want to include that in this guide but the steps appear to be (roughly):

  1. Remove the CustomMapper() annotation
  2. Rename your class from MyClassMapper to MyClassMapperElement
  3. Change your class to extend from MapperElementBase instead of BaseMapper
  4. Create a private constructor: MyClassMapperElement._(super.mapper, super.container);
  5. Create an additional new class:

    class MyClassMapper extends MapperBase<T> {
    @override
    MapperElementBase<Color> createElement(MapperContainer container) =>
      MyClassMapperElement._(this, container);
    
    @override
    Function get typeFactory => <T>(f) => f<MyClass<T>>();
    }
naveenr-egov commented 7 months ago

It would be helpful to mention the equivalent code to replace something like this:

T deserialize<T>(String value) {
    return Mapper.fromJson<T>(value);
}

In the current docs, the breaking change seemingly removes the ability to have a generic deserializer. If this is actually the case, I can open a new issue/discussion about that since it is a very powerful feature that at least I rely pretty heavily on.

Edit: This seems possible via documentation here. It would just be nice to have that one specific substitution mentioned in this migration guide since it does affect migration.

documentation link is not found @point-source