I have the following situation in my project:
a large module (call it converter) with its own dependencies is being integrated into the main application (which has been developed separately by different people and has its own, partially overlapping, dependencies);
originally this converter module was callable from the command line as an executable jar so it has its own entry points (runnable classes with main() methods defined); this executable jar has been always created as an uber-jar via maven shade plugin;
now this converter module has to be additionally callable from the main application (to do this I, for now, directly call main() of the entry point classes after forming the command line arguments). The main application has also been created as an uber-jar and is planned to continue to be created this way.
So I am going to achieve the proper separation of dependencies using shade plugin for this case, to do this, I have added the following relocation specifications to the pom.xml for the converter module:
<relocations>
<relocation>
<pattern>com</pattern>
<shadedPattern>quase.com</shadedPattern>
</relocation>
<!-- ... other top-level patterns for converter dependencies -->
<relocation>
<pattern>org</pattern>
<shadedPattern>quase.org</shadedPattern>
<excludes>
<exclude>org.aau.**</exclude> <!-- my own code for converter is not shaded -->
</excludes>
</relocation>
</relocations>
As a result, all the dependencies of the converter module are shaded (with prepending quase. to them) while combined into the uber-jar of the main application.
The problem with this configuration is that both application and the converter use logging (slf4j with log4j) and after the converter method is called from the application code and starts to use logging, the following error occurs:
log4j:ERROR A "org.apache.log4j.FileAppender" object is not assignable to a "quase.org.apache.log4j.Appender" variable.
log4j:ERROR The class "quase.org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.FileAppender" was loaded by [sun.misc.Launcher$AppClassLoader@55f96302].
log4j:ERROR Could not instantiate appender named "file1".
log4j:ERROR A "org.apache.log4j.FileAppender" object is not assignable to a "quase.org.apache.log4j.Appender" variable.
log4j:ERROR The class "quase.org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.FileAppender" was loaded by [sun.misc.Launcher$AppClassLoader@55f96302].
log4j:ERROR Could not instantiate appender named "file2".
log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a "quase.org.apache.log4j.Appender" variable.
log4j:ERROR The class "quase.org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.ConsoleAppender" was loaded by [sun.misc.Launcher$AppClassLoader@55f96302].
log4j:ERROR Could not instantiate appender named "console".
log4j:WARN No appenders could be found for logger (org.aau.quase.quontology.builder.QuLogHandler).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
So it seems to me that the shaded logging code called from the converter module gets the reference to non-shaded logging code already initialized in the main application and fails because it expects the shaded code (see the failure to assign non-shaded org.apache.log4j.FileAppender
to shaded quase.org.apache.log4j.Appender
).
I have tried to exclude logging dependencies from shading in converter's pom.xml:
<excludes>
<exclude>org.aau.**</exclude>
<exclude>org.apache.log4j.**</exclude>
<exclude>org.slf4j.**</exclude>
</excludes>
but this led to further problems: the whole application fails as follows:
Exception in thread "main" java.lang.NoClassDefFoundError
at org.apache.log4j.Category.class$(Category.java:118)
at org.apache.log4j.Category.<clinit>(Category.java:118)
at org.apache.log4j.LogManager.<clinit>(LogManager.java:82)
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:66)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:277)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:288)
at org.aau.quase.application.LoggingProtocolHandler.<clinit>(LoggingProtocolHandler.java:16)
at org.aau.quase.application.QuASEApplication$1.<init>(QuASEApplication.java:71)
at org.aau.quase.application.QuASEApplication.<init>(QuASEApplication.java:65)
at org.aau.quase.application.util.QuASERunner.main(QuASERunner.java:8)
Caused by: java.lang.ClassNotFoundException: quase/org.apache.log4j.Category
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
... 10 more
Looks like the converter code still expects shaded version somehow as it fails to find quase/org.apache.log4j.Category
and quase is the shading prefix.
What am I doing wrong? Any help is greatly appreciated.
We were facing the same issue and we fixed it by excluding the log4j from the root itself rather than relocating them.
<configuration>
<filters>
<filter>
<artifact>groupId:artifactId:*</artifact>
<excludes><exclude>org/apache/log4j/**</exclude></excludes>
</filter>
</filters>
<relocations>
<relocation>
<pattern>com</pattern>
<shadedPattern>xyz.shaded.com</shadedPattern>
</relocation>
</relocations>
</configuration>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With