I am stuck with the following Maven problem.
Basically, I have two projects. Project A is a Maven plugin and project B is using it.
Project A pom.xml
:
<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>io.github.martinschneider</groupId>
<artifactId>demo-maven-plugin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>maven-plugin</packaging>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.6.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Project B pom.xml
:
<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>io.github.martinschneider</groupId>
<artifactId>demo-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>io.github.martinschneider</groupId>
<artifactId>demo-maven-plugin</artifactId>
<version>0.0.1-SNAPSHOT</version>
</plugin>
</plugins>
</build>
</project>
When executing mvn demo:demo
on project B, the mojo starts executing but then I get the following error:
[ERROR] Failed to execute goal my.group:my-maven-plugin:1.2.3:some-goal (default-cli) on project my-project: Execution default-cli of goal my.group:my-maven-plugin:1.2.3:some-goal failed: A required class was missing while executing io.github.martinschneider:demo-maven-plugin:0.0.1-SNAPSHOT:demo: org/slf4j/event/Level
The core message of the error is:
A required class was missing [...] : org/slf4j/event/Level
The log and stacktrace also include:
[WARNING] Error injecting: package.SomeMojo java.lang.NoClassDefFoundError: org/slf4j/event/Level
and
Caused by: java.lang.ClassNotFoundException: org.slf4j.event.Level
at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass (SelfFirstStrategy.java:50)
at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass (ClassRealm.java:271)
at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass (ClassRealm.java:247)
at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass (ClassRealm.java:239)
It boils down to org.slf4j.event.Level
not being found on the classpath which is strange because it is in slf4j-api
which is both an explicit and a transitive (via slf4j-core
) dependency in the plugin.
However, for some reason it is not included in the class realm:
[DEBUG] Populating class realm plugin>io.martinschneider.github:demo-maven-plugin:0.0.1-SNAPSHOT
[DEBUG] Included: io.martinschneider.github:demo-maven-plugin:0.0.1-SNAPSHOT
[DEBUG] Included: org.slf4j:slf4j-simple:jar:1.7.25
...
slf4j-simple
is in the list, slf4j-api
is not.
A few lines earlier:
[DEBUG] Dependency collection stats: {ConflictMarker.analyzeTime=121223, ConflictMarker.markTime=606293, ConflictMarker.nodeCount=72, ConflictIdSorter.graphTime=74295, ConflictIdSorter.topsortTime=819750, ConflictIdSorter.conflictIdCount=45, ConflictIdSorter.conflictIdCycleCount=0, ConflictResolver.totalTime=1909563, ConflictResolver.conflictItemCount=70, DefaultDependencyCollector.collectTime=68369892, DefaultDependencyCollector.transformTime=3575054}
[DEBUG] io.martinschneider.github:demo-maven-plugin:jar:0.0.1-SNAPSHOT:
[DEBUG] org.slf4j:slf4j-simple:jar:1.7.25:compile
[DEBUG] org.slf4j:slf4j-api:jar:1.7.25:compile
...
Here, both slf4j-simple
and slf4j-api
are included.
The problem only occurs when I explicitly use the affected class org.slf4j.event.Level
in my plugin code. If I remove any explicit usage of it everything works fine.
I'm using Maven 3.5.2 and Java 11.
I don't know if this is a problem with SLF4J or a more general problem with Maven or just an unlucky combination of events.
What I've tried:
- deleted and re-populated my Maven repo (to rule out corrupted JAR files)
- tried different versions of SLF4J
- explicitly added
slf4j-api
under<pluginDepdendencies>
- used Java 8 (instead of 11)
UPDATE I've created a demo project to reproduce this error: https://github.com/martinschneider/stackoverflow_53757567
As per comment in MNG-5845 issue for similar problem:
The problem comes from the fact that we are exporting the slf4j-api artefact, thus plugins cannot use their own version but we forgot to export the content of the package org/slf4j/helpers. Thus the
java.lang.ClassNotFoundException: org.slf4j.helpers.MessageFormatter
slf4j-api
is one of the special dependencies exported by maven core however org.sfl4j.event
package isn't exported. Looking at Maven master, currently the following packages are exported:
<!-- SLF4J -->
<exportedPackage>org.slf4j.*</exportedPackage>
<exportedPackage>org.slf4j.spi.*</exportedPackage>
<exportedPackage>org.slf4j.helpers.*</exportedPackage>
Because of above you won't be able to access classes from org.sfl4j.event
package during your plugin execution. You can compile the plugin code since the compile classpath is different than runtime classpath. This can be confirmed by removing the second log statement and related import
statement, the plugin will execute just fine which proves that SLF4J JARs aren't corrupted:
[INFO] ---------------< io.github.martinschneider:demo-project >---------------
[INFO] Building demo-project 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- demo-maven-plugin:0.0.1-SNAPSHOT:demo (default-cli) @ demo-project ---
[INFO] Hello world!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
You can either open a new issue in Maven project and include a new export statement or implement plugin logging with standard getLog()
method as per A Simple Mojo guide:
@Mojo(name = "demo")
public class DemoMojo extends AbstractMojo {
public void execute() throws MojoExecutionException, MojoFailureException {
getLog().info("Hello world!");
}
}