TooTallNate / Java-WebSocket

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

java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory (how to add dependency to fatjar) #1438

Closed cadergator10 closed 2 days ago

cadergator10 commented 3 days ago

Describe what you would like to know or do I'm trying to add the websocket client to a minecraft mod, but for some reason my implementation of the fatjar doesn't add it no matter what I do

Describe the solution you'd considered multiple different ways of adding a library to a fatjar, both compile and implementation

Additional context Crash report:

`---- Minecraft Crash Report ---- // Uh... Did I do that?

Time: 9/24/24 1:47 PM Description: Exception in server tick loop

net.minecraftforge.fml.common.LoaderExceptionModCrash: Caught exception from Advanced Base Security (advancedbasesecurity) Caused by: java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory at org.java_websocket.drafts.Draft_6455.(Draft_6455.java:113) at org.java_websocket.drafts.Draft_6455.(Draft_6455.java:210) at org.java_websocket.drafts.Draft_6455.(Draft_6455.java:198) at org.java_websocket.drafts.Draft_6455.(Draft_6455.java:178) at org.java_websocket.client.WebSocketClient.(WebSocketClient.java:184) at com.cadergator10.advancedbasesecurity.util.WebsocketHandler.(WebsocketHandler.java:37) at com.cadergator10.advancedbasesecurity.AdvBaseSecurity.init(AdvBaseSecurity.java:53) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at net.minecraftforge.fml.common.FMLModContainer.handleModStateEvent(FMLModContainer.java:637) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at com.google.common.eventbus.Subscriber.invokeSubscriberMethod(Subscriber.java:91) at com.google.common.eventbus.Subscriber$SynchronizedSubscriber.invokeSubscriberMethod(Subscriber.java:150) at com.google.common.eventbus.Subscriber$1.run(Subscriber.java:76) at com.google.common.util.concurrent.MoreExecutors$DirectExecutor.execute(MoreExecutors.java:399) at com.google.common.eventbus.Subscriber.dispatchEvent(Subscriber.java:71) at com.google.common.eventbus.Dispatcher$PerThreadQueuedDispatcher.dispatch(Dispatcher.java:116) at com.google.common.eventbus.EventBus.post(EventBus.java:217) at net.minecraftforge.fml.common.LoadController.sendEventToModContainer(LoadController.java:219) at net.minecraftforge.fml.common.LoadController.propogateStateMessage(LoadController.java:197) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at com.google.common.eventbus.Subscriber.invokeSubscriberMethod(Subscriber.java:91) at com.google.common.eventbus.Subscriber$SynchronizedSubscriber.invokeSubscriberMethod(Subscriber.java:150) at com.google.common.eventbus.Subscriber$1.run(Subscriber.java:76) at com.google.common.util.concurrent.MoreExecutors$DirectExecutor.execute(MoreExecutors.java:399) at com.google.common.eventbus.Subscriber.dispatchEvent(Subscriber.java:71) at com.google.common.eventbus.Dispatcher$PerThreadQueuedDispatcher.dispatch(Dispatcher.java:116) at com.google.common.eventbus.EventBus.post(EventBus.java:217) at net.minecraftforge.fml.common.LoadController.distributeStateMessage(LoadController.java:136) at net.minecraftforge.fml.common.Loader.initializeMods(Loader.java:749) at net.minecraftforge.fml.server.FMLServerHandler.finishServerLoading(FMLServerHandler.java:108) at net.minecraftforge.fml.common.FMLCommonHandler.onServerStarted(FMLCommonHandler.java:338) at net.minecraft.server.dedicated.DedicatedServer.func_71197_b(DedicatedServer.java:219) at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:486) at java.lang.Thread.run(Unknown Source) Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:101) at java.lang.ClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) ... 43 more

A detailed walkthrough of the error, its code path and all known details is as follows:

-- System Details -- Details: Minecraft Version: 1.12.2 Operating System: Windows 11 (amd64) version 10.0 Java Version: 1.8.0_401, Oracle Corporation Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Oracle Corporation Memory: 1111762368 bytes (1060 MB) / 1261961216 bytes (1203 MB) up to 7578058752 bytes (7227 MB) JVM Flags: 0 total; IntCache: cache: 0, tcache: 0, allocated: 0, tallocated: 0 FML: MCP 9.42 Powered by Forge 14.23.5.2860 5 mods loaded, 5 mods active States: 'U' = Unloaded 'L' = Loaded 'C' = Constructed 'H' = Pre-initialized 'I' = Initialized 'J' = Post-initialized 'A' = Available 'D' = Disabled 'E' = Errored

| State | ID                   | Version      | Source                        | Signature                                |
|:----- |:-------------------- |:------------ |:----------------------------- |:---------------------------------------- |
| LCHI  | minecraft            | 1.12.2       | minecraft.jar                 | None                                     |
| LCHI  | mcp                  | 9.42         | minecraft.jar                 | None                                     |
| LCHI  | FML                  | 8.0.99.99    | forge-1.12.2-14.23.5.2860.jar | e3c3d50c7c986df74c645c0ac54639741c90a557 |
| LCHI  | forge                | 14.23.5.2860 | forge-1.12.2-14.23.5.2860.jar | e3c3d50c7c986df74c645c0ac54639741c90a557 |
| LCHE  | advancedbasesecurity | 1.0          | advancedbasesecurity-1.0.jar  | None                                     |

Loaded coremods (and transformers): 
Profiler Position: N/A (disabled)
Is Modded: Definitely; Server brand changed to 'fml,forge'
Type: Dedicated Server (map_server.txt)`

The build.gradle:

buildscript {
    repositories {
        maven { url = 'https://maven.minecraftforge.net/' }
        mavenCentral()
    }
    dependencies {
        classpath 'net.minecraftforge.gradle:ForgeGradle:3.+'
    }
}

apply plugin: 'net.minecraftforge.gradle'
// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
apply plugin: 'eclipse'
apply plugin: 'maven-publish'

version = '1.0'
group = 'com.cadergator10.advancedbasesecurity' // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = 'advancedbasesecurity'

sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.

minecraft {
    // The mappings can be changed at any time, and must be in the following format.
    // snapshot_YYYYMMDD   Snapshot are built nightly.
    // stable_#            Stables are built at the discretion of the MCP team.
    // Use non-default mappings at your own risk. they may not always work.
    // Simply re-run your setup task after changing the mappings to update your workspace.
    //mappings channel: 'snapshot', version: '20171003-1.12'
    mappings channel: 'snapshot', version: '20171003-1.12'
    // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.

    // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')

    // Default run configurations.
    // These can be tweaked, removed, or duplicated as needed.
    runs {
        client {
            workingDirectory project.file('run')

            // Recommended logging data for a userdev environment
            property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'

            // Recommended logging level for the console
            property 'forge.logging.console.level', 'debug'
        }

        server {

            // Recommended logging data for a userdev environment
            property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'

            // Recommended logging level for the console
            property 'forge.logging.console.level', 'debug'
        }
    }
}

configurations {
    // configuration that holds jars to include in the jar
    extraLibs
}

dependencies {
    // Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
    // that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
    // The userdev artifact is a special name and will get all sorts of transformations applied to it.
    minecraft 'net.minecraftforge:forge:1.12.2-14.23.5.2860'

    // You may put jars on which you depend on in ./libs or you may define them like so..
    // compile "some.group:artifact:version:classifier"
    // compile "some.group:artifact:version"
    //compile 'org.apache.httpcomponents:httpclient:4.5.14'
    //implementation 'org.java-websocket:Java-WebSocket:1.5.7'
    //implementation group: 'org.json', name: 'json', version: '20240303'

    extraLibs 'org.slf4j:slf4j-api:2.0.6'
    extraLibs 'org.apache.httpcomponents:httpclient:4.5.14'
    extraLibs 'org.java-websocket:Java-WebSocket:1.5.7'
    extraLibs group: 'org.json', name: 'json', version: '20240303'

    configurations.compile.extendsFrom(configurations.extraLibs)

    // Real examples
    // compile 'com.mod-buildcraft:buildcraft:6.0.8:dev'  // adds buildcraft to the dev env
    // compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env

    // The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
    // provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'

    // These dependencies get remapped to your current MCP mappings
    // deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev'

    // For more info...
    // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
    // http://www.gradle.org/docs/current/userguide/dependency_management.html

}

// Example for how to get properties into the manifest for reading by the runtime..
jar {
    from {
        configurations.extraLibs.collect { it.isDirectory() ? it : zipTree(it) }
    }
    manifest {
        attributes([
            "Specification-Title": "examplemod",
            "Specification-Vendor": "examplemodsareus",
            "Specification-Version": "1", // We are version 1 of ourselves
            "Implementation-Title": project.name,
            "Implementation-Version": "${version}",
            "Implementation-Vendor" :"examplemodsareus",
            "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
        ])
    }
}

// Example configuration to allow publishing using the maven-publish task
// This is the preferred method to reobfuscate your jar file
jar.finalizedBy('reobfJar') 
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
//publish.dependsOn('reobfJar')

publishing {
    publications {
        mavenJava(MavenPublication) {
            artifact jar
        }
    }
    repositories {
        maven {
            url "file:///${project.projectDir}/mcmodsrepo"
        }
    }
}
PhilipRoman commented 3 days ago

Strange, I tried building a reduced version of your build.gradle file, and the jar included slf4j as expected. Can you give link to the full project? Also need to know what Gradle version you're using, since your file uses a lot of deprecated/removed functionality.

cadergator10 commented 2 days ago

It would be gradle 4.9, and in a couple hours I'll try and get the full project to you

cadergator10 commented 2 days ago

https://drive.google.com/file/d/1doqnqulFqt5B2jiuc9u0jacdOp0YHdUk/view?usp=sharing

cadergator10 commented 2 days ago

Note: you might need to replace only the build.gradle file with what i pasted above, since it hasn't been updated

PhilipRoman commented 2 days ago

I cloned your provided link, replaced build.gradle with version from comment, ran gradle jar and checked resulting jar files. Both of them include org/slf4j/LoggerFactory.class as expected. Looks like this issue is specific to minecraft/forge.

Here are other people experiencing exactly the same issue (slf4j is present in jar but not found by class loader):

So forge must be doing something stupid with class loading... You can probably use the "shadow" plugin to remap slf4j within your jar: https://gradleup.com/shadow/configuration/relocation/ But I would recommend asking forge devs what to do in this situation. As a last resort - you can clone this library, delete all uses of "log" and "Logger" (there aren't that many actually) and recompile.

Anyway, closing this issue since it is unrelated to java-websocket, good luck with your project!

cadergator10 commented 2 days ago

Just double checking: the gradle program "publish" works right? That's what I used to get the mod jar

PhilipRoman commented 1 day ago

Yes, in fact all 3 jar files are identical

PhilipRoman commented 1 day ago

@cadergator10 Out of curiosity I checked and it's pretty easy to remove slf4j from this library, see my fork https://github.com/PhilipRoman/Java-WebSocket/commit/a8d43d1dd2e7447f0ad0440e298427b8884e6d3e So you have a backup option available

cadergator10 commented 1 day ago

@cadergator10 Out of curiosity I checked and it's pretty easy to remove slf4j from this library, see my fork PhilipRoman@a8d43d1 So you have a backup option available

Oh perfect! I am definitely in need of it now, since I found out you can open the jar archive with 7zip and, yeah, it is included in the fatjar. but the class is still never found running the mod. Thank you for the help!

cadergator10 commented 1 day ago

@cadergator10 Out of curiosity I checked and it's pretty easy to remove slf4j from this library, see my fork PhilipRoman@a8d43d1 So you have a backup option available

For some reason, now I'm getting a "[java.lang.ThreadGroup:uncaughtException:1052]: java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;" error now, both in the ide and the mod

Edit: I built the project using jdk 21 -_- lol... trying with 1.8. i think that'll fix it

PhilipRoman commented 1 day ago

Yes, this happens because in Java 9 they added overrides to ByteBuffer which return a more specific type. So code compiled with jdk >= 9 will fail to run on java <= 8. To avoid, either compile with older jdk, or pass --release to javac (in Gradle, that should be targetCompatibility setting)