socketio / socket.io-client-java

Full-featured Socket.IO Client Library for Java, which is compatible with Socket.IO v1.0 and later.
https://socketio.github.io/socket.io-client-java/installation.html
Other
5.32k stars 972 forks source link

IncompatibleClassChangeError when consuming response from server v4 #690

Closed wkrzywiec closed 2 years ago

wkrzywiec commented 2 years ago

Describe the bug I'm building the Socket.io server using Java library - trinopoty/socket.io-server-java and now I would like to write some integration tests using this library.

When the connection with server is established, i.e server is sending initial 200 response with body:

0{"pingInterval":25000,"pingTimeout":20000,"upgrades":["websocket"],"sid":"7PRUGwUPF45"}

for the request GET http://localhost:8080/socket.io/?EIO=4&transport=polling, and exception is thrown on a client side:

java.lang.IncompatibleClassChangeError: Method io.socket.engineio.parser.Parser.decodePayload(Ljava/lang/String;Lio/socket/engineio/parser/Parser$DecodePayloadCallback;)V must be InterfaceMethodref constant
    at io.socket.engineio.client.transports.Polling._onData(Polling.java:131) ~[engine.io-client-2.0.0.jar:na]
    at io.socket.engineio.client.transports.Polling.onData(Polling.java:101) ~[engine.io-client-2.0.0.jar:na]
    at io.socket.engineio.client.transports.PollingXHR$5$1.run(PollingXHR.java:117) ~[engine.io-client-2.0.0.jar:na]
    at io.socket.thread.EventThread$2.run(EventThread.java:80) ~[engine.io-client-2.0.0.jar:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
    at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

Exception in thread "EventThread" java.lang.IncompatibleClassChangeError: Method io.socket.engineio.parser.Parser.decodePayload(Ljava/lang/String;Lio/socket/engineio/parser/Parser$DecodePayloadCallback;)V must be InterfaceMethodref constant
    at io.socket.engineio.client.transports.Polling._onData(Polling.java:131)
    at io.socket.engineio.client.transports.Polling.onData(Polling.java:101)
    at io.socket.engineio.client.transports.PollingXHR$5$1.run(PollingXHR.java:117)
    at io.socket.thread.EventThread$2.run(EventThread.java:80)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)

To Reproduce

Socket.IO server version: 3.0.2 (trinopoty/socket.io-server-java)

Server

Implementation based on https://github.com/trinopoty/socket.io-server-java/issues/18#issuecomment-909389666 .

If needed I can provide full example code of it.

Socket.IO java client version: 2.0.1

Client

My application is run with Spring Boot and here is my simple integration test example:

@Test
    void shouldTest() throws URISyntaxException, InterruptedException {
        //given
       var map = new ConcurrentHashMap<String, String>();

        var url = "http://localhost:" + String.valueOf(port) + "/";
        Socket socket = IO.socket(url);

        socket.on(Socket.EVENT_CONNECT, (data) -> {
            System.out.println("Socket.EVENT_CONNECT");
        });

        socket.on("event", args -> {
            System.out.println("SocketEvent.PROJECT_CREATED.value()");
            map.put("event", (String) args[0]);
        });

        socket.connect();

        // when
        publisher.publishMessage("room", "event", "test message");

       //then
        assertEquals(1, map.size());
    }

Expected behavior Client should not throw such error when performing standard connection.

Platform:

Additional context I've tested the server with a simple React application using the "socket.io-client": "^4.3.2" library and everything works fine, therefore it seems as a client side problem.

Thanks in advance for all your support

oddmario commented 2 years ago

Could reproduce this, were you able to solve it?

oddmario commented 2 years ago

Figured it out. In my case I had both the server and the client running on the same project.

A conflict happens between https://github.com/socketio/engine.io-server-java/blob/master/engine.io-server/src/main/java/io/socket/engineio/parser/Parser.java (used by trinopoty's Socket.IO server) and https://github.com/socketio/engine.io-client-java/blob/master/src/main/java/io/socket/engineio/parser/Parser.java (used by this client), they both share the same package & class names io.socket.engineio.parser which causes the issue.

As a temporary workaround, I decided to run each of the server and the client in separate projects and made sure that the project of the client doesn't include engine.io-server or any dependency of trinopoty's server, this solved the conflict happening.

oliverboehm02 commented 1 year ago

hello!

Ive got the same problem now.. i am using my client with okhttp like this:

`SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[] { trustManager }, null);

    OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .hostnameVerifier(hostnameVerifier)
            .sslSocketFactory(sslContext.getSocketFactory(), trustManager)
            .readTimeout(1, TimeUnit.MINUTES) // important for HTTP long-polling
            .build();

    IO.Options options = new IO.Options();
    options.callFactory = okHttpClient;
    options.webSocketFactory = okHttpClient;

    Socket client = IO.socket("https://xyz.self-signed.com", options);
    client.connect();`

sadly im not able to split my program like you. is there any new information for that topic?

is it maybe possible to exclude one of the two parsers? is it possible to use my own parser(decoder and encoder) like options.decoder= new MyOwnDecoder()

I am thankful for any help

@darrachequesne