TooTallNate / Java-WebSocket

A barebones WebSocket client and server implementation written in 100% Java.
http://tootallnate.github.io/Java-WebSocket
MIT License
10.36k stars 2.57k forks source link

the crash happen from 1.5.3 to 1.5.4 #1353

Closed unengchen closed 7 months ago

unengchen commented 10 months ago

Describe the bug when I upgrade websocket version, from 1.5.3 to 1.5.4,and no other change,application crash

To Reproduce Steps to reproduce the behavior: everytime running crash for 1.5.4,but 1.5.3 is normal

Debug log: E/AndroidRuntime: FATAL EXCEPTION: main Process: com.zcla.gunbulletcabinet, PID: 4931 java.lang.IncompatibleClassChangeError: The method 'java.lang.Class java.lang.Object.getClass()' was expected to be of type interface but instead was found to be of type virtual (declaration of 'org.java_websocket.drafts.Draft_6455' appears in /data/app/com.zcla.gunbulletcabinet-1/base.apk:classes18.dex) at org.java_websocket.drafts.Draft_6455.(Draft_6455.java:247) at org.java_websocket.drafts.Draft_6455.copyInstance(Draft_6455.java:464) at org.java_websocket.WebSocketImpl.(WebSocketImpl.java:216) at org.java_websocket.client.WebSocketClient.(WebSocketClient.java:234) at org.java_websocket.client.WebSocketClient.(WebSocketClient.java:172) at com.zcla.gunbulletcabinet.socket.SocketManager$SocketClient.(SocketManager.java:1271) at com.zcla.gunbulletcabinet.socket.SocketManager$SocketClient.(SocketManager.java)

my app source code:

  String socketUrl = ConfigManager.getInstance().getWebSocketUrl();
    LogUtils.d(TAG, "init--socketurl", socketUrl);
    URI uri = URI.create(socketUrl);
    mSocketClient = new SocketClient(uri);
    // 取消丢失连接检测
    mSocketClient.setConnectionLostTimeout(0);
    mSocketClient.setReuseAddr(true);
    mSocketClient.connect();

private class SocketClient extends WebSocketClient { private SocketClient(URI serverUri) { super(serverUri); }

    @Override
    public void onOpen(ServerHandshake handshakedata) {

    }

    @Override
    public void onMessage(String message) {
        if (StringUtils.isEmpty(message)) return;
        mReceiveMessages.add(message);
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {

    }

    @Override
    public void onError(Exception ex) {
        LogUtils.d(TAG, "SocketClient-onError", ex.getMessage());
    }
}
PhilipRoman commented 10 months ago

What Android version are you using?

unengchen commented 10 months ago

Android 7.1

PhilipRoman commented 9 months ago

I have a potential fix for this, will try to push tonight. I have a feeling there may be even more issues caused by our build process update on Android, so I will also try to setup a test environment.

PhilipRoman commented 9 months ago

@marci4 Currently I see 2 ways to fix this - either every time we call an Object method (like hashCode, getClass, etc.) on an interface type we must cast to Object like this:

for(IExtension inputExtension : inputExtensions)
    if(((Object)inputExtension).getClass().equals(...))
        ...

or - need to build release with lower JDK version. From my tests JDK 17 should be okay, but JDK 19 already produces the incompatibility. This is the important diff in bytecode: image

What did you use to build the jar in maven central?

marci4 commented 9 months ago

@PhilipRoman I did use JDK 18,

Seeing these changes in 18 and 19, we can expect they are intentional?

PhilipRoman commented 9 months ago

Probably yes, I read the spec and I cannot find any reason why virtual methods could not be invoked using invokeinterface, so it seems valid for "javac" to emit them. This seems to be an issue in Dalvik VM.

marci4 commented 9 months ago

Thanks for taking a look at this.

Doing a quick google with "java.lang.IncompatibleClassChangeError: The method 'java.lang.Class java.lang.Object.getClass()' was expected to be of type interface but instead was found to be of type virtual" I found this https://github.com/android/android-test/issues/1642#issuecomment-1452224722

Seems to be a Dexer (D8) issue.

PhilipRoman commented 9 months ago

Since it is issue on Android side, I think we can close this as wontfix

For those affected: until d8 is fixed, you can either use 1.5.3 (the only difference from 1.5.4 is lack of Java modules - not important for Android) or compile the library yourself (mvn package -DskipTests=true) with older JDK.