[
https://issues.apache.org/jira/browse/LOGGING-192?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17873281#comment-17873281
]
Björn Kautler edited comment on LOGGING-192 at 8/13/24 7:15 PM:
----------------------------------------------------------------
This can also be reproduce relatively simple.
Open a Gradle Kotlin DSL build script, paste in
{code:java}
val jasperReportsAnt = configurations.dependencyScope("jasperReportsAnt")
val jasperReportsAntRuntimeClasspath =
configurations.resolvable("jasperReportsAntRuntimeClasspath") {
extendsFrom(jasperReportsAnt.get())
}
dependencies {
jasperReportsAnt("net.sf.jasperreports:jasperreports-ant:7.0.0")
}
AntBuilder().apply {
isSaveStreams = false
}.withGroovyBuilder {
"taskdef"(
"name" to "jcr",
"classname" to "net.sf.jasperreports.ant.JRAntCompileTask",
"classpath" to jasperReportsAntRuntimeClasspath.get().asPath,
"uri" to "antlib:net.sf.jasperreports.ant"
)
"antlib:net.sf.jasperreports.ant:jcr"(
"srcdir" to file("."),
"includes" to "none"
)
} {code}
and run any task, it will fail searching for {{{}org.slf4j.MarkerFactory{}}}.
Add in front
{code:java}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.apache.logging.log4j:log4j-api:2.+")
}
} {code}
and run any task again, it will fail searching for
{{{}org.apache.logging.log4j.spi.LoggerAdapter{}}}.
It does not happen with {{{}ant.withGroovyBuilder \{ ... }{{}}}}, but you
cannot use that everywhere in Groovy, for example within worker actions where
you have to use the standard Groovy {{{}AntBuilder{}}}.
The problem is like this (using slf4j as example):
- {{LogFactory}} searches on the context classloader for {{org.slf4j.Logger}}
(in my example the Gradle build script classpath)
- It finds the class so wants to use its
{{org.apache.commons.logging.impl.Slf4jLogFactory}}
- Then it tries to load {{Slf4jLogFactory}} from the context classloader but
of course does not find it there as {{commons-logging}} is not present there
- Then as fallback tries to load {{Slf4jLogFactory}} from the current
classloader, which also fails, as there {{slf4j}} is not present and so the
{{Slf4jLogFactory}} class cannot be initialized
I guess the appropriate solution would be that when going the fallback route of
not using the context classloader but the current classloader, that then the
detection also has to be redone as the previous result is stale and possibly
wrong.
was (Author: vampire):
This can also be reproduce relatively simple.
Open a Gradle Kotlin DSL build script, paste in
{code:java}
val jasperReportsAnt = configurations.dependencyScope("jasperReportsAnt")
val jasperReportsAntRuntimeClasspath =
configurations.resolvable("jasperReportsAntRuntimeClasspath") {
extendsFrom(jasperReportsAnt.get())
}
dependencies {
jasperReportsAnt("net.sf.jasperreports:jasperreports-ant:7.0.0")
}
AntBuilder().apply {
isSaveStreams = false
}.withGroovyBuilder {
"taskdef"(
"name" to "jcr",
"classname" to "net.sf.jasperreports.ant.JRAntCompileTask",
"classpath" to jasperReportsAntRuntimeClasspath.get().asPath,
"loaderref" to jasperReportsAntRuntimeClasspath.get().asPath,
"uri" to "antlib:net.sf.jasperreports.ant"
)
"antlib:net.sf.jasperreports.ant:jcr"(
"srcdir" to file("."),
"includes" to "foo.jrxml"
) {
"classpath" {
"pathelement"("path" to
jasperReportsAntRuntimeClasspath.get().asPath)
}
}
}
{code}
and run any task, it will fail searching for {{{}org.slf4j.MarkerFactory{}}}.
Add in front
{code:java}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.apache.logging.log4j:log4j-api:2.+")
}
} {code}
and run any task again, it will fail searching for
{{{}org.apache.logging.log4j.spi.LoggerAdapter{}}}.
It does not happen with {{{}ant.withGroovyBuilder \{ ... }{{}}}}, but you
cannot use that everywhere in Groovy, for example within worker actions where
you have to use the standard Groovy {{{}AntBuilder{}}}.
The problem is like this (using slf4j as example):
- {{LogFactory}} searches on the context classloader for {{org.slf4j.Logger}}
(in my example the Gradle build script classpath)
- It finds the class so wants to use its
{{org.apache.commons.logging.impl.Slf4jLogFactory}}
- Then it tries to load {{Slf4jLogFactory}} from the context classloader but
of course does not find it there as {{commons-logging}} is not present there
- Then as fallback tries to load {{Slf4jLogFactory}} from the current
classloader, which also fails, as there {{slf4j}} is not present and so the
{{Slf4jLogFactory}} class cannot be initialized
I guess the appropriate solution would be that when going the fallback route of
not using the context classloader but the current classloader, that then the
detection also has to be redone as the previous result is stale and possibly
wrong.
> 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)