← Concept 2 · Definition vs. implementation

Annotation-based Chenile services

Two recent changes make defining a Chenile service lighter and more flexible:

  1. 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, no ControllerSupport, no hand-written @PostMapping methods.
  2. 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.

What "decoupled" buys you
The bean is now a real Chenile service — it runs inside the interception pipeline (security, tenancy, logging, i18n), can be invoked through proxies, driven by messaging or a workflowwithout any HTTP or Spring-MVC coupling. HTTP exposure becomes an opt-in layer, not a prerequisite.

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(...).

When to turn it off
Internal-only services, test doubles / mocks, and services you never intend to reach through a remote proxy are good candidates. Leave it on (the default) for anything other services should be able to discover and call.

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 as Object.class, Chenile computes it from the operations.
  • registerInServiceRegistrytrue by default; set false to skip registry publication.

Methods are marked with @ChenileOperation("<opName>").

Where to look
Non-HTTP registration: org.chenile.core.init.AnnotationChenileServiceInitializer ("Registers non-HTTP Chenile controllers"). HTTP registration: org.chenile.http.init.HttpAnnotationChenileServiceInitializer. Annotations: ChenileController, ChenileOperation. Model: ChenileServiceDefinition (registerInServiceRegistry).