Chenile 2.1.35
Tagged October 27, 2026. The framework repositories carry annotated 2.1.35 tags (chenile-parent and
chenile-core on October 27). JGen 2.1.35 was released on October 31: the distribution zip and jgen-cli.jar are on
the GitHub release, and it installs with Homebrew
(brew install ajapros/jgen-tap/jgen) and JBang. JGen features merged after the tag are in the
2.1.36 notes.
Choose the implementation per request: serviceSelector
A Chenile service can now name a ServiceSelector — @ChenileController(serviceSelector = "..."), or
"serviceSelector" in a JSON service definition. The selector is a Spring bean implementing
org.chenile.core.service.ServiceSelector:
String selectServiceReferenceName(ChenileExchange exchange, ChenileServiceDefinition serviceDefinition);
It runs on every invocation inside constructServiceReference and returns the bean name of the implementation
to call, or null to keep the service’s configured serviceName. Resolution order is fixed: mock mode,
then a trajectory override, then the selector, then the default bean. A selector bean that is not a
ServiceSelector fails startup (error 525). The bean it returns is resolved — and its method matched — per
request, so a misnamed bean fails that request rather than startup. See
choosing the implementation per request.
Typed process work listeners
Process management is the first user of serviceSelector. Queue-delivered process work is now typed end to end:
- New contract in
process-api:WorkListenerService<T>and theWorkListenerInput<T>envelope (processId,dispatchId,payload,execDef). - New worker bases in
process-delegate:ExecutorWorkListener<In, Out>,SplitterWorkListener<In, ChildIn>andAggregatorWorkListener<In, Out, ChildOut>. Executors and splitters implementdoStart(WorkListenerInput<In>); the aggregator folds each child withdoStart(out, input, childOutput, child). - Routing.
processWorkServiceSelectorpicks the worker bean from the message’sprocessTypeandworkerTypeheaders —item+EXECUTOR→itemExecutor— andprocessWorkBodyTypeSelectortypes the payload from that worker’s generic parameter. Worker bean names are therefore routing keys. - Queue message.
QueueBasedProcessStarterpublishes theWorkListenerInputenvelope withprocessType/workerTypeheaders and stamps the process’s tenant on each message. The previousWorkerDtoformat remains available asstart1(). - Failure semantics. A worker’s own exception is reported to the server as
doneWithErrors,splitDoneWithErrorsoraggregationDoneWithErrors, so the process endsPROCESSED_WITH_ERRORSwithout retrying the same input. Callback failures and malformed deliveries still go to Kafka retry and the dead-letter topic. - Generator and sample. JGen’s process blueprints generate the listener and workers in this shape (the
generated
doStarthooks return defaults instead of throwing), andchenile-samples/p1is migrated — see the process deployment tutorial.
Upgrading: the shared BatchServiceBase bean from 2.1.34 is replaced by a fallback that fails if no worker
was selected. Move workers to the typed listener bases and name their beans <processType>Executor,
<processType>Splitter, <processType>Aggregator. SplitterBase, ExecutorBase, AggregatorBase and
BatchServiceBase remain in process-delegate for legacy WorkerDto listeners.
Process console
The crontab form in process-ui has a Quartz cron-expression builder: pick every-N-minutes, hourly, daily,
weekdays, weekly or monthly and a time, and it fills the expression (for example 0 30 9 ? * MON-FRI), which
stays editable.
Interceptor names checked at startup
Deployable-wide interceptors (chenile.pre.processors, chenile.post.processors and chenile.exception.handler)
are now resolved when the application starts, before it takes traffic. They used to be resolved on the first request.
Resolution is all or nothing:
- A name with no Spring bean fails with E526.
- A bean that is not a Chenile interceptor fails with E527.
- Spaces and empty entries in the comma-separated lists are ignored (
a, b,).
This fixes a bug in 2.1.34 and earlier. A missing bean left a partly built list cached, so the first request failed and later requests silently skipped the rest of the interceptors.
Upgrading: a deployable whose interceptor names were wrong now fails at startup instead of at request time. Fix
the name. If you need time to fix it, set chenile.interceptors.validate-on-startup=false to go back to
first-request resolution, which is now also all or nothing.
JGen: one validator for blueprint inputs
jgen-base has BlueprintPayloadValidator, the single validator for blueprint input payloads. It is used by
jgen -f, the portal, composed blueprints and external callers such as ChenAIle. It reports every problem,
each with a path, a code and a message. It covers:
- JSON syntax, including duplicate keys, with line and column;
- required fields that are visible;
- types and declared rules, including nested fields;
- the shared project inputs.
Undeclared keys are reported as warnings. The older fail-fast helpers now use the same checks.
Two behaviour changes:
- A boolean input must be
true,false,yorn. Other text used to be read as false without warning. jgen -fchecks the whole input file before generating and lists all errors at once.
See input validation.
JGen: generation records and regeneration
Every project JGen generates now carries .jgen/generation.json. It records:
- the blueprint, with its version and jar coordinates;
- the config;
- the validated inputs, with copies of file inputs;
- a SHA-256 hash of every generated file.
jgen -r <project> regenerates the project with the blueprint now on the classpath, into a separate folder. It
compares the original generation, the project as it is now, and the new output, and reports each file as one of:
- safe update
- keep yours
- conflict
- new
- delete
It never modifies the original project. Merging is left to git, a person or an AI agent. To switch recording off,
pass -Djgen.record=false. See regeneration.
JGen: blueprints from the web
A blueprint can now be used straight from a GitHub release, for example
jgen -g github:acme/jgen-terraform@1.2.0. JGen:
- checks that the source is trusted (only the official organisations are trusted by default; anything else asks
first, or needs
--trustin CI); - downloads the release’s blueprint jar and checks its SHA-256 against an optional
#sha256:pin and against the hash recorded on first use; - caches it under
~/.jgen/cache(--offlineuses the cache only); - loads it in its own class loader.
Installed blueprints always win. Generation records store the reference and hash, so jgen -r can fetch exactly
the blueprint that cut a project. See blueprints from the web.
JGen: install without building
JGen no longer needs to be built from source:
- Homebrew:
brew install ajapros/jgen-tap/jgeninstalls JGen with its manual page (man jgen) and tab completion for bash, zsh and fish. - JBang:
jbang app install jgen@rajakolluru/chenile-gen. - Download: the zip on the GitHub release.
Blueprint jars dropped into ~/.jgen/blueprints are picked up without a rebuild. See
installing JGen and the manual.