Spring 3.1 Release and runtime exception with Logfactory
Join the DZone community and get the full member experience.
Join For FreeWith the upgrade this morning of our applications to Spring 3.1.1-RELEASE, we obtained odd runtime exceptions :
The detailed stacktrace is :
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory at org.springframework.context.support.AbstractApplicationContext.<init>(AbstractApplicationContext.java:161) at org.springframework.context.support.AbstractRefreshableApplicationContext.<init>(AbstractRefreshableApplicationContext.java:90) at org.springframework.context.support.AbstractRefreshableConfigApplicationContext.<init>(AbstractRefreshableConfigApplicationContext.java:59) at org.springframework.context.support.AbstractXmlApplicationContext.<init>(AbstractXmlApplicationContext.java:61) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:136) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) at com.tocea.codewatch.platform.service.local.LocalCodewatch.init(LocalCodewatch.java:116) at com.tocea.codewatch.platform.service.local.LocalCodewatch.<init>(LocalCodewatch.java:50) at com.tocea.codewatch.platform.front.test.FakeAuditTest.setUp(FakeAuditTest.java:54) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:616) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory at java.net.URLClassLoader$1.run(URLClassLoader.java:217) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:205) at java.lang.ClassLoader.loadClass(ClassLoader.java:321) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294) at java.lang.ClassLoader.loadClass(ClassLoader.java:266) ... 32 more
The suspected class is
/** ... */ public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean { >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> /** Logger used by this class. Available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
After inspecting the dependencies of our project with mvn dependency:dependency-list.
[INFO] \- org.springframework:spring-context:jar:3.1.1.RELEASE:compile [INFO] +- org.springframework:spring-aop:jar:3.1.1.RELEASE:compile [INFO] | \- aopalliance:aopalliance:jar:1.0:compile [INFO] +- org.springframework:spring-beans:jar:3.1.1.RELEASE:compile [INFO] +- org.springframework:spring-core:jar:3.1.1.RELEASE:compile [INFO] +- org.springframework:spring-expression:jar:3.1.1.RELEASE:compile [INFO] \- org.springframework:spring-asm:jar:3.1.1.RELEASE:com
Curiously, the class AbstractApplicationContext inside org.springframework:spring-context does not depend from commmons-logging of Apache.
The correction is rather simple : add the following lines to your pom.xml :
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1</version> </dependency>
A reader indicated me that :
Chin Huang :
The Spring Reference Documentation explains why Spring does NOT depend on Apache commons-logging and recommends using instead SLF4J and its jcl-over-slf4j library which adapts the commons-logging API to the SLF4J API.
Answer : The main problem is that nothing is indicated by maven that this choice exist and no suggestion is made by maven. That is a flaw would be interesting to fix in a new maven plugin. In Tocea, we are going to start a project to manage this kind of problem. Stay informed!
- Former occurence of this error : blog
- Spring Web site
- Apache Commons Logging web site
- Original article : article on Tocea blog
- Find defects in your code : techdebt.org
Opinions expressed by DZone contributors are their own.
Comments