NoClassDefFoundError: org/hamcrest/Matchers using

2019-05-23 03:33发布

问题:

I get an NoClassDefFoundError for org.hamcrest.Matchers, when i run my Test as OSGi PlugIn test, but when i run it as plain JUnit test everthing works as expected. I am using the OSGi version of PowerMock and have all neccessary dependencies in my launch config. What i am doing wrong? It seems like the Testrunner doesnt see the class, for some reason.

Edit: I created a reduced sample project and figured out that the Problem only appear when i use @PrepareForTest(XXX.class) in my class declaration.


java.lang.NoClassDefFoundError: org/hamcrest/Matchers
    at eu.gemtec.commons.util.assertion.Assert.assertParamNotNull(Assert.java:107)
    at eu.gemtec.eagle.device.aastra.omaxi.core.system.model.impl.MessageHandleFactory.<init>(MessageHandleFactory.java:72)
    at eu.gemtec.eagle.device.aastra.omaxi.core.system.model.impl.TestMessageHandleFactory.setUp(TestMessageHandleFactory.java:74)
    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:601)
    at org.junit.internal.runners.MethodRoadie.runBefores(MethodRoadie.java:132)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:95)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$LastRuleTestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:148)
    at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:91)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:104)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53)
    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.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:62)
    at org.eclipse.pde.internal.junit.runtime.CoreTestApplication.run(CoreTestApplication.java:23)
    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:601)
    at org.eclipse.equinox.internal.app.EclipseAppContainer.callMethodWithException(EclipseAppContainer.java:587)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:198)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:344)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
    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:601)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:622)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:577)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1410)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1386)
Caused by: java.lang.ClassNotFoundException: org.hamcrest.Matchers
    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:467)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:429)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:417)
    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:65)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 52 more

回答1:

If you take a look at the update site of Powermock-osgi, you will notice, that there are hamcrest and junit bundles there. They are however not the "normal" official released bundles, but are wrapper bundles exposing more packages than the official ones.

If you use Eclipse, the bundle pools of the workspaces are shared. The bundles are looked up using symbolic name and version. So you have to add junit and hamcrest from the update site of powermock-osgi, and you have to be sure, that before resolving the target platform you deleted ALL bundle pools of all workspaces.

See Powermock-OSGI site:

Tycho and Eclipse PDE caches the bundles based on symbolic name and version. So if the user already had a 4.11 version of Junit anytime in the past, our hacked powermock version will not be taken.

So before first usage inside Eclipse the user has to delete the .metadata.plugins\org.eclipse.pde.core.bundle_pool and .metadata.plugins\org.eclipse.pde.core.external_libraries in ALL workspaces of the specific Eclipse installation (bundles are looked up cross workspace way). BE SURE, that when you run the unit tests in eclipse the plugins tab in the launch config REALLY contains the JUnit, Mockito and Hamcrest plugins of the Powermock feature, and not some other version. Before first usage with Tycho delete the .meta .cache and p2 folders from the maven local repository

If this is not the case, then please provide the followings to let me help you:

  • your target file as XML
  • the test fragment manifest and host bundle manifest
  • the size of your hamcrest and junit bundles inside

If you file an issue at https://code.google.com/p/powermock-osgi/ with a sample project, I will take a look at it.

EDIT: One more thing. Is the class eu.gemtec.commons.util.assertion.Assert inside an OSGI bundle importing hamcrest as dependency? Is eu.gemtec.commons.util.assertion package exported?

EDIT2: It turned out, that my "hacked" powermock-osgi version of hamcrest does not export org.hamcrest as split package, and that is the problem. Fix for the update site comes soon. See https://code.google.com/p/powermock-osgi/issues/detail?id=2#c4

EDIT3: Update site is provided for Chriss for testing purposes at http://powermock-osgi.googlecode.com/svn/updateSite/1.5.4.1

UPDATE: Project was auto migrated to github. Update site: https://raw.githubusercontent.com/liptga/powermock-osgi/master/update-site/1.5.6.0

Project site: https://github.com/liptga/powermock-osgi

Thanks Chriss for helping the investigation.