Decoding Solon WebSocket: Moving Beyond the Annotation Maze
A deep dive into how Solon WebSocket diverges from standard Java JSR-356, offering a cleaner listener interface pattern that is easier to test and route.

Stock photo for illustration only, not from the actual event
- Solon WebSocket features an architecture that clearly diverges from the standard Java JSR-356 specification.
- It supports shared port configurations where HTTP and WebSocket traffic use the same port.
- Legacy code using @ServerEndpoint must be refactored to fit the listener interface pattern.
- The core advantage is easier unit testing and explicit routing without annotation scanning surprises.
Solon's WebSocket support is one of those areas where the design diverges clearly from what most Java developers expect. If you have built WebSocket endpoints with JSR-356—the standard followed by Spring, Tomcat, and most Java EE containers—Solon handles things differently. It is not worse, simply different, and once the pattern clicks, it proves to be noticeably cleaner.
Solon WebSocket operates under specific configurations based on the server plugin in use:
- Shared port configuration allows HTTP and WebSocket traffic to share a single port, supported out of the box by most server plugins.
- Configuration is managed via
server.websocket.port : 18080, with no version numbers required in dependency declarations since the Solon BOM handles them.
A crucial detail is that Solon WebSocket does not implement the JSR-356 API. Developers migrating legacy code that directly utilizes javax.websocket.Session, @ServerEndpoint in the javax.websocket namespace, or standard encoders/decoders will need to rewrite that code to adopt the listener interface pattern. While not a massive rewrite, it is certainly a tangible migration effort.

Stock photo for illustration only, not from the actual event
Transitioning away from annotation-heavy frameworks toward explicit listener interfaces often benefits enterprise applications by eliminating hidden 'magic' behaviors. Explicit pipelines and path listeners make debugging straightforward because the routing logic resides directly in the code rather than being inferred by background reflection scanners.
On the flip side, the listener pattern is remarkably easier to test—developers can simply instantiate the listener class and invoke its methods directly. Furthermore, it simplifies component composition, giving you explicit, readable routing pathways without the usual surprises associated with annotation scanning.
Source: Dev.to
Found something wrong in this article? Report an issue with this article
Comments
Leave a Comment