Uploaded image for project: 'SLF4J'
  1. SLF4J
  2. SLF4J-573

SLF4J 2.0 searches for providers in the wrong classloader

    XMLWordPrintable

Details

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • None
    • 2.0.3
    • Core API
    • Java 11, Java 17

    Description

      I have tried to upgrade my tests from SLF4J 1.7.36 to SLF4J 2.0.3, but they are failing with this error:

      {{java.util.ServiceConfigurationError: org.slf4j.spi.SLF4JServiceProvider: org.slf4j.simple.SimpleServiceProvider not a subtype at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:589) at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1237) at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1265) at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1300) at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1385) at org.slf4j.LoggerFactory.findServiceProviders(LoggerFactory.java:104) at org.slf4j.LoggerFactory.bind(LoggerFactory.java:147) at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:139) at org.slf4j.LoggerFactory.getProvider(LoggerFactory.java:422) at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:408) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:357) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:383) }}

      My test has added slf4j-api, slf4j-simple and a jar containing a Callable into a single classloader that has a null parent classloader, and is then executing the task isolated from the application classloader. But unfortunately for me, LoggerFactory.findServiceProviders() is implemented like this:

      private static List<SLF4JServiceProvider> findServiceProviders() {
           ServiceLoader<SLF4JServiceProvider> serviceLoader = ServiceLoader.load(SLF4JServiceProvider.class);
           List<SLF4JServiceProvider> providerList = new ArrayList<>();
           for (SLF4JServiceProvider provider : serviceLoader) {
               providerList.add(provider);
           }
           return providerList;
      }

      Specifically, ServiceLoader.load() does not specify which classloader to use, and so defaults to the ThreadContextClassLoader.

      I believe a more compatible (with earlier versions of SLF4J) choice would be:

      ServiceLoader.load(SLF4JServiceProvider.class, LoggerFactory.class.getClassLoader())

       

      Attachments

        Activity

          People

            slf4j-dev SLF4J developers list
            chrisjr Chris Rankin
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: