Browse Source

Update LogAdapter to allow build-time code removal

Allow for example to remove those classes and 90 related methods when Logback is used:
- org.apache.commons.logging.LogAdapter$JavaUtilAdapter
- org.apache.commons.logging.LogAdapter$JavaUtilLog
- org.apache.commons.logging.LogAdapter$LocationResolvingLogRecord
- org.apache.commons.logging.LogAdapter$Log4jAdapter
- org.apache.commons.logging.LogAdapter$Log4jLog
- org.apache.commons.logging.LogAdapter$LogApi
- org.apache.logging.log4j.message.ObjectMessage
- org.apache.logging.log4j.message.ReusableObjectMessage
- org.apache.logging.log4j.simple.SimpleLoggerContext
- org.apache.logging.log4j.simple.SimpleLoggerContextFactory

Closes gh-29506
pull/29534/head
Sébastien Deleuze 3 years ago
parent
commit
04366f4129
  1. 3
      spring-core/src/main/java/org/springframework/aot/nativex/feature/PreComputeFieldFeature.java
  2. 53
      spring-jcl/src/main/java/org/apache/commons/logging/LogAdapter.java

3
spring-core/src/main/java/org/springframework/aot/nativex/feature/PreComputeFieldFeature.java

@ -36,7 +36,8 @@ class PreComputeFieldFeature implements Feature {
Pattern.compile(Pattern.quote("org.springframework.core.NativeDetector#imageCode")), Pattern.compile(Pattern.quote("org.springframework.core.NativeDetector#imageCode")),
Pattern.compile(Pattern.quote("org.springframework.") + ".*#.*Present"), Pattern.compile(Pattern.quote("org.springframework.") + ".*#.*Present"),
Pattern.compile(Pattern.quote("org.springframework.") + ".*#.*PRESENT"), Pattern.compile(Pattern.quote("org.springframework.") + ".*#.*PRESENT"),
Pattern.compile(Pattern.quote("reactor.") + ".*#.*Available") Pattern.compile(Pattern.quote("reactor.") + ".*#.*Available"),
Pattern.compile(Pattern.quote("org.apache.commons.logging.LogAdapter") + "#.*Present")
}; };
private final ThrowawayClassLoader throwawayClassLoader = new ThrowawayClassLoader(PreComputeFieldFeature.class.getClassLoader()); private final ThrowawayClassLoader throwawayClassLoader = new ThrowawayClassLoader(PreComputeFieldFeature.class.getClassLoader());

53
spring-jcl/src/main/java/org/apache/commons/logging/LogAdapter.java

@ -17,6 +17,7 @@
package org.apache.commons.logging; package org.apache.commons.logging;
import java.io.Serializable; import java.io.Serializable;
import java.util.function.Function;
import java.util.logging.LogRecord; import java.util.logging.LogRecord;
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Level;
@ -32,45 +33,52 @@ import org.slf4j.spi.LocationAwareLogger;
* Detects the presence of Log4j 2.x / SLF4J, falling back to {@code java.util.logging}. * Detects the presence of Log4j 2.x / SLF4J, falling back to {@code java.util.logging}.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sebastien Deleuze
* @since 5.1 * @since 5.1
*/ */
final class LogAdapter { final class LogAdapter {
private static final String LOG4J_SPI = "org.apache.logging.log4j.spi.ExtendedLogger"; private static final boolean log4jSpiPresent = isPresent("org.apache.logging.log4j.spi.ExtendedLogger");
private static final String LOG4J_SLF4J_PROVIDER = "org.apache.logging.slf4j.SLF4JProvider"; private static final boolean log4jSlf4jProviderPresent = isPresent("org.apache.logging.slf4j.SLF4JProvider");
private static final String SLF4J_SPI = "org.slf4j.spi.LocationAwareLogger"; private static final boolean slf4jSpiPresent = isPresent("org.slf4j.spi.LocationAwareLogger");
private static final String SLF4J_API = "org.slf4j.Logger"; private static final boolean slf4jApiPresent = isPresent("org.slf4j.Logger");
private static final LogApi logApi; private static final Function<String, Log> createLog;
static { static {
if (isPresent(LOG4J_SPI)) { if (log4jSpiPresent) {
if (isPresent(LOG4J_SLF4J_PROVIDER) && isPresent(SLF4J_SPI)) { if (log4jSlf4jProviderPresent && slf4jSpiPresent) {
// log4j-to-slf4j bridge -> we'll rather go with the SLF4J SPI; // log4j-to-slf4j bridge -> we'll rather go with the SLF4J SPI;
// however, we still prefer Log4j over the plain SLF4J API since // however, we still prefer Log4j over the plain SLF4J API since
// the latter does not have location awareness support. // the latter does not have location awareness support.
logApi = LogApi.SLF4J_LAL; createLog = Slf4jAdapter::createLocationAwareLog;
} }
else { else {
// Use Log4j 2.x directly, including location awareness support // Use Log4j 2.x directly, including location awareness support
logApi = LogApi.LOG4J; createLog = Log4jAdapter::createLog;
} }
} }
else if (isPresent(SLF4J_SPI)) { else if (slf4jSpiPresent) {
// Full SLF4J SPI including location awareness support // Full SLF4J SPI including location awareness support
logApi = LogApi.SLF4J_LAL; createLog = Slf4jAdapter::createLocationAwareLog;
} }
else if (isPresent(SLF4J_API)) { else if (slf4jApiPresent) {
// Minimal SLF4J API without location awareness support // Minimal SLF4J API without location awareness support
logApi = LogApi.SLF4J; createLog = Slf4jAdapter::createLog;
} }
else { else {
// java.util.logging as default // java.util.logging as default
logApi = LogApi.JUL; // Defensively use lazy-initializing adapter class here as well since the
// java.logging module is not present by default on JDK 9. We are requiring
// its presence if neither Log4j nor SLF4J is available; however, in the
// case of Log4j or SLF4J, we are trying to prevent early initialization
// of the JavaUtilLog adapter - e.g. by a JVM in debug mode - when eagerly
// trying to parse the bytecode for all the cases of this switch clause.
createLog = JavaUtilAdapter::createLog;
} }
} }
@ -84,19 +92,7 @@ final class LogAdapter {
* @param name the logger name * @param name the logger name
*/ */
public static Log createLog(String name) { public static Log createLog(String name) {
return switch (logApi) { return createLog.apply(name);
case LOG4J -> Log4jAdapter.createLog(name);
case SLF4J_LAL -> Slf4jAdapter.createLocationAwareLog(name);
case SLF4J -> Slf4jAdapter.createLog(name);
default ->
// Defensively use lazy-initializing adapter class here as well since the
// java.logging module is not present by default on JDK 9. We are requiring
// its presence if neither Log4j nor SLF4J is available; however, in the
// case of Log4j or SLF4J, we are trying to prevent early initialization
// of the JavaUtilLog adapter - e.g. by a JVM in debug mode - when eagerly
// trying to parse the bytecode for all the cases of this switch clause.
JavaUtilAdapter.createLog(name);
};
} }
private static boolean isPresent(String className) { private static boolean isPresent(String className) {
@ -110,9 +106,6 @@ final class LogAdapter {
} }
private enum LogApi {LOG4J, SLF4J_LAL, SLF4J, JUL}
private static class Log4jAdapter { private static class Log4jAdapter {
public static Log createLog(String name) { public static Log createLog(String name) {

Loading…
Cancel
Save