
Hi, We had a discussion earlier today with Martin Ellis and Ceki Gülcü on IRC. Martin challenged my proposal to make sure that we guarantee backwards compatibility, make it clear what we are exactly trying to solve and find the possible alternatives. The full log is available for interested parties [1]. The motivation: * make static bindings optional for developers using frameworks that already do binding (OSGi, Guice, Spring, etc) or want to roll their own solution. * make it easier to use OSGi features like having several implementations available concurrently * in general, make slf4j more modular. The main problem: We would like to separate the static binding logic from the general API: however the org.slf4j package contains both the central interfaces ILoggerFactory, Logger, IMarkerFactory and Marker and the static binding logic. To keep backwards compatibility for both "vanilla" Java and OSGi environments, we cannot easily split that package into two different JARs. The alternatives discussed: (1) Do nothing. :-) (2) We move static-binding related classes in the org.slf4j package (LoggerFactory, MarkerFactory) to another package (e.g: org.slf4j.factories). In order to provide backwards-compatibility, we keep the factory classes in the org.slf4j that delegate to their moved counterpart, but we deprecate them. (3) We create a new package org.slf4j.api in which we put the central interfaces ILoggerFactory, IMarkerFactory, Logger and Marker. In org.slf4j the original interfaces are deprecated, emptied (except for constants that delegate to the new interfaces) and extend the moved interfaces. (4) We make LoggerFactory/MarkerFactory return proxies to the actual implementations, so that we can support implementation swapping. This requires providing new SPI to define proxy factories. I won't elaborate on this alternative because it adds complexity (it could also be done as a complement of alternatives (2) or (3)). (2) vs. (3): Alternatives (2) and (3) differ on what gets deprecated, and on how soon people can get the benefit of the lighter API without static binding. In the call: Logger logger = LoggerFactory.get(..): * with (2), LoggerFactory only gets deprecated. It can be solved by simply changing the import from org.slf4j.LoggerFactory to org.slf4j.factories.LoggerFactory * with (3), Logger only gets deprecated. It can be solved by changing the import from org.slf4j.Logger to org.slf4j.api.Logger. In both case, we could provide support with the migrator tool to make the proper import change, and in any case there will be no removal of the classes without a lot of time, due notice, a major version change and a FAQ entry ;). Even then, for non-OSGi users, a very simple compatibility JAR can be dropped to support this ad vitam eternam. Alternative (3) puts a bit more effort on implementation providers, since they have to update the interfaces they implement. Still they will have plenty of time to do so since the interfaces they already implement will extend the new ones. Packaging: To keep full backwards compatibility while allowing interested parties to take only what they need, the plan would be to keep the current slf4j-api with the same contents, but provide two new lighter JARS: slf4j-light-api and slf4j-static-bindings. (slf4j-api = slf4j-light-api + slf4j-static-bindings) Solution (2) (I hope you used fixed-width fonts for mails ;)). --------------------- ----------------------- | slf4j-light-api | | slf4j-static-bindings | | | | | | [org.slf4j] | | [org.slf4j.factories] | | [org.slf4j.helpers] | | [org.slf4j.spi] | |_____________________| |_______________________| Solution (3) --------------------- ----------------------- | slf4j-light-api | | slf4j-static-bindings | | | | | | [org.slf4j.api] | | [org.slf4j] | | [org.slf4j.helpers] | | [org.slf4j.spi] | |_____________________| |_______________________| About implementation bindings: Currently, implementations are registered by providing a class org.slf4j.impl.Static{Logger,Marker}Binder. This is problematic in an OSGi environment, when several implementation bundles are installed, because multiple bundles export the same package/version with different contents. The wiring of the package used by clients likely depends on installation order of implementation bundles. While this is a non mandatory extra-step for now, ideally the implementation bundles should let users choose the binding system used. It is much simpler to solve on this side, for instance by keeping the org.slf4j.impl package but not exporting it in the OSGi manifest, and providing the package in another bundle that only exports it as a commodity for OSGi users wishing to use static binding. Since this is entirely transparent, there could be a Bundle-Activator entry in the implementation manifest to register the implementation factories as OSGi services, and the same implementation bundle could be dropped without change in both OSGi and non-OSGi environments. We could also provide other bindings (e.g for Guice, Spring, etc). Summary: We can remain backwards compatible until we feel it's time and do a major version change (i.e, in years). For the sake of good practices, we would mark interfaces @Deprecated but it's just a matter of changing the import (can be done by the provided migrator tool). We keep publishing JARs entirely compatible, but OSGi/Guice/Springs users who want to can gain flexibility by dropping static binding altogether. Those who want to use static bindings can as long as they want. So, this was supposed to be a short mail :). I hope it's clear, at least ;). Cheers, -- Simon [1] https://gist.github.com/0811d39d8264dcf881dc