d_serializer 1.1.2
d_serializer: ^1.1.2 copied to clipboard
Static JSON serializer with annotation-based generation for Dart
d_serializer #
d_serializer is a static JSON serialization library for Dart and Flutter with annotation-based code generation.
It provides a simple API:
Serializer.toJson<T>(value)Serializer.fromJson<T>(json)
And a codegen flow that avoids manual toMap/fromMap boilerplate for each model.
Features #
- Annotation-based model generation with
@Serializable() - Static serializer API (
toJson/fromJson) - Registry bootstrap via generated
initializeDSerializer() - Field controls via
@JsonKey(...) - Formatter pipeline via
@Format(...) - Strict and safe deserialization options
- Support for common Dart types and nested models
Installation #
dependencies:
d_serializer: ^1.0.2
dev_dependencies:
build_runner: ^2.10.3
d_serializer_builder: ^1.0.2
Quick Start #
1) Create a model #
import 'package:d_serializer/d_serializer.dart';
part 'user.g.dart';
@Serializable()
class User {
@JsonKey(requiredKey: true)
final int id;
@JsonKey(requiredKey: true)
final String name;
User({required this.id, required this.name});
}
2) Generate code #
dart run build_runner build --delete-conflicting-outputs
3) Initialize registry once #
import 'd_serializer_registry.g.dart';
void main() {
initializeDSerializer();
}
4) Serialize / deserialize #
final user = User(id: 1, name: 'Abner');
final json = Serializer.toJson<User>(user);
final restored = Serializer.fromJson<User>(json);
API #
Serializer #
Serializer.register<T>({fromJson, toJson})Serializer.toJson<T>(value)Serializer.fromJson<T>(json)Serializer.formatDate(value, pattern)Serializer.parseDate(value, pattern)
@Serializable(...) #
Class-level options:
renamediscriminatortypeFieldstrictnaming(JsonNaming.none,JsonNaming.snakeCase)
@JsonKey(...) #
Field-level options:
nameignoredefaultValueconverteruseEnumIndexrequiredKeyunknownEnumValue
@Format(...) #
Field formatter pipeline (applied in both toJson and fromJson).
| Formatter | Supported field types | Notes |
|---|---|---|
@Format.trim() |
String, String? |
Trims leading/trailing whitespace |
@Format.uppercase() |
String, String? |
Uppercase transformation |
@Format.lowercase() |
String, String? |
Lowercase transformation |
@Format.date('yyyy-MM-dd') |
DateTime, DateTime? |
Uses built-in formatter/parser |
@Format.date('iso8601') |
DateTime, DateTime? |
Uses toIso8601String/DateTime.parse |
@Format.custom('X') |
Any | Uses custom formatter functions |
Pipeline order:
- Formatters are applied in annotation order.
- Same order is applied in
toJsonand infromJson.
Build-time validation:
- String formatters on non-string fields fail generation.
- Date formatter on non-date fields fails generation.
- Empty
@Format.custom('')fails generation.
@Format.custom('X') contract:
Define top-level functions visible in the same model library scope:
XFormatToJson(dynamic value)XFormatFromJson(dynamic value)
Complete Structured Example #
A production-like sample is included in this package:
lib/example/models/user_profile.dartlib/example/models/address.dartlib/example/models/geo.dartlib/example/models/user_status.dartlib/example/models/money.dartlib/example/formatters/title_case_formatter.dartlib/example/formatters/money_converter.dartexample/example.dart
This sample demonstrates:
- nested models
- enum fallback with
unknownEnumValue List<T>,Set<T>, andMap<String, T>@JsonKey(requiredKey, defaultValue, ignore, converter)@Format.trim()and@Format.custom('TitleCase')@Serializable(strict, naming, typeField, discriminator)
Run the sample:
dart run build_runner build
dart run example/example.dart
Advanced Examples #
Custom converter (@JsonKey(converter: 'Money')) #
class Money {
final int cents;
const Money(this.cents);
}
Object? MoneyToJson(dynamic value) => (value as Money).cents;
Money MoneyFromJson(dynamic value) => Money((value as num).toInt());
@Serializable()
class Invoice {
@JsonKey(converter: 'Money')
final Money total;
Invoice({required this.total});
}
Custom formatter (@Format.custom('TitleCase')) #
String TitleCaseFormatToJson(dynamic value) {
final input = (value as String).trim().toLowerCase();
if (input.isEmpty) return input;
return input[0].toUpperCase() + input.substring(1);
}
String TitleCaseFormatFromJson(dynamic value) {
return TitleCaseFormatToJson(value);
}
@Serializable()
class Post {
@JsonKey(requiredKey: true)
@Format.custom('TitleCase')
final String title;
Post({required this.title});
}
Discriminator support #
@Serializable(typeField: 'kind', discriminator: 'order')
class OrderEvent {
final int id;
OrderEvent({required this.id});
}
Unknown key policy (strict) #
@Serializable(strict: true)
class StrictModel {
final int id;
StrictModel({required this.id});
}
Supported Types #
int,double,String,bool,dynamicDateTime,Uri,BigInt,DurationList<T>,Set<T>,Map<String, T>- Enums (by name or index)
- Nested
@Serializable()models
Build Workflow #
Do I need to run build every time? #
Not for every run.
- If you changed annotated models: regenerate.
- If models did not change: no manual regeneration needed.
Recommended during development:
dart run build_runner watch --delete-conflicting-outputs
Recommended for CI/release:
dart run build_runner build --delete-conflicting-outputs
Troubleshooting #
-
Type X is not registered:- Run code generation.
- Call
initializeDSerializer()before use.
-
Converter function not found:
- Ensure
XToJson/XFromJsonexist as top-level functions and are visible in the model library.
- Ensure
-
Custom formatter function not found:
- Ensure
XFormatToJson/XFormatFromJsonexist as top-level functions and are visible in the model library.
- Ensure
-
Unknown fields error:
- Check
@Serializable(strict: true)behavior or disable strict mode.
- Check
License #
MIT