fjson CLI — Dart Bean Generator
The fjson CLI generates @JsonSerializable Dart entity classes from JSON responses and regenerates .g.dart serialization helpers, json_field.dart, and json_convert_content.dart. It replaces the FlutterJsonBeanFactory IntelliJ plugin for CLI/agent workflows.
The bundled JAR lives inside this skill directory: fjson-cli.jar. Invoke it as:
java -jar <path-to-skill>/fjson-cli.jar <command> [options]
When running from the unyo project root, the skill is at .agents/skills/fjson-dart-bean-generator/:
java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar <command> [options]
If you need to rebuild the JAR (rare — only after modifying fjson-cli source):
cd ../fjson-cli && ./gradlew jar
# Then copy the new JAR into the skill:
cp ../fjson-cli/build/libs/fjson-cli.jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar
Two Commands
| Command | Purpose | When to use |
|---|---|---|
fjson bean |
Create a new entity .dart file from JSON |
User provides a class name + JSON (string or file) |
fjson gen |
Regenerate all .g.dart helpers, json_field.dart, json_convert_content.dart |
After adding/modifying any @JsonSerializable class |
Important:
fjson beanautomatically runsfjson genwhen invoked inside a Flutter project (one with apubspec.yaml). You do NOT need to rungenseparately afterbean.
fjson bean — Generate a new entity from JSON
Required flags
| Flag | Description | Example |
|---|---|---|
--class <Name> |
Root class name (use the API response root name) | --class MediaResponse |
--json <string> |
Raw JSON string | --json '{"id":1,"title":"..."}' |
--file <path> |
Path to a .json file (alternative to --json) |
--file response.json |
Optional flags
| Flag | Description | Default | When to use |
|---|---|---|---|
--output <path> |
Directory for the generated .dart file |
./lib |
Direct entity to correct DTO subfolder |
--suffix <text> |
Suffix appended to generated class names | entity |
Leave as default for unyo |
--nullable |
Make fields nullable (Type?) |
off | Rarely needed in unyo |
--set-default |
Assign default values to primitive fields | off | Always use this for unyo DTOs |
--project <path> |
Flutter project root | . |
Usually not needed from unyo root |
Typical unyo invocation
java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar bean \
--class MediaCollectionResponse \
--json '<paste JSON here>' \
--output ./lib/core/services/api/dto/anilist/ \
--set-default
Or from a file:
java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar bean \
--class AnizipEpisodeInfo \
--file ./response.json \
--output ./lib/core/services/api/dto/anizip/ \
--set-default
What gets generated
The command produces a .dart file containing:
- A root
@JsonSerializable()class with--suffixappended (e.g.,MediaCollectionResponse→MediaCollectionResponseEntity) - Nested
@JsonSerializable()classes for each nested JSON object (e.g.,MediaCollectionResponseDtoPage) @JSONField(name: 'original_key')annotations for keys whose Dart naming differs from JSONlatefields with default values (if--set-default)fromJson()factory andtoJson()method stubsimportofjson_field.dartand the matching.g.dartexportof the matching.g.dart
The generated entity also auto-triggers fjson gen, so the matching .g.dart, json_field.dart, and json_convert_content.dart are all regenerated immediately.
fjson gen — Regenerate all helpers
java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar gen --project .
This scans lib/**/*.dart for every @JsonSerializable class and:
- Regenerates each
<entity>.g.dartfile inlib/generated/json/ - Rebuilds
lib/generated/json/base/json_field.dart(annotation definitions) - Rebuilds
lib/generated/json/base/json_convert_content.dart(theJsonConvertruntime andJsonConvertClassCollectionregistry with all entity imports) - Deletes any stale
.g.dartfiles for entities that no longer exist
Run this after any manual edit to an entity file (adding/removing/renaming fields).
Generated File Layout in unyo
unyo/
├── lib/core/services/api/dto/
│ └── anilist/
│ └── media_response_entity.dart ← fjson bean output
└── lib/generated/json/
├── media_response_entity.g.dart ← auto-generated helpers
├── media_collection_graphql_entity.g.dart ← existing
├── ... ← all other .g.dart
└── base/
├── json_field.dart ← annotations
└── json_convert_content.dart ← registry + runtime
Entity file naming convention in unyo
- Snake_case filenames: e.g.,
media_details_graphql_entity.dart - PascalCase class names: e.g.,
MediaDetailsGraphqlEntity - fjson converts PascalCase
--classnames to snake_case filenames automatically - Always place entities in the correct DTO subfolder:
lib/core/services/api/dto/<provider>/- Providers:
anilist/,anizip/,aniskip/,extensions/
- Providers:
Default unyo settings that fjson matches
--set-defaultis always used → all fields get= '',= 0,= false, etc.--suffix entity(default) → class names end withEntityflutter_json.generated_pathisgenerated/jsoninpubspec.yaml
Workflow: Adding a new API response model
- Get the JSON — Either from the user, from a file, or from a GraphQL response
- Determine the provider (anilist, anizip, aniskip, extensions)
- Run
fjson beanwith--class,--json/--file,--output, and--set-default:java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar bean \ --class NewApiResponse \ --json '<the JSON>' \ --output ./lib/core/services/api/dto/anilist/ \ --set-default - Verify the output — Open the generated
.dartfile and check:- Class names and field types are correct
- Nested objects are properly generated as sub-classes
@JSONField(name: ...)mappings are correct for non-matching keys
- Update
json_convert_content.dart— Already done automatically byfjson gen(triggered byfjson bean). Verify the new entity's import is present. - Run analysis —
flutter analyzeto ensure no issues - If fields need adjustment — Edit the entity file directly, then re-run
fjson gen:java -jar .agents/skills/fjson-dart-bean-generator/fjson-cli.jar gen --project .
Common Pitfalls
- Wrong
--outputpath: Entity files must go to the correct provider subfolder (lib/core/services/api/dto/<provider>/) for the import injson_convert_content.dartand.g.dartfiles to resolve correctly. - Forgetting
--set-default: Without it, fields uselatewithout defaults. In unyo, all DTO fields have defaults (exceptdynamic). - Running in wrong directory: Commands assume the current working directory is the unyo project root (where
pubspec.yamllives). The--projectflag overrides this. - Class name collision: If a class name already exists in another entity file, the generated
.g.dartwill have duplicate function names, causing compile errors. Check for existing names before running. - JSON with empty arrays: fjson handles this but cannot infer the element type of an empty
List. The field will be typedList<dynamic>and must be corrected manually. - After running
beanin a non-Flutter directory:fjson genis skipped. You must manually run it from the project root.
Cross-references
- unyo project structure and entity patterns: See
unyo-domain-data-layerskill - DTO conventions and GraphQL response mapping: See
unyo-domain-data-layerskill - Rebuilding fjson-cli from source: See
../fjson-cli/README.md