dart_json_annotations 2.2.0
dart_json_annotations: ^2.2.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.2.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.1
Requirements #
- Dart SDK >= 3.0.0
- Rust - Install Rust
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Clone and setup
git clone https://github.com/djsmk123/dart_json_annotations.git
cd dart_json_annotations
# Active local
dart pub global activate -s path .
# Build the Rust binary (first time only)
dart_json_gen --build
# Generate code
dart_json_gen -i lib/models
Local Installation #
Quick Start #
Basic Usage #
All features are now specified using explicit parameters on the @Model annotation:
@Model(
fromJson: true, // Generate fromJson
toJson: true, // Generate toJson
copyWith: true, // Generate copyWith
equatable: true, // Generate == and hashCode
stringify: true, // Generate toString
)
Example: JSON-only (minimal) #
import 'package:dart_json_annotations/dart_json_annotations.dart';
part 'user.t.dart';
@Model(fromJson: true, toJson: true) // 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) => _$UserFromJson(json);
}
Example: Data class (common pattern) #
part 'user_profile.t.dart';
@Model(
fromJson: true,
toJson: true,
copyWith: true,
equatable: true,
namingConvention: NamingConvention.snakeCase,
)
class UserProfile {
@JsonKey(name: 'user_id')
final int userId;
final String firstName;
final String lastName;
@Ignore(equality: true) // Exclude from == comparison
final DateTime updatedAt;
UserProfile({
required this.userId,
required this.firstName,
required this.lastName,
required this.updatedAt,
});
factory UserProfile.fromJson(Map<String, dynamic> json) => _$UserProfileFromJson(json);
}
Example: Bloc state (no JSON) #
part 'counter_state.t.dart';
@Model(copyWith: true, equatable: true) // 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 == state2) { ... } // Uses generated == operator
Example: Sealed/Union class #
Union classes support all parameter styles:
- No parameters:
factory Event.reset() = EventReset; - Positional:
factory Event.setValue(int value) = EventSetValue; - Named:
factory Event.load({required String id}) = EventLoad; - Mixed:
factory Event.update(int id, {String? reason}) = EventUpdate;
part 'result.t.dart';
@Model(fromJson: true, toJson: true, equatable: true)
sealed class Result {
const Result._();
factory Result.fromJson(Map<String, dynamic> json) => _$ResultFromJson(json);
// Different parameter styles all supported
const factory Result.success(String data) = ResultSuccess;
const factory Result.failure(String error, int code) = ResultFailure;
const factory Result.loading() = ResultLoading;
const factory Result.retry({required int attempt}) = ResultRetry;
}
// Generated usage:
final message = result.when(
success: (data) => 'Got: $data',
failure: (error, code) => 'Error $code: $error',
loading: () => 'Loading...',
retry: (attempt) => 'Retry #$attempt',
);
// 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(
fromJson: false, // Generate fromJson (default: false)
toJson: false, // Generate toJson (default: false)
copyWith: false, // Generate copyWith (default: false)
copyWithNull: false, // Generate copyWithNull (default: false)
equatable: false, // Generate == and hashCode (default: false)
stringify: false, // Generate toString (default: false)
mutable: false, // Generate mutable class (default: false)
namingConvention: NamingConvention.camelCase, // Naming convention
discriminator: 'type', // Discriminator field for union classes
)
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: true) |
Ignore from JSON only |
@Ignore(equality: true) |
Ignore from == comparison |
@Ignore(copyWith: true) |
Ignore from copyWith |
@Ignore(stringify: true) |
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 generated files (use with -i to specify path)
--threads <N> Parallel threads (0 = auto)
-v, --verbose Detailed output (shows parsing, generation steps)
-h, --help Show help
EXAMPLES:
dart_json_gen --build # Build binary
dart_json_gen -i lib/models # Generate code
dart_json_gen -i lib/models --verbose # Generate with detailed logs
dart_json_gen --clean -i lib/models # Clean generated files in lib/models
dart_json_gen --clean -i lib/user.dart # Clean specific file's generated code
dart_json_gen -i lib --threads 4 # Use 4 threads
Configuration File #
Create a dart_json_gen.yaml (or dart_json_gen.yml) file in your project root to customize the generator:
# Custom extension for generated files
# Default: .t.dart
# Examples: .gen.dart, .g.dart, .generated.dart
generated_extension: ".t.dart"
Example configurations:
# Use .g.dart extension (like json_serializable)
generated_extension: ".g.dart"
# Use .t.dart extension
generated_extension: ".t.dart"
# Use .generated.dart extension
generated_extension: ".generated.dart"
Note: After changing the extension in the config file:
- Clean old generated files:
dart_json_gen --clean -i lib/models - Regenerate with new extension:
dart_json_gen -i lib/models
Verbose Mode #
Use --verbose or -v to see detailed logging during code generation:
dart_json_gen -i lib/models --verbose
Output includes:
- Files being parsed
- Classes found in each file
- Variant names for union/sealed classes
- Files being generated or skipped
- Detailed generation progress
Example verbose output:
[VERBOSE] Parsing 10 Dart files...
[VERBOSE] Found 3 class(es) in lib/models/user.dart
[VERBOSE] Source: lib/models/user.dart
[VERBOSE] Processing: lib/models/user.dart
[VERBOSE] Generating code for 3 class(es) in user.gen.dart
[VERBOSE] Written: lib/models/user.gen.dart
Output Size Comparison #
For 200 models:
| Configuration | Lines/Model | Total |
|---|---|---|
JSON only (fromJson, toJson) |
25 | 5,000 β |
Data class (fromJson, toJson, copyWith, equatable) |
50 | 10,000 |
Bloc state (copyWith, equatable) |
35 | 7,000 β |
| Full features (all enabled) | 70 | 14,000 |
Tip: Start with JSON-only features, add copyWith and equatable only when needed.
Migration from v1.x #
// v1.x (deprecated - used separate annotations)
@Json()
@CopyWith()
@Equatable()
class User { ... }
// v2.0+ (current - use explicit parameters)
@Model(
fromJson: true,
toJson: true,
copyWith: true,
equatable: true,
)
class User { ... }
Note: Preset constructors like @Model.json(), @Model.data(), etc. have been removed in favor of explicit parameters for better clarity and flexibility.
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 || Do we really need this? because it is already instant generation
- β Config file
License #
MIT