Thursday, July 19, 2007

No more commons-logging

Update 2007-10-10: No-commons-logging has been superseded by (backward compatible) Version 99 Does Not Exist.

Disclaimer
COMMONS-LOGGING VERSION 99.0-does-not-exist IS NOT IN ANY WAY AFFILIATED WITH THE ORIGINAL DEVELOPERS OF COMMONS-LOGGING NOR WITH APACHE.

Why no-commons-logging?
If you are using Maven you'll know it is practically impossible to move away from commons-logging (with its class-loading problems) and migrate to SLF4J. About every second pom declares it is dependent on commons-logging. Unfortunately Maven does not provide an easy way to exclude a certain package throughout your project. You will have to exclude commons-logging on each and every dependency you need (including transitive dependencies).

No-commons-logging is a Maven hack that allows you to exclude commons-logging from your application with a single piece of configuration.

How does no-commons-logging work?
No-commons-logging is a Maven2 package that mimics a commons-logging package with a high version number, but without any actual java code in the jar. This trick works because Maven allows you to specify a specific version for a dependency, and that version will then be used regardless of other dependency specifications.

Update 2007-07-22: Added package to mimic commons-logging-api as requested by Olivier Lamy.

How do you use no-commons-logging?
In your pom.xml include the following piece of xml:

<repositories>
    <repository>
        <id>no-commons-logging</id>
        <name>No-commons-logging Maven Repository</name>
        <layout>default</layout>
        <url>http://no-commons-logging.zapto.org/mvn2</url>
    </repository>
</repositories>
<dependencies>
    <!-- use no-commons-logging -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>99.0-does-not-exist</version>
    </dependency>
    <!-- no-commons-logging-api, if you need it -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging-api</artifactId>
        <version>99.0-does-not-exist</version>
    </dependency>
    <!-- the slf4j commons-logging replacement -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl104-over-slf4j</artifactId>
        <version>1.4.2</version>
    </dependency>
    <!-- the other slf4j jars -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.4.2</version>
    </dependency>
    <!-- using log4j as backend -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.4.2</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.14</version>
    </dependency>
</dependencies>

Disclaimer
COMMONS-LOGGING VERSION 99.0-does-not-exist IS NOT IN ANY WAY AFFILIATED WITH THE ORIGINAL DEVELOPERS OF COMMONS-LOGGING NOR WITH APACHE.

13 comments:

  1. Interesting hack... I wonder what are the prospects of getting Maven changed to use SLF4J natively instead of JCL? It's bound to change sooner or later as more and more developers realize that it's better.

    ReplyDelete
  2. Arther, I am sure exclusion of packages in Maven's dependency management will be supported one day. This is just not that day yet.

    BTW, on the Maven mailing I already asked whether this feature is available. As I got no response, I assumed there was no interest. Which is of course their good right. Furthermore, if you don't like an open source project, you either don't use it, or you improve it. I choose to cheet :)

    ReplyDelete
  3. It's kind of awful that one needs to go all these hoops to avoid JCL but when you need to weed out JCL in 45 dependencies, your method may save time and grief.

    Erik, thank you for sharing this hack.

    ReplyDelete
  4. Thanks for the workaround.
    an artifact commons-logging-api is needed too ;-)

    ReplyDelete
  5. Olivier, I added commons-logging-api :)

    ReplyDelete
  6. Hi,

    for me the workaround doesn't work together with jasperreports. If I depend on commons-logging-99.0-does-not-exist and jasperreports-2.0.0 in one pom I get various errors like "Missing indirectly referenced artifact commons-collections:commons-collections:jar:99.0-does-not-exist:compile" within eclipse. It seems that maven tries to get a 99.0 version for every JAR that depends on jasperreports. Could you please try to reproduce this?

    I just imported...

    groupId: commons-logging
    artifactId: commons-logging
    version: 99.0-does-not-exist

    ...and...

    groupId: jasperreports
    artifactId: jasperreports
    version: 2.0.0

    Thanks
    Sebastian

    ReplyDelete
  7. Sebastian, please search for commons-collections and see what version you specify there.

    The poms I serve do not declare any dependency so this can not be the problem.

    There one other possible problem: if jasperreports declares a dependency to commons-collections with version range, and the version range has an open end version, Maven will pick up version 99.0-does-not-exist.

    ReplyDelete
  8. Erik, that's it. Indeed jasperreports declares its dependencies with an open version range, therefore I explicitly declared them with a fixed version. Now it works. Thanks a lot.

    ReplyDelete
  9. I've pushed the concept further and used dependencyManagement clause in my top-level parent project.

    And then I created Maven relocations to jcl-over-slf4j in my local repository.

    It works great, cleans up the mess, since I dont see commons-logging EVER, not even in M2Eclipse dependency diagram. And I dont have an empty placeholder jar floating in my libs.

    I dont have a blog and cant post the XML here, e-mail me for details at francis DOT lalonde AT cgi.com

    ReplyDelete
  10. Perhaps people would be interested in voting for a real solution to this problem provided by Maven: http://jira.codehaus.org/browse/MNG-5101

    ReplyDelete
  11. I really don't understand how you can add your own version for a widely used library. It is non-sense and it is intrusive.
    Please don't hack stuff which are used by people, just play around with your 'own' stuff. Please.

    ReplyDelete
    Replies
    1. I did not add my own version of existing libraries to maven central. You have to opt-in to the virtual maven repository in order to get these special versions.

      Delete