Skip to content

Coming from Spring Boot

If you know Spring Boot, the Dirigible Java model will feel familiar: you annotate a class or method to declare intent, and the platform wires it into DI, routing, persistence, scheduling, messaging, websockets, and security. The annotations live under org.eclipse.dirigible.sdk.* and deliberately mirror their Spring / Jakarta counterparts.

The big mental shift: your .java files are client code that the platform compiles in-process and loads through its own classloader. They are not part of Spring's component scan, so @Autowired is a no-op on them - you use Dirigible's own (Spring-shaped) DI surface instead.

Mapping table

Spring / JakartaDirigibleNote
@Component@Component (sdk.component)Same idea; default bean name is the decapitalized class name.
@Autowired field / constructor@Inject field / constructor injectionConstructor injection is preferred.
List<T> injectionList<T> injectionReceives every bean assignable to T.
ApplicationContext.getBean(...)Beans.get(...) / Beans.get(name, ...) / Beans.getAll(...) (sdk.component.Beans)Client-facing facade - not the platform-internal BeanProvider.
@RestController@Controller (sdk.http)Return value is serialized as the response body.
@GetMapping / @PostMapping / @PutMapping / @PatchMapping / @DeleteMapping@Get / @Post / @Put / @Patch / @Delete (sdk.http)Method-level; value() is the path suffix with {name} placeholders.
@PathVariable / @RequestParam / @RequestBody@PathParam / @QueryParam / @Body (sdk.http)Same parameter-binding roles.
interface … extends JpaRepository<T, ID>class … extends JavaRepository<T> + @RepositoryA concrete class, not an interface. No derived queries - use query(hql, params).
org.quartz.Job (interface)JobHandler (sdk.job) - self-describing cron() + run()Strong-interface job style.
@Scheduled(cron = …) on a method@Scheduled(expression = …) on a @Component methodMethod-level scheduling style.
jakarta.jms.MessageListenerMessageHandler (sdk.messaging) - self-describing destination() / kind() + onMessageStrong-interface listener style.
@JmsListener(destination = …) on a method@Listener(name = …, kind = …) on a @Component methodMethod-level listener style.
TextWebSocketHandlerWebsocketHandler (sdk.net) - self-describing endpoint() + callbacksStrong-interface websocket style.
Jakarta @ServerEndpoint + @OnMessage@Websocket(endpoint = …) class + @OnOpen / @OnMessage / @OnError / @OnCloseMethod-level callback style.
@RolesAllowed / @PreAuthorize@Roles (sdk.security)Any-of role check on a class or method.
Spring Security context / principalUser (sdk.security.User)Static accessors for the current user.
@PostConstruct / @PreDestroy@PostConstruct / @PreDestroy (jakarta.annotation)Same lifecycle callbacks.

Side-by-side: implementing each artifact

Each artifact is shown the Spring way first, then the Dirigible way, so you can see how close they are. For jobs, listeners, and websockets there are two styles - a self-describing strong interface or method-level annotations on a @Component - and a single @Component class uses one or the other, never both. The main difference: in Spring the interface style gets its binding (destination / cron / path) from separate configuration, whereas the Dirigible interface is self-describing (the binding is a method on the interface).

Listener

Strong interface. Spring - implement jakarta.jms.MessageListener (the destination is set on the listener container in config):

java
import jakarta.jms.Message;
import jakarta.jms.MessageListener;
import org.springframework.stereotype.Component;

@Component
class OrderListener implements MessageListener {
    public void onMessage(Message message) { /* ... */ }
}

Dirigible - implement MessageHandler and supply your own destination():

java
import org.eclipse.dirigible.sdk.component.Component;
import org.eclipse.dirigible.sdk.messaging.MessageHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
public class OrderListener implements MessageHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger("app.out");

    @Override
    public String destination() { return "java-order-queue"; }

    @Override
    public void onMessage(String message) { LOGGER.info("received: {}", message); }
}

Method-level. Spring - @JmsListener on a bean method:

java
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
class Invoices {
    @JmsListener(destination = "java-invoice-queue")
    void onInvoice(String message) { /* ... */ }
}

Dirigible - @Listener on a @Component method:

java
import org.eclipse.dirigible.sdk.component.Component;
import org.eclipse.dirigible.sdk.messaging.Listener;
import org.eclipse.dirigible.sdk.messaging.ListenerKind;

@Component
public class InvoiceListener {
    @Listener(name = "java-invoice-queue", kind = ListenerKind.QUEUE)
    public void onInvoice(String message) { /* ... */ }
}

Sample: dirigiblelabs/sample-java-listener-decorator.

Job

Strong interface. Spring - implement Quartz org.quartz.Job (the cron lives in a Trigger bean):

java
import org.quartz.Job;
import org.quartz.JobExecutionContext;

public class CleanupJob implements Job {
    public void execute(JobExecutionContext context) { /* ... */ }
}

Dirigible - implement JobHandler and supply your own cron():

java
import org.eclipse.dirigible.sdk.component.Component;
import org.eclipse.dirigible.sdk.job.JobHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
public class CleanupJob implements JobHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger("app.out");

    @Override
    public String cron() { return "* * * * * ?"; }

    @Override
    public void run() { LOGGER.info("CleanupJob executed!"); }
}

Method-level. Spring - @Scheduled on a bean method:

java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
class Maintenance {
    @Scheduled(cron = "0/45 * * * * ?")
    void purgeTempFiles() { /* ... */ }
}

Dirigible - @Scheduled on a @Component method (expression instead of cron):

java
import org.eclipse.dirigible.sdk.component.Component;
import org.eclipse.dirigible.sdk.job.Scheduled;

@Component
public class Maintenance {
    @Scheduled(expression = "0/45 * * * * ?")
    public void purgeTempFiles() { /* ... */ }
}

Sample: dirigiblelabs/sample-java-job-decorator.

WebSocket

Strong interface. Spring - extend TextWebSocketHandler (the path is registered in config):

java
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component
class ChatHandler extends TextWebSocketHandler {
    protected void handleTextMessage(WebSocketSession session, TextMessage message) { /* ... */ }
}

Dirigible - implement WebsocketHandler and supply your own endpoint(); override only what you need:

java
import org.eclipse.dirigible.sdk.component.Component;
import org.eclipse.dirigible.sdk.net.WebsocketHandler;

@Component
public class ChatHandler implements WebsocketHandler {
    @Override
    public String endpoint() { return "java-chat"; }

    @Override
    public void onMessage(String message, String from) { /* ... */ }
}

Annotation. Spring / Jakarta - @ServerEndpoint class with @OnOpen / @OnMessage:

java
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.ServerEndpoint;

@ServerEndpoint("/java-ticker")
public class TickerHandler {
    @OnOpen    public void opened(Session session) { /* ... */ }
    @OnMessage public String message(String message) { return "tick: " + message; }
}

Dirigible - @Websocket(endpoint = …) class with @OnOpen / @OnMessage / @OnError / @OnClose (a non-void @OnMessage return is sent back to the client):

java
import org.eclipse.dirigible.sdk.net.OnMessage;
import org.eclipse.dirigible.sdk.net.OnOpen;
import org.eclipse.dirigible.sdk.net.Websocket;

@Websocket(name = "Java Ticker", endpoint = "java-ticker")
public class TickerHandler {
    @OnOpen    public void opened() { /* ... */ }
    @OnMessage public String message(String message, String from) { return "tick: " + message; }
}

Sample: dirigiblelabs/sample-java-websocket-decorator.

Controller

Spring - @RestController with constructor injection:

java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
class CountryController {
    private final CountryRepository countries;
    CountryController(CountryRepository countries) { this.countries = countries; }

    @GetMapping("/{id}")
    Country find(@PathVariable long id) { return countries.findById(id).orElseThrow(); }
}

Dirigible - @Controller; the return value is serialized as the response body:

java
import org.eclipse.dirigible.sdk.http.Controller;
import org.eclipse.dirigible.sdk.http.Get;
import org.eclipse.dirigible.sdk.http.PathParam;

@Controller
public class CountryController {
    private final CountryRepository countries;
    public CountryController(CountryRepository countries) { this.countries = countries; }

    @Get("/{id}")
    public Country find(@PathParam("id") long id) { return countries.findById(id); }
}

See REST APIs.

Repository

Spring Data - declare an interface, the framework generates the implementation:

java
import org.springframework.data.jpa.repository.JpaRepository;

interface CountryRepository extends JpaRepository<Country, Long> { }

Dirigible - a concrete class extending JavaRepository<T>, marked @Repository (typed CRUD plus query(hql, params)):

java
import org.eclipse.dirigible.sdk.component.Repository;
import org.eclipse.dirigible.components.data.store.java.repository.JavaRepository;

@Repository
public class CountryRepository extends JavaRepository<Country> {
    public CountryRepository() { super(Country.class); }
}

See Entities and persistence.

Extension

The shape is the same in both: an interface, @Component implementations, and a consumer that injects List<Interface> to receive them all.

Spring:

java
import java.util.List;

import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestController;

interface SampleExtensionPoint { String describe(); }

@Component
class SampleContribution implements SampleExtensionPoint {
    public String describe() { return "Hello from SampleContribution!"; }
}

@RestController
class InjectingConsumer {
    private final List<SampleExtensionPoint> contributions;
    InjectingConsumer(List<SampleExtensionPoint> contributions) { this.contributions = contributions; }
}

Dirigible (no dedicated annotation - the @Component name is the contribution name):

java
import java.util.List;

import org.eclipse.dirigible.sdk.component.Component;
import org.eclipse.dirigible.sdk.http.Controller;

public interface SampleExtensionPoint { String describe(); }

@Component("sample-contribution")
public class SampleContribution implements SampleExtensionPoint {
    @Override
    public String describe() { return "Hello from SampleContribution!"; }
}

@Controller
public class InjectingConsumer {
    private final List<SampleExtensionPoint> contributions;
    public InjectingConsumer(List<SampleExtensionPoint> contributions) { this.contributions = contributions; }
}

Sample: dirigiblelabs/sample-java-extension-decorator. See Extension providers.

Where to go next

Released under the EPL-2.0 License.