ADL vs JHipster
JHipster Agrees With Us Right Up to the Moment It Generates
TL;DR: Of every tool in this series, JHipster starts closest to ADL. Its JDL language declares entities, relationships, and behavior options in a compact DSL: the same bet ADL makes about where a backend should be defined. Then the two projects give opposite answers to the next question: what is the DSL for? JHipster says it is a seed for generating code you will own. ADL says it is the application, interpreted directly. Everything that separates the two tools (the day-2 story, the regeneration problem, the size of what you review) follows from that single fork.
The steelman
JHipster is one of the most complete acts of generosity in open source. One command line, one JDL file:
entity Article {
title String required maxlength(255)
content TextBlob
publishedDate Instant
}
entity Author {
name String required
}
relationship OneToMany {
Author{articles} to Article{author}
}
paginate Article with pagination
dto * with mapstruct
service Article with serviceClass
and you receive a production-grade Spring Boot application: JPA entities, repositories, services, REST controllers, DTOs with MapStruct mappers, Liquibase changelogs, Spring Security wiring, a full Angular, React, or Vue frontend with working CRUD screens, tests for all of it, Docker configs, CI pipelines. Not a scaffold — an application that runs, deploys, and passes its own test suite before you have written a line.
And notice what JDL itself is. It is a description language. Entities, fields, constraints, relationships, cross-cutting options (paginate, dto, service). All declared, not coded. The JHipster team looked at the ceremony of a Java web stack and concluded, exactly as ADL does, that the interesting part of a backend is a declaration compact enough to read in one sitting. A useful JDL file is often under a hundred lines. The generated application is tens of thousands.
That ratio is JHipster’s proudest number. It is also the whole disagreement.
Same input theory, opposite execution theory
ADL and JDL agree on the input: the domain should be declared. They disagree on what execution means.
JHipster treats the declaration as a seed. The DSL is consumed once (or per re-import), and its meaning is transcribed into Java, TypeScript, XML, and YAML that you now own. From that moment the JDL file and the application are two artifacts, and only one of them is authoritative — and it is not the DSL. The truth of the system lives in the generated-then-edited code.
Kalos treats the declaration as the program. kalosd interprets the ADL file on every request. There is no transcription step, so there is no second artifact to drift from the first. The YAML is not documentation of the application; it is the application.
This sounds philosophical until day 2, when it becomes extremely practical.
Day 2: the regeneration wound
Add one field to one entity.
In Kalos: edit the YAML, and the runtime migrates the schema and serves the new field (with its validation, permissions, and history rules) because those are declarations too. The diff you review is the diff you wrote: a few lines.
In JHipster: re-import the JDL, and the generator rewrites the files it owns: entity, DTO, mapper, service, controller, Liquibase changelog, frontend components, tests. If you have never touched those files, this is fine. But you have touched them, because JHipster generates CRUD and your application is not CRUD; the business logic that makes it yours was hand-written into the generated service layer. Now the regeneration collides with your edits, and you are in a merge: reviewing a diff measured in thousands of lines to accept a change you could state in one.
This is not a bug and JHipster does not hide it. The project’s own guidance (commit before regenerating, resolve with git merge tooling, keep customizations in side-by-side classes that extend generated ones so the generator’s territory stays clean) is mature, honest engineering advice for living with generation. But read that advice again as an architecture review: the recommended pattern is to organize your entire codebase around not touching the code you were given. The generated mass is treated, in practice, as something between an asset and a hazard: regenerable, therefore not really yours to edit, yet fully yours to maintain, secure, and audit.
That is the liability-surface argument, told by someone else’s documentation. Every generated line is a line your team reviews in diffs, your scanners flag, your upgrades break, and your auditors read. The declaration stayed under a hundred lines; the liability did not.
The vocabulary gap
There is a second, quieter difference: how much the DSL can say.
JDL’s vocabulary covers structure and generation options: entities, typed fields with bean-validation constraints (required, min/max, pattern, unique), relationships, pagination, DTO and service strategy. It is a vocabulary about the code to be produced.
It has no way to say: this operation requires this role; this field is readable by HR and the owner but writable only by HR; this status may move from draft to published only by an editor, only if an excerpt exists, setting publishedAt on the way through; this total is the sum of related line items and recalculates when they change. In JHipster, all of that is exactly the hand-written Java that regeneration must then merge around. In ADL, it is more declaration — the permissions block, the state machine, the computed field — interpreted with the same authority as the schema, and intercepting the same bypasses (a direct PATCH to a state-machine field executes the transition’s guards or is rejected; it cannot sneak past them).
So the fork compounds: JHipster’s DSL stops earlier and what lies beyond it becomes merge-hostile code. ADL’s vocabulary is larger precisely so that the day-2 diff stays declaration-sized.
The honest concessions
Two, and neither is small.
JHipster ships a frontend. Kalos renders nothing. A JHipster run ends with working screens (list views, edit forms, login) in the SPA framework of your choice. ADL chapter 43 defines UI intent vocabulary that a client may consume; the runtime draws no pixels. If your measure of “application” includes something a user can click on ten minutes after you start, JHipster delivers that and Kalos does not. Frontends against Kalos are consumers of its API and schema endpoint, built with your framework and your effort.
Generated code has zero runtime lock-in. If the JHipster project vanished tomorrow, every JHipster application keeps running, because each one is a normal Spring Boot app with no dependency on its generator. Betting on Kalos means trusting an interpreter to keep executing your declarations correctly — a different and real dependency, and the fair price of keeping the liability surface flat. It is the strongest argument for generation, and it deserves to be stated at full strength rather than waved at.
Closer
JHipster and ADL read the same file and see different things: JHipster sees a seed for the codebase you will maintain; ADL sees the only thing worth maintaining.