Exhaustive Mansart reference. For onboarding, see Getting started. For everyday patterns, see Usage.
Maven artefacts
| Artefact | Role |
|---|---|
|
Runtime: |
|
CDI 4.1 Lite bootstrap (BCE): |
|
Shipped SQL dialects ( |
|
APT — static metamodel + |
|
Dialect SPI ( |
|
H2 dialect (test reference + embedded). |
|
PostgreSQL dialect (production target). |
|
CDI 4.1 bootstrap — Vauban-compatible BCE that discovers |
|
Pool public API: |
|
|
|
|
|
POM aggregator. Runtime applications use |
Java modules
| Module | Exports |
|---|---|
|
|
|
|
|
|
|
The core publicly exports the generated-access SPI; model packages have qualified exports to the processor. Dialects and CDI integration are service-based modules. See implemented modules. |
All modules are strict Java Modules — minimal exports, no unjustified opens, no classpath.
Bean archives NEW
mansart-data-cdi and mansart-transactions-cdi are explicit bean archives. Each ships a META-INF/beans.xml with bean-discovery-mode="annotated". A CDI container that does not scan implicit archives, such as Weld SE by default, therefore treats them as bean archives too. The default RepositoryRuntime producer (MansartRuntimeProducer) does not depend on discovery mode: the mansart-data-cdi extension adds it at @Discovery.
Entity annotations
Entities use the standard jakarta.persistence annotations: @Entity, @Table, @Id, @GeneratedValue, @Column, @Version, @Enumerated, @Embedded/@Embeddable, @ManyToOne, @OneToOne, @JoinColumn, @Transient. The processor reads them at compile time; no other annotation set is recognized (the early zero-dep Mansart annotations were retired in M7-29).
NEW An enum attribute is stored as @Enumerated says: @Enumerated(EnumType.ORDINAL), or a bare @Enumerated, stores the constant’s index in an integer column; @Enumerated(EnumType.STRING) stores its name. An enum with no @Enumerated stores its name — unlike Jakarta Persistence, whose default is the index. Mansart keeps the name because it survives a reordering of the constants and because existing tables already hold names. Declare @Enumerated(EnumType.ORDINAL) to get the index.
The storage applies wherever Mansart knows which attribute a value belongs to: inserts and updates, row mapping, projections, WHERE bindings, bulk updates by attribute, and the table DDL Mansart generates (an integer column for ORDINAL). Two paths do not know it yet and still bind a value by its Java type: an aggregate (SELECT MAX(…), …) over an ORDINAL enum, and a JDQL UPDATE … SET that Mansart runs at run time rather than compiling it (a SET with an arithmetic expression, or a statement passed to JdqlExecutor.run). Before 0.4, @Enumerated was ignored and every enum was stored by its name; see Upgrading from 0.3.0 for existing ORDINAL columns.
Outside the Jakarta Data backend scope: @OneToMany, @ManyToMany, @MappedSuperclass, @Inheritance, @Convert/AttributeConverter. Persistence implements these within its documented mapping boundaries.
Repository annotations
| Annotation | Usage |
|---|---|
|
On the interface — triggers APT generation. |
|
Finder method by typed parameters (Java parameter = entity attribute). |
|
JDQL — SELECT/UPDATE/DELETE with named parameters ( |
|
Lifecycle annotations — parameter = entity, collection or varargs; return |
|
Static order on a derived finder; dynamic order via |
|
Routes the repository to a named datasource ( |
Transaction annotations
| Annotation | Usage |
|---|---|
|
CDI interceptor. TxType: |
|
CDI scope whose lifetime matches the transaction. |
PoolConfig configuration
| Property | Type | Description |
|---|---|---|
|
|
Full JDBC URL. |
|
|
DB login. |
|
|
Password. |
|
|
Idle connections kept warm (default 0). |
|
|
Hard pool bound (default 10). |
|
|
Timeout on |
|
|
Eviction of an idle connection (default 10 min). |
|
|
Eviction of an old connection (default 30 min). |
|
|
|
|
|
SQL used by |
|
|
Leak stack-trace if a connection is borrowed longer than the threshold. |
|
|
Bound on a validation probe (default 1 s). |
|
|
Extra driver properties ( |
|
|
Explicit |
Pluggable dialects
| Dialect | Status | Notes |
|---|---|---|
H2 |
✅ Delivered |
Test reference + embedded. |
PostgreSQL |
⏳ M4 |
Production target. |
MariaDB / MySQL |
❌ Backlog |
— |
SQL Server |
❌ Backlog |
— |
Oracle |
❌ Backlog |
— |
SQLite |
❌ Backlog |
— |
Discovered via ServiceLoader (provides DialectFactory with H2DialectFactory).
The core API for tools NEW
io.vidocq.mansart.data.core (artefact mansart-data-core) exposes what a tool needs to describe an application’s entities and to run a JDQL statement typed as text, without re-reading annotations or reflecting on generated classes. The Vidocq dev console uses it for its Mansart Data catalogue and its JDQL prompt. An application does not need it: repositories cover that.
EntityModels.of(Class<E>)-
The
EntityModel<E>Mansart uses for an entity: the generated<package>._<Entity>.$MODELwhen the processor wrote one, otherwise a model built at run time from the entity’s fields and itsjakarta.persistenceannotations. It throws aMansartDataExceptionwhen Mansart cannot map the class (no id field, no no-arg constructor, a package not open toio.vidocq.mansart.data.core). The model’s attributes carry the getter and setter handles Mansart reads and writes the entity with; a tool may use them as Mansart does, but must not change the model.The model is cached with its class (a
ClassValue): a second call returns the same instance, and the model goes away with the class’s loader. Under a dev reload, where the application layer is replaced while Mansart stays, a discarded layer is no longer kept in memory by Mansart. JdqlExecutor.run(jdql, parameters, model, runtime)-
Parses one statement (
FROM …,SELECT … FROM …,UPDATE … SET …orDELETE FROM …) againstmodel, takes each named parameter:namefromparameters.get("name"), and runs it onruntimeas a@Querymethod’s statement would, in whatever transaction the caller has begun. AStringvalue compared or assigned to an attribute that is not text is converted to the attribute’s type: an enum by constant name, thejava.timetypes by ISO parsing, numbers exactly (BigDecimalandBigIntegerincluded),Booleanfromtrue/false,UUID. A positional parameter (?1), a parameter without a value, a value no parameter uses and a value that does not convert are refused before anything runs.The result is a sealed
JdqlResult:Entities,Rows(the columns and rows of a projection),Count(the rows counted, or changed by anUPDATEor aDELETE) orValue(an aggregate’s value). JdqlExecutor.run(jdql, parameters, model, runtime, maxRows)-
The same, reading at most
maxRowsentities or projected rows in the statement’s order, through the dialect’s pagination (a SQLLIMIT): no more is ever read from the database. A count, an aggregate, anUPDATEand aDELETEare not affected.maxRowsbelow 1 is refused. JdqlExecutor.isWrite(jdql),JdqlExecutor.target(jdql)-
Read a statement’s first keyword (is it an
UPDATEor aDELETE?) and the entity it names, without parsing it. Since a statement that puts anUPDATEor aDELETEafter aSELECTclause is refused, a tool can rely on the first keyword to tell a read from a write.
Compatibility
-
Java 25 (LTS), Maven 3.9.16.
-
Jakarta Data 1.0 (delivered), Jakarta Persistence 3.2 (P0–P12 delivered within documented scope), Jakarta Transactions 2.0.
-
CDI 4.1 Lite via Vauban.
-
Virtual Threads for any JDBC execution.
See also
-
Mansart PLAN.md — global vision and work order.
-
mansart-jakarta-data PLAN.md — detailed plan of the Data module.
-
mansart-pool PLAN.md — pool design.
-
mansart-transactions PLAN.md — transactions roadmap.