0

This is a non-Spring app. It's a simple java app with a main. I'm using Lombok @Slf4j with a log4j2.xml config file. Gradle build file contains the following content:

dependencies {
    ...
    implementation 'org.slf4j:slf4j-api:2.0.7'
    implementation 'org.apache.logging.log4j:log4j-slf4j2-impl:2.20.0'
    ...
}
configurations {
    testImplementation.extendsFrom compileOnly
    // excludes transitive dependencies
    implementation.transitive = false
}
jar {
    dependsOn check
    duplicatesStrategy = DuplicatesStrategy.FAIL

    configurations.implementation.setCanBeResolved(true)

    into('META-INF/lib') {
        from (configurations.implementation)
    }

    manifest {
        attributes("Spring-Context": "*;publish-context:=false")
        attributes(
            'Class-Path': configurations.runtimeClasspath.files.collect { it.getName() }.join(' '),
            'Main-Class': 'com.example.Application'
        )
    }
}

Logging works fine when run within IntelliJ. Running as an executable jar file:

Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
        at dia.nmec.twm.s3_client_plugin.S3ClientPlugin.<clinit>(S3ClientPlugin.java:10)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        ... 1 more

Suggestions?

TIA, Eric

emiles
  • 739
  • 1
  • 10
  • 17

1 Answers1

1

So, the libs to include are the following ...

implementation 'org.slf4j:slf4j-api:2.0.7'
implementation 'org.apache.logging.log4j:log4j-slf4j2-impl:2.20.0'

My problem was with build.gradle. Putting all necessary jar files in META-INF/lib, for instance, doesn't add the jar files to the classpath. In fact, copying jar files to META-INF/lib is pretty useless for an executable jar file as far as I can see.

The following lines in the 'jar' section of build.gradle will grab the jar files and explode them to the root, before jarring everything up (known as a 'fat' or 'uber' jar file).

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

This fixed everything for me.

What I do wish is to be able to add all jar files to META-INF/lib with this (in the jar task, remove the 'from' task above) ...

into('META-INF/lib') {
    from(configurations.runtimeClasspath)
}

Then add 'Class-Path' to the MANIFEST with the following ...

'Class-Path': configurations.runtimeClasspath.files.collect { it.getName() }.join(' ')

So that all jar files in META-INF/lib are on the classpath and can be found.

If anyone has suggestions, I would love to hear if this is possible.

emiles
  • 739
  • 1
  • 10
  • 17
  • Unzipping all JAR files into a single folder will **overwrite** many important files. If you are using multiple Log4j modules pay attention to: 1. `META-INF/services` 2. `Log4j2Plugins.dat` files (cf. [this question](https://stackoverflow.com/q/44480197/11748454)), 3. the resulting JAR must have `Multi-Release: true` in the manifest, 4. `LICENSE/NOTICE/DEPENDENCIES` files. – Piotr P. Karwasz May 16 '23 at 16:34