dart_json_annotations 2.0.0
dart_json_annotations: ^2.0.0 copied to clipboard
High-performance code generation for Dart/Flutter: JSON, copyWith, equatable, and union/sealed class support. Rust-powered CLI with parallel processing.
dart_json_annotations v2.0 #
β οΈ EXPERIMENTAL - This package is under active development. APIs may change without notice.
A high-performance Dart code generator powered by Rust. Generates JSON serializers, copyWith, Equatable, and toString methods with optimized output size for large codebases.
Why v2.0? #
- 70% smaller output - Optimized for 200+ models (< 10k lines)
- Parallel processing - Uses Rust's rayon for multi-core builds
- Single
@Modelannotation - Replaces 4+ separate annotations - Sealed class support -
when/mapmethods like Freezed - Preset patterns - One-liner for common use cases
Features #
- π¦ Rust-powered - Fast parallel code generation
- π¦ Zero runtime dependency - Generated pure Dart code
- π JSON serialization -
toJson(),fromJson(),toJsonString() - π copyWith - Immutable state updates
- βοΈ Equatable - Value equality
- π― Sealed/Union classes -
when,map,maybeWhen,maybeMap - β Checksum caching - Skip unchanged files
Installation #
dependencies:
dart_json_annotations: ^2.0.0
Requirements #
- Dart SDK >= 3.0.0
- Rust - Install Rust
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Global Installation #
dart pub global activate dart_json_annotations
# Build the Rust binary (first time only)
dart_json_gen --build
# Generate code
dart_json_gen -i lib/models
Quick Start #
@Model Presets #
| Preset | Features | Output Size |
|---|---|---|
@Model() |
JSON only | ~25 lines |
@Model.data() |
JSON + copyWith + equatable | ~50 lines |
@Model.bloc() |
copyWith + equatable (no JSON) | ~35 lines |
@Model.full() |
Everything | ~70 lines |
@Model.union() |
Sealed class with when/map | ~60 lines |
Example: JSON-only (minimal) #
import 'package:dart_json_annotations/dart_json_annotations.dart';
import 'user.gen.dart';
@Model() // JSON only - smallest output
class User {
final int id;
final String name;
final String? email;
User({required this.id, required this.name, this.email});
factory User.fromJson(Map<String, dynamic> json) => $UserSerializer.fromJson(json);
}
Example: Data class (common pattern) #
@Model.data(namingConvention: NamingConvention.snakeCase)
class UserProfile {
@JsonKey(name: 'user_id')
final int userId;
final String firstName;
final String lastName;
@Ignore.equality() // Exclude from == comparison
final DateTime updatedAt;
UserProfile({...});
}
Example: Bloc state (no JSON) #
@Model.bloc() // copyWith + equatable, NO json
class CounterState {
final int count;
final bool isLoading;
final String? error;
CounterState({required this.count, required this.isLoading, this.error});
}
// Generated usage:
final newState = state.copyWith(count: state.count + 1);
if (state1.equals(state2)) { ... }
Example: Sealed/Union class #
@Model.union()
sealed class Result {
const factory Result.success(String data) = ResultSuccess;
const factory Result.failure(String error, int code) = ResultFailure;
const factory Result.loading() = ResultLoading;
}
// Generated usage:
final message = result.when(
success: (data) => 'Got: $data',
failure: (error, code) => 'Error $code: $error',
loading: () => 'Loading...',
);
// Optional handling
result.maybeWhen(
success: (data) => print(data),
orElse: () => print('Not success'),
);
// Type checks
if (result.isSuccess) {
final data = result.asSuccess!.data;
}
Annotations Reference #
@Model Options #
@Model(
json: true, // Generate toJson/fromJson (default: true)
copyWith: false, // Generate copyWith (default: false)
copyWithNull: false, // Generate copyWithNull (default: false)
equatable: false, // Generate equals/props (default: false)
stringify: false, // Generate toString (default: false)
union: false, // Generate when/map for sealed classes
namingConvention: NamingConvention.snakeCase,
)
Field Annotations #
| Annotation | Description |
|---|---|
@JsonKey(name: 'custom') |
Custom JSON key |
@JsonKey(ignore: true) |
Skip in JSON |
@JsonKey(defaultValue: '0') |
Default value |
@Ignore() |
Ignore from ALL features |
@Ignore.json() |
Ignore from JSON only |
@Ignore.equality() |
Ignore from == comparison |
@Ignore.copyWith() |
Ignore from copyWith |
@Ignore.stringify() |
Ignore from toString |
CLI Usage #
dart_json_gen [OPTIONS]
OPTIONS:
-i, --input <PATH> Input directory or file
--build Build Rust binary only
--rebuild Force rebuild before generation
--clean Delete all .gen.dart files
--threads <N> Parallel threads (0 = auto)
-v, --verbose Detailed output
-h, --help Show help
EXAMPLES:
dart_json_gen --build # Build binary
dart_json_gen -i lib/models # Generate code
dart_json_gen --clean -i lib # Clean generated files
Output Size Comparison #
For 200 models:
| Preset | Lines/Model | Total |
|---|---|---|
@Model() |
25 | 5,000 β |
@Model.data() |
50 | 10,000 |
@Model.bloc() |
35 | 7,000 β |
@Model.full() |
70 | 14,000 |
Tip: Use @Model() (JSON only) as default, add features only when needed.
Migration from v1.x #
// v1.x (deprecated)
@Json()
@CopyWith()
@Equatable()
class User { ... }
// v2.0 (recommended)
@Model.data() // Same features, less code
class User { ... }
Project Structure #
dart_json_annotations/
βββ bin/dart_json_gen.dart # Dart CLI
βββ codegen/ # Rust source
β βββ Cargo.toml
β βββ src/
β βββ main.rs
β βββ parser/mod.rs
β βββ models/mod.rs
βββ lib/
β βββ dart_json_annotations.dart
β βββ src/annotations.dart
βββ examples/
Roadmap #
- β JSON serialization
- β copyWith / copyWithNull
- β Equatable
- β Naming conventions
- β Checksum caching
- β Parallel processing (rayon)
- β @Model presets
- β Sealed/Union class support
- β Enum support
- β Watch mode
- β Config file
License #
MIT