I have been unsuccessfully trying to include slf4j
in a project. I've added slf4j-api-1.7.32.jar
and slf4j-jdk14-1.7.32.jar
into the classpath but no matter what I've tried I end up with a java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
.
The initial part of the error is
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at com.google.gwt.dev.shell.jetty.JettyLauncher$WebAppContextWithReload$WebAppClassLoaderExtension.findClass(JettyLauncher.java:354)
at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:366)
at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:337)
...
(happy to include more if it would be helpful but the compiler cuts it off at that point)
The project is in Eclipse and I've tried
- putting the libraries at the beginning of the class path
- putting them at the end
- turning Eclipse off and on
- rebuilding the project
- using different versions
Nothing seems to work.
However, oddly, with the exact same collection of libraries it works fine in JUnit tests I've written.
This morning a coworker found that adding the pair of slf4j
libraries to war/WEB-INF/lib
got things working, but this isn't a workable long term solution.
I'm hoping someone out there has some bright ideas!
Edit: Made some more progress. From here needed to add
<Set name="systemClasses">
<Array type="java.lang.String">
<!-- we from jetty WebAppContext source code ...-->
<Item>java.</Item>
<Item>javax.servlet.</Item>
<Item>javax.xml.</Item>
<Item>org.mortbay.</Item>
<Item>org.xml.</Item>
<Item>org.w3c.</Item>
<Item>org.apache.commons.logging.</Item>
<Item>org.apache.log4j.</Item>
<!-- and ... added slf4j -->
<Item>org.slf4j.</Item>
</Array>
</Set>
to jetty-web.xml
. Now need to find out what needs to change in deploy script.
CodePudding user response:
Solution:
Add the following 'systemClasses' set to the jetty-web.xml
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">
...
<Set name="systemClasses">
<Array type="java.lang.String">
<!-- we copied these paths from jetty WebAppContext source code ...-->
<Item>java.</Item>
<Item>javax.servlet.</Item>
<Item>javax.xml.</Item>
<Item>org.mortbay.</Item>
<Item>org.xml.</Item>
<Item>org.w3c.</Item>
<Item>org.apache.commons.logging.</Item>
<Item>org.apache.log4j.</Item>
<!-- and ... added slf4j -->
<Item>org.slf4j.</Item>
<!-- we must promote slf4j to system classes, otherwise gwt
hosted mode will not allow loading them due to a policy
that don't allow server classes to be loaded from the
outside world (see gwt JettyLauncher source code). -->
</Array>
</Set>
</Configure>
As found in this message board from 2009: https://www.mail-archive.com/[email protected]/msg14754.html
How we found the solution:
While stepping through JettyLauncher.WebAppContextWithReload.WebAppClassLoaderExtension.findClass(String name)
showed that on first load, most super.findClass(name)
threw a ClassNotFoundException
, then as they passed isServerPath
they got down to using the systemClassLoader
to load them from .jar files. Now the systemClassLoader
has parent type URLClassLoader
which has a field ucp
(URLClassPath
) that has a list (under path
) of all the .jar files that it can load classes from. Taking a look in here, the slf4j jars indeed existed, but for some reason isServerPath
was returning true. This is finally what led to finding the solution above.