1

I'm aware of reasons for missing or duplicate slf4j implementations on classpath due to (Maven) dependency management and know how to avoid such through exclusions.

However, if I have a multi-module Java project with a JAR containing EJB interfaces and entities, an EJB implementation and a WAR web frontend which is packaged as EAR I do not find a way to place the slf4j API org.slf4j:slf4j-api:1.7.25, the implementation ch.qos.logback:logback-classic:1.2.3 and the configuration logback.xml so that I have working logging in the JAR, EJB and WEB module and can avoid both

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

and

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/home/richter/zpool-tmp/jee-slf4j-logging/jee-slf4j-logging-ear/target/gfdeploy/jee-slf4j-logging-ear/jee-slf4j-logging-web-1.0-SNAPSHOT_war/WEB-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/richter/zpool-tmp/jee-slf4j-logging/jee-slf4j-logging-ear/target/gfdeploy/jee-slf4j-logging-ear/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

and

Caused by: java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/glassfish/web/loader/WebappClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of org/glassfish/javaee/full/deployment/EarLibClassLoader) for the method's defining class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type org/slf4j/ILoggerFactory used in the signature
    at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:418)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:357)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:383)

I'm providing a MCVE at https://gitlab.com/krichter/jee-slf4j-logging.

GlassFish 4, no logging framework dependencies is working in pom.xml doesn't cover the Java EE aspect.

Kalle Richter
  • 8,008
  • 26
  • 77
  • 177
  • Note that logging accesses the file system directly which is not allowed in a fully compliant application. You may consider using slf4j to go to java.util.logging which all servlet containers I know about captures and logs centrally – Thorbjørn Ravn Andersen Jan 06 '18 at 11:03
  • The easiest way is to put everything in your WAR file and just deploy that. Building correct EAR files with all the dependent jars in the right place (even with Maven) is a tricky affair and would take some time to explain – Steve C Jan 06 '18 at 12:37
  • @SteveC I know the advantages of WAR over EAR packaging. I already experienced the advantage of being able to develop different web clients for a Java EE with cleanest possible separation. So, I'd like to keep the multi-module structure. – Kalle Richter Jan 06 '18 at 14:12
  • You can try to see maven effective pom and search duplicate dependency. Maybe it helps you: https://stackoverflow.com/questions/15985337/dependency-and-dependcy-viewer-tab-in-intellij-idea https://blog.jetbrains.com/idea/2010/05/maven-dependencies-diagram/ – Eugene Roldukhin Jan 06 '18 at 14:24
  • My answer at https://stackoverflow.com/questions/41306341/my-ear-is-not-able-to-find-ejb-module-classes/41310413#41310413 will explain why you must put these jars in the EAR/lib directory. This also means that your configuration must be in a jar in the EAR/lib directory or specified via a system property such as `-Dlogback.configurationFile=/path/to/config.xml` – Steve C Jan 06 '18 at 23:11

1 Answers1

0

I ended up doing the following:

  1. Create a new folder directly under the EAR folder. For example, create a new folder named "conf" --> EAR/conf

  2. Place your logback.xml file in this new folder: EAR/conf/logback.xml

  3. In your WAR/EJB/API file's MANIFEST.MF file, add this new folder to the classpath:

Class-Path: conf

If you are using maven to build your project in your moules such as web, ejb and ejb interface add dependecy to slf4j-api with provided scope:

WEB, EJB, API modules
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>${slf4j.version}</version>
  <scope>provided</scope>
</dependency>

and in your EAR module add dependencies to slf4j-api and logback-classic and logback-core:

EAR modeule
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>${slf4j.version}</version>
</dependency>

<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>${logback.version}</version>
</dependency>

<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-core</artifactId>
  <version>${logback.version}</version>
</dependency>

To define conf as Class-Path in your modules use lines below in maven-war-plugin, maven-jar-plugin and maven-ejb-plugin

WEB, EJB, API modules
<configuration>
  <archive>
    <addMavenDescriptor>false</addMavenDescriptor>
    <manifest>
      <addClasspath>true</addClasspath>
    </manifest>
    <manifestEntries>
      <Class-Path>logback</Class-Path>
    </manifestEntries>
  </archive>
...