Last Apache Meecrowave release (v1.2.11) got a new meecrowave-websocket module which enables to use tomcat-websocket without having to integrate in a custom fashion CDI with default Apache Tomcat websocket server implementation without using a custom configurator.

Long story short, you can now write:

@Dependent (1)
@ServerEndpoint("/ws")
public class MyServerEndpoint {
    @Inject
    private MyMessageHandler handler; (2)

    @OnMessage
    public void onMessage(final String message) {
        handler.onMessage(message);
    }
}
1 The websocket endpoint is a CDI bean - highly recommended to use @Dependent scope due to websocket threading nature,
2 Therefore it can get injections as any bean.

This simple change enables to simplify the code and the explicit usage of CDI.current() to look up a delegate implementation in the POJO endpoint (default mode in Tomcat until today).

What is important to see is that future Tomcat version will also support this out of the box so you will be able to replace org.apache.meecrowave:meecrowave-websocket by org.apache.tomcat:tomcat-websocket - change will be transparent in terms of code. We are also working with Apache Tomcat community to see if we can get the same feature for encoders/decoders which would make the full websocket stack CDI friendly out of the box.

this module also comes with a sibling module with the classifier jakarta if you want to code against jakarta namespace/package instead of javax one, just use org.apache.meecrowave:meecrowave-websocket:1.2.11:jakarta or in the future org.apache.tomcat:tomcat-websocket in version >= 10.x.

For more advanced cases you can still rely on a custom configurator to instantiate your endpoint - here you can use the vanilla tomcat module:

@ServerEndpoint(
    value "/ws",
    configurator = MyConfigurator.class (1)
)
public class MyServerEndpoint {
    // as before
}
1 We force a custom configurator implementation.

The configurator can look like:

public class CDIServerConfigurator extends ServerEndpointConfig.Configurator { (1)
    @Override
    public <T> T getEndpointInstance(final Class<T> clazz) throws InstantiationException {
        try {
            return CDI.current().select(clazz).get(); (2)
        } catch (final RuntimeException re) {
            return super.getEndpointInstance(clazz); (3)
        }
    }
}
1 We extend ServerEndpointConfig.Configurator to inherit defaults (a configurator can do way more than instantiating the endpoint instance),
2 We try to lookup the endpoint instance through CDI - or any other mecanism,
3 If it fails we use the default implementation which will just do a "new".

This last mecanism works well with any websocket implementation but requires to set the configurator on each endpoint using annotated API.

If you use this option, the programmatic API can be worth a look:

public class MyDeployer implements ServletContextListener { (1)
    @Override
    public void contextInitialized(final ServletContextEvent sce) {
        final ServerContainer sc = ServerContainer.class.cast( (2)
            sce.getServletContext().getAttribute(ServerContainer.class.getName()));

        sc.addEndpoint(ServerEndpointConfig.Builder (3)
                .create(MyEndpoint.class, "/my-endpoint") (4)
                .configurator(new ServerEndpointConfig.Configurator() { (5)
                    @Override
                    public <T> T getEndpointInstance(final Class<T> clazz) throws InstantiationException {
                        return singletonEndpoint;
                    }
                })
                .build());
    }
}
1 We implement a ServletContextListener which enables us to deploy the websocket endpoint(s) with the web application,
2 We lookup the ServerContainer which is provided by tomcat-websocket - or meecrowave-websocket,
3 We add our endpoint built from ServerEndpointConfig.Builder,
4 We define our endpoint from its class and associate it a binding path,
5 We don’t forget to set our configurator (instantiator in this case).

What is important to see with this example is that you can easily reuse a configurator implementation for all endpoint since being programmatic enables to do loops and call methods compared to using the annotated API.

Last note of this post will be that you probably noticed I didn’t speak about the client side API. This is because, as of today where Java 11 is mainstream, there is no need to use javax/jakarta client API and you can rely on Java 11 HttpClient websocket support so bother yourself with a dependency for the client side. Its API already makes it easy to integrate with any IoC.

From the same author:

In the same category: