简体   繁体   中英

Using custom Configurator with WebSockets

Just a quick question with regard to extending ServerEndpointConfig.Configurator to override Tomcat's default action of instantiating the POJO class annotated with @ServerEndpoint on receiving a WebSocket request. My reason for doing this is that my endpoint class depends on IoC dependency injection, and therefore needs to be got from the registry to have its dependencies in place.

My Configurator method:

@Override 
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException { 
    return endpointClass.cast(RegistryProxy.getService(HarbourServerEndpoint.class)); 
} 

The @ServerEndpoint annotation is placed on on my HarbourServerEndpointImpl POJO class, not the interface that it implements. Based on the below runtime catalina.out error message the problem appears to be that the registry is returning HarbourServerEndpoint whereas Tomcat is expecting an instance of HarbourServerEndpointImpl?

I'm hoping someone can please explain what is going wrong with my custom Configurator.

15-Apr-2019 12:45:28.488 SEVERE [http-nio-8080-exec-915] org.apache.coyote.AbstractProtocol$ConnectionHandler.process Error reading request, ignored java.lang.ClassCastException: Cannot cast $HarbourServerEndpoint_39c9cc24eb8b2a to com.optomus.harbour.services.HarbourServerEndpointImpl at java.lang.Class.cast(Class.java:3369) at com.optomus.harbour.services.HarbourServerEndpointConfigurator.getEndpointInstance(HarbourServerEndpointConfigurator.java:17) at org.apache.tomcat.websocket.pojo.PojoEndpointServer.onOpen(PojoEndpointServer.java:44)

 at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.init(WsHttpUpgradeHandler.java:133) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:846) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748)

Finally, with no casting at all, the compiler gives the error:

 Error:(17, 40) java: incompatible types: inference variable T has incompatible bounds equality constraints: com.optomus.harbour.services.HarbourServerEndpoint upper bounds: T,java.lang.Object

Since posting this question, I researched Tapestry-IoC and how it works. Turns out there is a reason for what is being returned looking a little odd ($HarbourServerEndpoint_39c9cc24eb8b2a). It is a service proxy object, not an instance of the service implementation as I was expecting. I'm not sure how typical this is for IoC containers. Quoting from the Tapestry website:

"Services consist of two main parts: a service interface and a service implementation.

The service interface is how the service will be represented throughout the rest of the registry. Since what gets passed around is normally a proxy, you can't expect to cast a service object down to the implementation class (you'll see a ClassCastException instead). In other words, you should be careful to ensure that your service interface is complete, since Tapestry IoC effectively walls you off from back doors such as casts."

This makes it rather tricky to acquire from the IoC registry instances of the class annotated with @ServerEndpoint, and I'm now exploring other options.

Regards,

Chris.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM