dart_json_mapper 1.1.7 copy "dart_json_mapper: ^1.1.7" to clipboard
dart_json_mapper: ^1.1.7 copied to clipboard

outdated

This package allows programmers to annotate Dart classes in order to serialize / deserialize them from / to JSON.

dart-json-mapper #

Build Status pub package

This package allows programmers to annotate Dart classes in order to Serialize / Deserialize them to / from JSON.

Why? #

  • Compatible with all Dart platforms, including Flutter and Web platforms
  • No need to extend your classes from any mixins/base/abstract classes to keep code leaner
  • Clean and simple setup, transparent and straightforward usage with no heavy maintenance
  • No extra boilerplate involved, 100% generated only
  • Custom converters support per each class field

Basic setup #

Please add the following dependencies to your pubspec.yaml:

dependencies:
  dart_json_mapper: any
dev_dependencies:
  reflectable: ^2.0.8
  build_runner: ^1.1.2

Library has NO dependency on dart:mirrors, one of the reasons is described here.

Dart classes reflection mechanism is based on reflectable library. This means "extended types information" is auto-generated out of existing Dart program guided by the annotated classes only, as the result types information is accesible at runtime, at a reduced cost.

Say, you have a dart program main.dart having some classes intended to be traveling to JSON and back.

  • First thing you should do is to put @jsonSerializable annotation on each of those classes
  • Next step is to auto generate main.reflectable.dart file. And afterwards import that file into main.dart

lib/main.dart

import 'package:dart_json_mapper/annotations.dart';
import 'package:dart_json_mapper/json_mapper.dart';

import 'main.reflectable.dart'; // Import generated code.

@jsonSerializable // This annotation let instances of MyData traveling to/from JSON
class MyData {
  int a = 123;

  @JsonProperty(ignore: true)
  bool b;

  @JsonProperty(name: 'd')
  String c;

  MyData(this.a, this.b, this.c);
}

main() {
  initializeReflectable(); // Imported from main.reflectable.dart
  
  print(JsonMapper.serialize(MyData(456, true, "yes")));
  // { 
  //  "a": 456,
  //  "d": "yes"
  // }
}

Go ahead and create a build.yaml file in your project root directory. Then add the following content:

targets:
  $default:
    builders:
      reflectable:
        generate_for:
          - lib/main.dart
        options:
          formatted: true

Now run the code generation step with the root of your package as the current directory:

> pub run build_runner build

You'll need to re-run code generation each time you are making changes to lib/main.dart So for development time, use watch like this

> pub run build_runner watch

Each time you modify your project code, all *.reflectable.dart files will be updated as well.

  • Next step is to add "*.reflectable.dart" to your .gitignore
  • And this is it, you are all set and ready to go. Happy coding!

Example with immutable class #

enum Color { Red, Blue, Green, Brown, Yellow, Black, White }

@jsonSerializable
class Car {
    @JsonProperty(name: 'modelName')
    String model;
    
    @JsonProperty(enumValues: Color.values)
    Color color;
    
    @JsonProperty(ignore: true)
    Car replacement;
    
    Car(this.model, this.color);
}

@jsonSerializable
class Immutable {
    final int id;
    final String name;
    final Car car;
    
    const Immutable(this.id, this.name, this.car);
}

print(
  JsonMapper.serialize(
    Immutable(1, 'Bob', Car('Audi', Color.Green))
  )
);

Output:

{
 "id": 1,
 "name": "Bob",
 "car": {
  "modelName": "Audi",
  "color": "Color.Green"
 }
}

Iterable based types handling #

Since Dart language has no possibility to create typed iterables dynamically, it's a bit of a challenge to create exact typed lists/sets/etc via reflection approach. Those types has to be declared explicitly.

For example List() will produce List<dynamic> type which can't be directly set to the concrete target field List<Car> for instance. So obvious workaround will be to cast List<dynamic> => List<Car>, which can be performed as List<dynamic>().cast<Car>().

In order to do so, we'll use Value Decorator Function inspired by Decorator pattern.

final iterableCarDecorator = (value) => value.cast<Car>();
final String json = '[{"modelName": "Audi", "color": "Color.Green"}]';
JsonMapper.registerValueDecorator<List<Car>>(iterableCarDecorator);
JsonMapper.registerValueDecorator<Set<Car>>(iterableCarDecorator);

List<Car> myCarsList = JsonMapper.deserialize(json);
Set<Car> myCarsSet = JsonMapper.deserialize(json);

Basic iterable based generics using Dart built-in types like List<num>, List<Sring>, List<bool>, List<DateTime>, Set<num>, Set<Sring>, Set<bool>, Set<DateTime>, etc. supported out of the box.

For custom iterable types like List<Car> / Set<Car> you have to register value decorator function as showed in a code snippet above before using deserialization. This function will have explicit cast to concrete iterable type.

Enum based types handling #

Enum construction in Dart has a specific meaning, and has to be treated accordingly.

Enum declarations should not be annotated with @jsonSerializable, since they are not a classes technically, but a special built in types.

@JsonProperty(enumValues: Color.values)
Color color;

Each enum based class field has to be annotated as showed in a snippet above. Enum.values refers to a list of all possible enum values, it's a handy built in capability of all enum based types. Without providing all values it's not possible to traverse it's values properly.

Inherited classes derived from abstract / base class #

Please use complementary @Json(includeTypeName: true) annotation for subclasses derived from abstract or base class. This way dart-json-mapper will dump the concrete object type to the JSON output during serialization process. This ensures, that dart-json-mapper will be able to reconstruct the object with the proper type during deserialization process.

@jsonSerializable
abstract class Business {
  String name;
}

@jsonSerializable
@Json(includeTypeName: true)
class Hotel extends Business {
  int stars;

  Hotel(this.stars);
}

@jsonSerializable
@Json(includeTypeName: true)
class Startup extends Business {
  int userCount;

  Startup(this.userCount);
}

@jsonSerializable
class Stakeholder {
  String fullName;
  List<Business> businesses;

  Stakeholder(this.fullName, this.businesses);
}

// given
final jack = Stakeholder("Jack", [Startup(10), Hotel(4)]);

// when
JsonMapper.registerValueDecorator<List<Business>>((value) => value.cast<Business>());
final String json = JsonMapper.serialize(jack);
final Stakeholder target = JsonMapper.deserialize(json);

// then
expect(target.businesses[0], TypeMatcher<Startup>());
expect(target.businesses[1], TypeMatcher<Hotel>());

Using static JsonMapper.typeNameProperty you can specify suitable name for the json property, which will contain the object type:

JsonMapper.typeNameProperty = "objectType";

Custom based types handling #

For the very custom types, specific ones, or doesn't currently supported by this library, you can provide your own custom Converter class per each custom runtimeType.

/// Abstract class for custom converters implementations
abstract class ICustomConverter<T> {
  dynamic toJSON(T object, [JsonProperty jsonProperty]);
  T fromJSON(dynamic jsonValue, [JsonProperty jsonProperty]);
}

All you need to get going with this, is to implement this abstract class

class CustomStringConverter implements ICustomConverter<String> {
  const CustomStringConverter() : super();

  @override
  String fromJSON(dynamic jsonValue, [JsonProperty jsonProperty]) {
    return jsonValue;
  }

  @override
  dynamic toJSON(String object, [JsonProperty jsonProperty]) {
    return '_${object}_';
  }
}

And register it afterwards, if you want to have it applied for all occurrences of specified type

JsonMapper.registerConverter<String>(CustomStringConverter());

OR use it individually on selected class fields, via @JsonProperty annotation

@JsonProperty(converter: CustomStringConverter())
String title;
269
likes
0
pub points
94%
popularity

Publisher

verified publisheredensapple.com

This package allows programmers to annotate Dart classes in order to serialize / deserialize them from / to JSON.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

fixnum, intl, reflectable

More

Packages that depend on dart_json_mapper