Standalone Java Websocket client NoClassDefFoundError by ContainerProvider

howToDeleteMyAccount picture howToDeleteMyAccount · Dec 5, 2015 · Viewed 11k times · Source

I'm new to Java, but I have to use it to do a small WebSocket related project.

So, I installed JDK 1.8.0 and NetBeans 8.1 on my CentOS 7 in a VirtualBox.

I added the tyrus-standalone-client-jdk 1.12 plug-in in the pom.xml to make the standalone Websocket client, and it built fine. However, I ran into the error below:

[root@cet7 ~]# java -jar "/root/NetBeansProjects/Switchclient/target/Switchclient-1.0-SNAPSHOT.jar"

Exception in thread "main" java.lang.NoClassDefFoundError: javax/websocket/ContainerProvider
    at org.sample.switchclient.Switchclient.main(Switchclient.java:21)
Caused by: java.lang.ClassNotFoundException: javax.websocket.ContainerProvider
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 1 more

[root@cet7 ~]# java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)

I did a bit more searching and found that the "fully qualified classname of the container implementation of ContainerProvider must be listed in the META-INF/services/javax.websocket.ContainerProvider file in the implementation JAR file" for the ServiceLoader API according to Oracle documentation. So, I added the serviceloader-maven-plugin to the pom.xml. The result was that it did generate the META-INF/services/javax.websocket.ContainerProvider file, but without any content, and the runtime error continued to persist. I tried to modify the contents bellow manually and re-pack it into a JAR but it did not worked:

  1. org.glassfish.tyrus.container.inmemory.InMemoryContainerProvider
  2. org.glassfish.tyrus.client.ClientManager

I've attached the Java file and the pom.xml. I've worked for hours and haven't a clue what the issue is, so any response to this thread will be appreciated.

Thank you very much.

===========LIST1: pom.xml===========

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.sample</groupId>
    <artifactId>Switchclient</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <archive>
            <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>org.sample.switchclient.Switchclient</mainClass>
            </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>eu.somatik.serviceloader-maven-plugin</groupId>
                <artifactId>serviceloader-maven-plugin</artifactId>
                <version>1.0.6</version>
                <configuration>
                    <services>
                        <param>javax.websocket.ContainerProvider</param>
                    </services>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.glassfish.tyrus.bundles</groupId>
            <artifactId>tyrus-standalone-client-jdk</artifactId>
            <version>1.12</version>
        </dependency>
    </dependencies>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>


</project>

===========LIST2: Switchclient.java===========
package org.sample.switchclient;

import java.net.URI;
import javax.websocket.ClientEndpoint;
import javax.websocket.ContainerProvider;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;

@ClientEndpoint
public class Switchclient {
    @OnMessage
    public void onRemoteMessage (String message) {
        System.out.println("Received msg: "+message); 
    }

    public static void main(String[] args) {
        WebSocketContainer container = null;
        Session session = null;
        try{
            container = ContainerProvider.getWebSocketContainer();
            session = container.connectToServer (Switchclient.class, URI.create("ws://localhost:8080/Switchserver/"));
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Answer

Takahiko Kawasaki picture Takahiko Kawasaki · Dec 8, 2015

Basically, Tyrus requires Java EE. It's the reason you have to list a lot of dependencies in pom.xml. If you use Java SE and want to keep your project small, use another different WebSocket client library that depends on only Java SE. For example, nv-websocket-client (mine).

Just add the following dependency to pom.xml,

<dependency>
    <groupId>com.neovisionaries</groupId>
    <artifactId>nv-websocket-client</artifactId>
    <version>1.13</version>
</dependency>

then try:

import com.neovisionaries.ws.client.*;

public class Switchclient
{
    public static void main(String[] args) throws Exception
    {
        WebSocket websocket = new WebSocketFactory()
            .createSocket("ws://localhost:8080/Switchserver/")
            .addListener(new WebSocketAdapter() {
                @Override
                public void onTextMessage(WebSocket ws, String message) {
                    System.out.println("Received msg: " + message);
                }
            })
            .connect();

        // Don't forget to call disconnect() after use.
        // websocket.disconnect();
    }
}