[ 
https://issues.apache.org/jira/browse/LOGGING-192?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17873351#comment-17873351
 ] 

Björn Kautler commented on LOGGING-192:
---------------------------------------

Here as patch to the project:
{code:none}
diff --git a/pom.xml b/pom.xml
index 9f0a998..c3b092d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -285,6 +285,7 @@ under the License.
                 
<log4j12>${org.apache.logging.log4j:log4j-1.2-api:jar}</log4j12>
                 <logkit>${logkit:logkit:jar}</logkit>
                 
<servlet-api>${javax.servlet:javax.servlet-api:jar}</servlet-api>
+                <slf4j-api>${org.slf4j:slf4j-api:jar}</slf4j-api>
                 
<commons-logging>target/${project.build.finalName}.jar</commons-logging>
                 
<commons-logging-api>target/${project.build.finalName}-api.jar</commons-logging-api>
                 
<commons-logging-adapters>target/${project.build.finalName}-adapters.jar</commons-logging-adapters>
diff --git 
a/src/test/java/org/apache/commons/logging/tccl/logfactory/BadTCCLTestCase.java 
b/src/test/java/org/apache/commons/logging/tccl/logfactory/BadTCCLTestCase.java
new file mode 100644
index 0000000..6341493
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/logging/tccl/logfactory/BadTCCLTestCase.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.logging.tccl.logfactory;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.PathableClassLoader;
+import org.apache.commons.logging.PathableTestSuite;
+
+/**
+ * Verify that if a log framework was detected on tccl but commons-logging 
cannot be loaded from it
+ * detection happens again on the current class loader before trying to load 
commons-logging.
+ */
+
+public class BadTCCLTestCase extends TestCase {
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() throws Exception {
+        final Class thisClass = BadTCCLTestCase.class;
+
+        final PathableClassLoader emptyLoader = new PathableClassLoader(null);
+
+        final PathableClassLoader parentLoader = new 
PathableClassLoader(emptyLoader);
+        parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
+        parentLoader.addLogicalLib("commons-logging");
+        parentLoader.addLogicalLib("testclasses");
+
+        final PathableClassLoader tccl = new PathableClassLoader(emptyLoader);
+        tccl.addLogicalLib("slf4j-api");
+
+        final Class testClass = parentLoader.loadClass(thisClass.getName());
+        return new PathableTestSuite(testClass, tccl);
+    }
+
+    /**
+     * Sets up instance variables required by this test case.
+     */
+    @Override
+    public void setUp() throws Exception {
+        LogFactory.releaseAll();
+    }
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    @Override
+    public void tearDown() {
+        LogFactory.releaseAll();
+    }
+
+    public void testLoader() throws Exception {
+
+        final ClassLoader thisClassLoader = this.getClass().getClassLoader();
+        final ClassLoader tccl = 
Thread.currentThread().getContextClassLoader();
+
+        // the tccl should NOT be the same as the loader that loaded this test 
class.
+        assertNotSame("tccl is the same as test class loader", 
thisClassLoader, tccl);
+
+        // org.slf4j.Logger should not be loadable via this loader
+        try {
+            thisClassLoader.loadClass("org.slf4j.Logger");
+            fail("Unexpectedly able to load org.slf4j.Logger via test class 
loader");
+        } catch (final ClassNotFoundException ex) {
+            // ok, expected
+        }
+
+        // org.slf4j.Logger should be loadable via tccl
+        try {
+            final Class clazz = tccl.loadClass("org.slf4j.Logger");
+            assertNotNull(clazz);
+        } catch (final ClassNotFoundException ex) {
+            fail("Unexpectedly unable to load org.slf4j.Logger via tccl");
+        }
+
+        // org.apache.commons.logging.Log should not be loadable via tccl
+        try {
+            tccl.loadClass("org.apache.commons.logging.Log");
+            fail("Unexpectedly able to load org.apache.commons.logging.Log via 
tccl");
+        } catch (final ClassNotFoundException ex) {
+            // ok, expected
+        }
+
+        // org.apache.commons.logging.Log should be loadable via this loader
+        try {
+            final Class clazz = 
thisClassLoader.loadClass("org.apache.commons.logging.Log");
+            assertNotNull(clazz);
+        } catch (final ClassNotFoundException ex) {
+            fail("Unexpectedly unable to load org.apache.commons.logging.Log 
via test class loader");
+        }
+
+        // getting a Logger from this loader should not throw an exception
+        final Class clazz = 
thisClassLoader.loadClass("org.apache.commons.logging.LogFactory");
+        clazz.getMethod("getLog", String.class).invoke(null, "");
+    }
+}
 {code}

> NoClassDefFoundError: org/apache/logging/log4j/spi/LoggerAdapter when using 
> custom classloader
> ----------------------------------------------------------------------------------------------
>
>                 Key: LOGGING-192
>                 URL: https://issues.apache.org/jira/browse/LOGGING-192
>             Project: Commons Logging
>          Issue Type: Bug
>    Affects Versions: 1.3.0, 1.3.1, 1.3.2
>         Environment: This behavior was observed while running Adopt Open JDK 
> 11 and the latest version of Tomcat 9.  The behavior can be reproduced 
> outside of tomcat (see attached reproduction case).
>            Reporter: Dave Dority
>            Priority: Major
>         Attachments: commons-logging-classloading-issue.zip
>
>
> If you have:
>  * A web application running in Tomcat which contains commons-logging:1.2
>  * That web application contains a custom classloader for loading a 
> seperately distributed software component (whose dependencies will conflict 
> with the dependencies of the web application).
>  * The software component uses commons-logging:1.3.2
> When the web application attempts use software component, the code 
> [here|https://github.com/apache/commons-logging/blob/rel/commons-logging-1.3.2/src/main/java/org/apache/commons/logging/LogFactory.java#L918-L938]
>  looks for the presence of different logging implementation classes on the 
> thread context classloader's (TCCL) classpath to select an optimal 
> implementation.  It seems like what is happening is that the LogFactory class 
> looking for implementation class on the TCCL's classpath and the trying to 
> load the selected factory from the web application's custom classloader (the 
> loader for the instance of LogFactory that is running).  This is the result:
> {code:java}
> Exception in thread "main" java.lang.NoClassDefFoundError: 
> org/apache/logging/log4j/spi/LoggerAdapter
>         at java.base/java.lang.Class.forName0(Native Method)
>         at java.base/java.lang.Class.forName(Class.java:315)
>         at 
> org.apache.commons.logging.LogFactory.createFactory(LogFactory.java:419)
>         at 
> org.apache.commons.logging.LogFactory.lambda$newFactory$3(LogFactory.java:1431)
>         at java.base/java.security.AccessController.doPrivileged(Native 
> Method)
>         at 
> org.apache.commons.logging.LogFactory.newFactory(LogFactory.java:1431)
>         at 
> org.apache.commons.logging.LogFactory.getFactory(LogFactory.java:928)
>         at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:987)
>         at 
> org.component.ClassLoadedComponent.<clinit>(ClassLoadedComponent.java:7)
>         at 
> java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native
>  Method)
>         at 
> java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
>         at 
> java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
>         at 
> java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
>         at java.base/java.lang.Class.newInstance(Class.java:584){code}
> This occurs when the web application has commons-logging:1.2 and the software 
> component has commons-logging:1.3.x.  This does not occur when both are using 
> version 1.2. 
> Unfortunately, changing the web application's version of commons-logging is 
> outside is not something I can influence.
> An isolated reproduction case is attached.  It requires Java 11.  To run it:
>  * Unzip it to a directory.
>  * Run 
> {code:java}
> ./gradlew reproduceIssue{code}
>   



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to