1

I am writing a desktop Java application as a web service client. I want to use WebSocket to implement notification "callback" from the server.

I am using the Spring framework's WebSocketStompClient. Below snippet shows how I initialize it:

import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.Transport;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
...
List<Transport> transports = new ArrayList<>();
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
stompClient = new WebSocketStompClient(new SockJsClient(transports));
...

It works perfectly if I run it in IntelliJ IDE, however, if I run by command line "java -cp my.jar MyPackage.MyMainClass", it will fail with the following message:

Error: Unable to initialize main class MyMainClass
Caused by: java.lang.NoClassDefFoundError: org/springframework/web/socket/client/WebSocketClient

The above was produced by Java SE 12.0.2. If I run it using Java SE 1.8, the error message will be:

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: 
org/springframework/web/socket/client/WebSocketClient
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
    at java.lang.Class.privateGetMethodRecursive(Unknown Source)
    at java.lang.Class.getMethod0(Unknown Source)
    at java.lang.Class.getMethod(Unknown Source)
    at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
    at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

Both java.lang.NoClassDefFoundError and getDeclaredMethods0(Native Method) suggsted that a native module (a DLL) is missing.

Below is my Gradle script:

dependencies {
    implementation project(':logman-common')
    implementation 'org.springframework:spring-web:5.2.2.RELEASE'
    implementation 'org.springframework:spring-websocket:5.2.2.RELEASE'
    implementation 'org.springframework:spring-messaging:5.2.2.RELEASE'
    ... // other unrelated dependencies, such as GUI
}

I don't think it was due to some missing JARs. I tried:

  • to add tyrus-standalone-client to the dependency list, or
  • to use StandardWebSocketClient instead of SockJsClient,

but the error remained.

I guess some native libraries are missing in my OS (Win10), but that can't explain why I can run it in IntelliJ...

Could you let me know what is missing? or how can I fix this? Thanks!

Anish B.
  • 9,111
  • 3
  • 21
  • 41
Zhou
  • 633
  • 5
  • 16

2 Answers2

2

Try to create a fat jar which contains all the dependencies and classes.

Update build.gradle script to this given below :

apply plugin: 'java'
version = '...'
sourceCompatibility = 1.8
targetCompatibility = 1.8

// to create a fat jar.
jar {
  manifest { 
    attributes "Main-Class": "MyPackage.MyMainClass"
  }  

  from {
    configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
  }
} 

dependencies {
    implementation project(':logman-common')
    implementation 'org.springframework:spring-web:5.2.2.RELEASE'
    implementation 'org.springframework:spring-websocket:5.2.2.RELEASE'
    implementation 'org.springframework:spring-messaging:5.2.2.RELEASE'
    ... // other unrelated dependencies, such as GUI
}

It will generate an executable fat jar in the build/libs of your root project which will include all the project files (this includes all of your dependencies, resource files, .class files and so on).

Note: For older versions of Gradle, use this configurations.compile.collect instead of configurations.runtimeClasspath.collect.

You just need to run the jar with this command : java -jar <project-version>.jar

This should solve your problem.

Anish B.
  • 9,111
  • 3
  • 21
  • 41
  • 1
    I don't think this would change a thing, because the libraries aren't the actual problem, but the framework is. – Martin Zeitler May 21 '20 at 06:16
  • @MartinZeitler I'm not sure. OP reports `java.lang.NoClassDefFoundError: org/springframework/web/socket/client/WebSocketClient` and moreover through IDE, it's working. Then it's obvious that something is problem with the jar. – Anish B. May 21 '20 at 06:21
  • 1
    Unless it's not being obfuscated, it should be there. The JNI error makes me believe it's the EE framework... which would have the native assembly, which is being demanded. – Martin Zeitler May 21 '20 at 06:27
  • @MartinZeitler That can also be possible reason. – Anish B. May 21 '20 at 06:30
  • 1
    @AnishB. Truly sorry for the late reply! This is about a "moonlight" project of mine, so I only have time to look at it on the weekend. *Your solution worked for me indeed! Cool!!* I guessed I need a fat jar when I confronted the problem, but I didn't know how to do it with Gradle. Thank you very much! – Zhou May 22 '20 at 10:19
  • @Zhou Thanks !! I thought that it didn't worked for you. – Anish B. May 22 '20 at 10:20
  • 1
    @MartinZeitler You are right. The error message clearly showed that a native library (a .dll, or a .so on Linux) is missing. I guess the native library is on my computer's disk, however, I must either tell the jvm where to find it or pack it into the jar. I always prefer fat jar just like modern devs prefer docker package :D . But I'm a beginner of Java and Gradle, so I didn't know how to pack everything in a jar. – Zhou May 22 '20 at 10:24
  • 1
    @AnishB. It worked for me. I just had a hard week and didn't have time and energy to take care of this post. Sorry again for the late reply! – Zhou May 22 '20 at 10:26
1

The error message reads, that a JNI error has occurred, so this indeed is related to native assembly (you could debug with LLDB). While I think that library might require Java EE and won't run on Java SE; likely it's the same with Tyrus and other JSR 356 implementations. Either switch to another WebSocket implementation, which is known to work with desktop Java SE or write your own; the WebSocket HBYI protocol isn't that difficult; Java SE 11 even has a WebSocket.Builder.

Community
  • 1
  • 1
Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • 1
    Thank you very much for your suggestion. I will find out what LLDB is and also take a look at the WebSocket HBYI protocol and the WebSocket.Builder. Yes, many people say that the error is due to something the Java SE doesn't have. Emm... I believe it is right. – Zhou May 22 '20 at 10:32