Igor Kromin |   Consultant. Coder. Blogger. Tinkerer. Gamer.

Recently at work a big amount of effort has been put in to adding unit tests for as much code as possible. Due to the nature of the services that we work with, we required to make heavy use of PowerMock. It's a great framework that lets us mock out certain classes that are usually hard to mock, like statics, and unfortunately at one point I started to see LinkageError exceptions being thrown that looked like this...
WARNING: Error while registering Oracle JDBC Diagnosability MBean.
java.lang.LinkageError: loader constraint violation: loader (instance of org/powermock/core/classloader/MockClassLoader) previously initiated loading for a different type with name "javax/management/MBeanServer"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at org.powermock.core.classloader.MockClassLoader.loadUnmockedClass(MockClassLoader.java:262)
at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:206)
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass1(DeferSupportingClassLoader.java:89)
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:79)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at oracle.jdbc.driver.OracleDriver.registerMBeans(OracleDriver.java:360)
at oracle.jdbc.driver.OracleDriver$1.run(OracleDriver.java:199)
at java.security.AccessController.doPrivileged(Native Method)
at oracle.jdbc.driver.OracleDriver.<clinit>(OracleDriver.java:195)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380)
at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)
at java.util.ServiceLoader$1.next(ServiceLoader.java:480)
at java.sql.DriverManager$2.run(DriverManager.java:603)
at java.sql.DriverManager$2.run(DriverManager.java:583)
at java.security.AccessController.doPrivileged(Native Method)
at java.sql.DriverManager.loadInitialDrivers(DriverManager.java:583)
at java.sql.DriverManager.<clinit>(DriverManager.java:101)

So what does this mean? Well PowerMock prepares and loads mocked classes using its MockClassLoader. In some cases this behaviour is undesirable and the mocked class must be loaded by the system class loader instead. This is easily done with the PowerMockIgnore annotation like this...
public class MyTestClass {

So in my case since the LinkageError was for the javax/management/MBeanServer class, I use the "javax.management.*" value to make sure that everything in the javax.management package is deferred to the system class loader (I could have used the specific class but I chose to use the entire package).

There is a way to apply this type of configuration globally by creating a file, "org/powermock/extensions/configuration.properties", and adding it to the classpath (if using Maven in the src/test/resources directory). The configuration file is a standard Java Properties file and needs to have the "powermock.global-ignore" set the same way as the annotation, however I couldn't get this to work.


Skip down to comments...
A quick disclaimer...

Although I put in a great effort into researching all the topics I cover, mistakes can happen. If you spot something out of place, please do let me know.

All content and opinions expressed on this Blog are my own and do not represent the opinions of my employer (Oracle). Use of any information contained in this blog post/article is subject to this disclaimer.
comments powered by Disqus
Other posts you may like...