Coming soon ChenAIle — agentic microservices: agents, AI tool calls, machine learning and a metrics-driven rules engine Learn more →

← All release notes

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 the WorkListenerInput<T> envelope (processId, dispatchId, payload, execDef).
  • New worker bases in process-delegate: ExecutorWorkListener<In, Out>, SplitterWorkListener<In, ChildIn> and AggregatorWorkListener<In, Out, ChildOut>. Executors and splitters implement doStart(WorkListenerInput<In>); the aggregator folds each child with doStart(out, input, childOutput, child).
  • Routing. processWorkServiceSelector picks the worker bean from the message’s processType and workerType headers — item + EXECUTOR → itemExecutor — and processWorkBodyTypeSelector types the payload from that worker’s generic parameter. Worker bean names are therefore routing keys.
  • Queue message. QueueBasedProcessStarter publishes the WorkListenerInput envelope with processType / workerType headers and stamps the process’s tenant on each message. The previous WorkerDto format remains available as start1().
  • Failure semantics. A worker’s own exception is reported to the server as doneWithErrors, splitDoneWithErrors or aggregationDoneWithErrors, so the process ends PROCESSED_WITH_ERRORS without 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 doStart hooks return defaults instead of throwing), and chenile-samples/p1 is 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, y or n. Other text used to be read as false without warning.
  • jgen -f checks 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:

  1. checks that the source is trusted (only the official organisations are trusted by default; anything else asks first, or needs --trust in CI);
  2. downloads the release’s blueprint jar and checks its SHA-256 against an optional #sha256: pin and against the hash recorded on first use;
  3. caches it under ~/.jgen/cache (--offline uses the cache only);
  4. 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/jgen installs 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.