A deterministic, template-driven code generation toolkit for building CRUD-style microservices β designed for environments where consistency, control, and scalability matter more than automation magic.
If your backend looks like this:
- dozen of models
- hundreds of fields
- dozens of nearly identical services, repositories, controllers
- the same validation and business rules repeated again and again
β¦then youβre not writing code β youβre rewriting patterns.
Instead of generating code directly with AI or scaffolding tools:
Build your own code generator β and reuse it.
Define:
- your style (templates)
- your domain (data)
Then generate everything else β deterministically.
Typical tools:
- generate only the project skeleton
- enforce their own architecture
- or produce non-deterministic results (AI)
This tool:
- generates entire vertical slices
- keeps full control over architecture and style
- works deterministically
- scales to large codebases
Use AI to:
- extract data from requirements
- help build templates
- assist with mapping and enrichment
But let the generator produce the final code.
Instead of writing:
(the same CRUD + patterns) Γ N models
you define them once β and regenerate when needed.
β¬οΈ Scroll down for architecture, workflow, and examples.
This project is a code generation toolkit, not a ready-to-use generator.
It allows you to:
- define your own code style using templates,
- describe your domain using structured data,
- generate large amounts of repeatable, consistent code,
- keep full control over the output.
It was created to speed up development of enterprise microservices where a large part of the codebase follows repeatable CRUD-like patterns, often extended with recurring business rules.
The goal is not to eliminate engineering work. The goal is to reduce repetitive work and make the remaining manual work more focused.
In real enterprise systems, a large amount of code is repetitive.
For many domain models, developers end up creating the same overall structure again and again: a similar vertical slice, often consisting of many classes across API, application, domain, infrastructure, tests, and database-related code.
That kind of repetition is exactly what code generators are good at.
But repetition does not stop at the structural level. Even business logic often contains recurring patterns, such as:
- uniqueness checks,
- existence checks for referenced objects,
- active/inactive checks,
- flag-based constraints,
- date-related rules,
- status-dependent behavior.
So the goal is not only to generate CRUD-like structure, but also to capture and reuse repeated business-rule patterns where that is practical.
This project formalizes that workflow.
Instead of repeatedly copying and rewriting code, you can:
- create or reuse example code,
- turn it into templates,
- describe the domain as data,
- regenerate the repetitive parts as often as needed.
The central idea is to separate:
- Data (D) β the domain description and generation input,
- Style (S) β templates, conventions, and code structure,
- translation logic β mapping and enrichment,
- reusable infrastructure β common low-volatility building blocks.
In practice, instead of manually producing code as:
D Γ S where D = data and S = style,
you define:
D + S where D = data and S = style,
and let the generator produce the repetitive result.
This also makes the process cheaper and easier to support with AI, because data and style are handled separately instead of being mixed into one large prompt.
This tool is intentionally minimal:
- implemented in Java
- generates Java code
- requires only a small set of dependencies (FreeMarker)
This makes it easy to adopt in constrained environments (e.g. corporate setups), where:
- installing additional runtimes (like Node.js) is restricted,
- developers are expected to work within a single technology stack,
- tooling must remain transparent and controllable.
FreeMarker was chosen deliberately, as it integrates well with IntelliJ and is widely understood.
A major goal of this project is determinism.
The final code should be generated by the generator, not directly by AI.
Why:
- the output is repeatable,
- the author keeps architectural control,
- the workflow scales better for large codebases,
- token usage stays lower,
- the result is easier to reason about than one-off AI output.
This matters especially in enterprise environments, where the generated code must fit an existing architecture and coding style rather than follow a generic framework opinion.
AI is meant to assist the process, not replace the generator.
Recommended use cases:
- extracting CSV input data from requirements or analysis documents,
- helping refine templates after automated conversion,
- generating mapping code from CSV input into the template data model,
- generating data enrichment logic,
- optionally helping with non-standard business rules as a post-generation step.
The final source code should still be produced by the deterministic generator.
This documentation was vibe coded β the tool itself was not.
Because AI and deterministic generation solve different problems.
AI is useful for:
- drafting,
- transformation,
- filling gaps,
- reducing manual work during generator development.
But direct AI code generation has trade-offs:
- non-deterministic results,
- inconsistent output between runs,
- expensive context requirements for large codebases,
- weaker control over style and architecture.
This project takes a different path:
- AI can help create the generator inputs and style,
- the final repetitive code is generated by a controlled tool.
Because this project solves a different problem.
Spring Initializr helps bootstrap a project, but it does not generate the repetitive CRUD and business-pattern code inside the microservice.
JHipster is powerful, but in many enterprise environments it is a poor fit:
- it is opinionated,
- it assumes its own ecosystem and conventions,
- it adds tooling overhead,
- it may not fit restricted corporate environments,
- it does not give the same level of fine-grained control over internal style.
CodeTools is intended for cases where:
- the architecture already exists,
- the coding style is already defined,
- the team wants full control,
- the repetitive work is inside the service implementation, not just in project bootstrap.
The generation process is intentionally straightforward:
- Load input data (CSV)
- Map it to a template data model
- Enrich it using processors
- Pass the same data to all templates
- Iterate over template definitions (
templates.csv) - For each template:
- decide when it should be executed (e.g. per model, per context),
- generate file content using FreeMarker,
- write the output file
There is no complex orchestration layer β just structured data and repeatable rules.
This is a toolkit-style workflow, not a one-click pipeline.
Create or reuse example code that represents the style you want to reproduce.
This may be:
- a vertical slice,
- a set of classes,
- or even a larger microservice fragment.
Use StyleGenerator to extract templates:
- based on a manually prepared
templates.csv, - inline markers in code,
- configuration defined in the generator code, which typically requires manual refinement.
This means the conversion step is not just automatic extraction. You also need to define the template list and adjust the generated configuration and templates manually.
Manually improve the generated templates.
The expectation is not full automation. The expectation is that a substantial part of the repetitive work has already been done for you.
Prepare structured input data, typically in CSV files such as:
microservice.csvmodels.csvfields.csvgroups.csvcontexts.csvrules.csv
AI can help with that.
Implement code that maps the input CSV model into the data model used by templates.
AI can help with that.
Add processors that compute extra structure, relations, derived values, or other generation-ready information.
AI can help with that.
Run the code generator to produce the output files.
Adjust templates, mapping, processors, or input data and generate again.
The goal is speed and leverage, not necessarily perfect generation on the first attempt.
Style example: https://github.com/archonity/enterprise-crud-classic-example
Generated output: https://github.com/archonity/enterprise-crud-classic-generated
Example data for the CRM style is stored in:
data/crm/microservice.csvdata/crm/models.csvdata/crm/fields.csvdata/crm/groups.csvdata/crm/contexts.csvdata/crm/rules.csv
These files describe the domain input used by the example style-specific generator.
A single generation run may produce many files, for example:
- domain classes,
- repositories,
- services,
- mappers,
- REST resources,
- DTOs,
- Liquibase changelogs,
- fixtures,
- integration tests,
- supporting infrastructure classes.
In practice, the output is intentionally large β that is the point of the tool.
Simplified overview:
-
reusable/- reusable low-volatility building blocks shared across tools and styles
-
styles/*/- style-specific implementations
- new styles should be created here, each in its own package
- styles can be copied, adapted, and evolved independently
- the repository currently contains one example style:
crm
Within each styles/*/ style:
-
codegen/- the style-specific code generator
-
stylegen/- the style-specific code-to-template conversion tool
Within each styles/*/codegen/ package, the most important areas are:
-
data/- the style-specific input model and template data model
- includes mapping from source data into the model used by templates
-
dataprocessor/- style-specific enrichment and transformation logic
- this is one of the main places where generation behavior is customized
-
template/- template root definitions used by the generator
- corresponds to the FreeMarker templates stored in
src/main/resources/...
Also important:
-
src/main/resources/com/codetools/styles/*/codegen/- style-specific FreeMarker templates and related template resources
In practice, the main extension point of the repository is the styles/*/ area:
- create a new style,
- define its generator,
- define its template conversion process,
- define its data model and processors,
- add or modify the corresponding FreeMarker templates.
The repository is organized around the idea that:
- some parts are highly reusable,
- some parts are style-specific,
- styles can evolve independently while still using shared infrastructure.
At the moment, the repository contains a CRM style example with:
- a style-specific generator,
- a style-specific code-to-template conversion tool,
- a style-specific CSV model,
- a style-specific template data model,
- style-specific templates and processors.
This structure is intended to support multiple styles over time.
- prototype,
- experimentally evolved through real use,
- already used to generate production code,
- used with multiple independent code styles, including at least four in practice.
This repository currently contains one example style as a reference implementation.
This project may be useful for:
- backend developers working on repetitive CRUD-heavy systems,
- architects who need strong control over generated code,
- teams maintaining internal architectural conventions,
- engineers who want AI assistance without giving up determinism.
It is probably not useful for someone looking for a plug-and-play generator with zero setup.
This project intentionally avoids over-engineering.
In practice, attempts to over-design code generators often lead to:
- unnecessary abstractions,
- premature generalization,
- increased complexity without real benefit.
Instead, this approach favors:
- simple data flow (load β map β enrich β generate),
- minimal assumptions,
- incremental evolution,
- extracting reusability only when it naturally appears (bottom-up).
The generator is designed to stay understandable and adaptable, rather than βperfectly abstractβ.
The generator itself is intentionally pragmatic. It may contain shortcuts or style-specific logic, as its primary goal is to enable fast iteration and effective code generation, not to serve as a general-purpose framework.
This code does not aim to be "perfect" or highly reusable in the traditional sense. In practice, the generator is adapted per use case (per code style), so reusability is not the primary goal.
Some parts may be fragile or implemented as quick solutions β this is a conscious trade-off. The generator is typically used intensively for a period of time, and then left unchanged once the target code is generated.
This is not a statement against clean code principles. In general, reusable, non-fragile, and flexible code is preferable. However, in this specific context, prioritizing speed and effectiveness often leads to more pragmatic solutions.
As long as the generated code is correct and maintainable, this trade-off is acceptable. The generator itself can always be improved later β or rewritten differently for another use case.
This is not:
- a universal code generator,
- a low-code platform,
- a one-click framework bootstrapper,
- a promise of perfectly compiling output in every workflow.
You are expected to:
- shape the style to your own needs,
- adapt the generator,
- refine templates,
- treat generation as a productivity tool rather than a magic final step.
Depending on the workflow, the generated application may still require manual setup or post-generation fixes.
This approach has been used in real-world projects over an extended period.
Example observations:
- Generating a large microservice (dozens of models, tens of thousands of lines of code) can be reduced from months of manual work to weeks of combined template + generation work.
- In one case, a complex service was effectively rebuilt using the generator faster than extending the existing codebase.
These results depend heavily on the use case, but the approach consistently reduces repetitive work significantly.
Rough estimates suggest that this approach can reduce repetitive coding effort by more than half in CRUD-heavy systems.
MIT License
The goal is not perfect code generation.
The goal is to save time.
If the generator removes most of the repetitive work and leaves only the valuable, case-specific work to humans, then it is doing its job.