← Concept 2 · Definition vs. implementation
Annotation-based Chenile services
Two recent changes make defining a Chenile service lighter and more flexible:
- The Spring REST controller is decoupled from the service definition. You can now turn a plain Spring bean into a full Chenile service with annotations alone — no
@RestController, noControllerSupport, no hand-written@PostMappingmethods. - Registering the service into the service registry is optional — a single flag on the annotation.
Both are driven by the @ChenileController annotation and are handled entirely at startup by Chenile’s service initializers.
1 · A Chenile service without a REST controller
Historically, an annotation-based Chenile service was a Spring @RestController that extended ControllerSupport and exposed each operation with a @PostMapping that called process(...). That coupled defining a service to exposing it over HTTP.
Now the two are separate. Annotate an ordinary bean with @ChenileController and mark its operations with @ChenileOperation:
@Component
@ChenileController(value = "s1Service", serviceName = "_s1Service_",
healthCheckerName = "s1HealthChecker")
public class S1ServiceImpl implements S1Service {
@Override
@ChenileOperation("op1")
public S1Entity op1(S1Entity entity) {
entity.id = "S1ServiceImpl"; // just business logic
return entity;
}
}
There is no @RestController here and nothing extends ControllerSupport. At startup, AnnotationChenileServiceInitializer (in chenile-core) finds every @ChenileController bean that is not a @RestController, builds a ChenileServiceDefinition from the annotation, reads its @ChenileOperation methods, resolves the service interface (or you name it via interfaceClass), and registers it as a first-class Chenile service.
Marking the exchange body: @ChenileBody 2.1.31
Mark the parameter that receives the body of the ChenileExchange with @ChenileBody (org.chenile.core.annotation). In 2.1.31 @ChenileController itself is supplied by chenile-core (same package name, so sources compile unchanged), which means a headless service needs no chenile-http dependency at all — it can serve in-process callers, events and serverless hosts. The chenile-headless-service blueprint generates exactly this shape:
@ChenileController(value = "ordersService", serviceName = "_ordersService_")
public class OrdersController {
@ChenileOperation("place")
public Order place(@ChenileBody Order order) { … }
}
The annotation-initialization lifecycle now lives in core; the HTTP initializer inherits it and adds only Spring MVC controller selection and route mapping.
Want REST as well?
Keep using the HTTP path when you do want REST: annotate the class with @RestController too. chenile-http then adds the Spring-MVC-specific operation metadata and request mappings on top of the same service. The point is that this is now a choice — HTTP controllers are handled by chenile-http; non-HTTP services are handled by chenile-core. One annotation model, two independent responsibilities:
| You write | Registered by | You get |
|---|---|---|
@ChenileController on a plain bean |
chenile-core · AnnotationChenileServiceInitializer |
A Chenile service (pipeline, proxies, messaging, STM) — no HTTP |
@ChenileController + @RestController |
chenile-http · HttpAnnotationChenileServiceInitializer |
The same service, plus REST endpoints |
2 · Make service-registry registration optional
By default a Chenile service publishes its remote service/operation/parameter definitions into the service registry so that proxies and other services can discover and call it. That isn’t always wanted — a purely internal helper, a mock, or a service reached only in-process adds noise to the registry.
@ChenileController now carries a flag to control this:
@Component
@ChenileController(value = "s1Service", serviceName = "_s1Service_",
registerInServiceRegistry = false) // ← do not publish to the registry
public class S1ServiceImpl implements S1Service { /* … */ }
registerInServiceRegistry defaults to true (unchanged behaviour). Set it to false and the service is still fully wired into the Chenile runtime — interceptors, health check, operations, everything — but its definition is not pushed into chenile-service-registry. Both initializers honour the flag by setting ChenileServiceDefinition.setRegisterInServiceRegistry(...).
To make a whole deployable a registry consumer that publishes nothing, set:
chenile.service.registry.read-only=true
Read-only mode keeps registry reads and local cache loading, but blocks both automatic publication at startup and direct delegate save(...) calls before any outbound HTTP write. (2.1.31)
3 · HTTP mapping rules 2.1.31
For HTTP controllers, a single SpringMvcMappingProducer now reads all five composed Spring annotations (@GetMapping, @PostMapping, @PutMapping, @PatchMapping, @DeleteMapping) and direct @RequestMapping declarations. A Chenile operation must resolve to exactly one HTTP verb and one route; an ambiguous mapping (several methods or paths) is now rejected at startup instead of being silently reduced to its first value.
When an operation’s implementation throws, the CANNOT_INVOKE_TARGET error (E509) now names the operation and the exception type and carries the underlying message — so the description your client receives in the GenericResponse points at the real cause.
The annotation, at a glance
@ChenileController (in org.chenile...annotation) exposes these fields:
value— the service id.serviceName— the bean name of the implementation (defaults to_<id>_, or the bean name in the non-HTTP path).serviceModule,bluePrintName,additionalAttributes— metadata for the service definition.healthCheckerName,mockName— optional companion beans (default to<id>HealthChecker/<id>Mock).interfaceClass— the service interface; if left asObject.class, Chenile computes it from the operations.registerInServiceRegistry—trueby default; setfalseto skip registry publication.
Methods are marked with @ChenileOperation("<opName>"); the exchange-body parameter with @ChenileBody.
org.chenile.core.init.AnnotationChenileServiceInitializer ("Registers non-HTTP Chenile controllers"). HTTP registration: org.chenile.http.init.HttpAnnotationChenileServiceInitializer. Annotations: ChenileController, ChenileOperation. Model: ChenileServiceDefinition (registerInServiceRegistry).