What steps will reproduce the problem? 1. Unzip Eclipse project (attachment) 2. Run MockitoTest as JUnit Test 3. Run MockitoTest as JUnit Plugin Test
What is the expected output? What do you see instead? When trying to mock an eclipse interface, an exception is thrown. Mocking Java classes or classes from the same plugin, (or an buddy plugin) works.
What version of the product are you using? On what operating system? mockito 1.3, Eclipse Target 3.3.1
Please provide any additional information below. Seems to be some class loading problems. jmock had these problems in some old version too. EasyMock works out of the box for eclipse plugins.
- mockito.zip 503.07KB
Comment #1
Posted on Apr 25, 2008 by Happy CatException when run as JUnit Test:
net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237) at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377) at net.sf.cglib.proxy.Enhancer.createClass(Enhancer.java:317) at org.mockito.internal.creation.MockFactory.createMock(MockFactory.java:29) at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:24) at org.mockito.Mockito.mock(Mockito.java:274) at MockitoTest.testMockito(MockitoTest.java:10) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at junit.framework.TestCase.runTest(TestCase.java:164) at junit.framework.TestCase.runBare(TestCase.java:130) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:120) at junit.framework.TestSuite.runTest(TestSuite.java:230) at junit.framework.TestSuite.run(TestSuite.java:225) at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:384) at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219) ... 24 more Caused by: java.lang.SecurityException: class "org.eclipse.core.databinding.observable.map.IMapChangeListener$$EnhancerByCGLIB$$e1a71500"'s signer information does not match signer information of other classes in the same package at java.lang.ClassLoader.checkCerts(ClassLoader.java:775) at java.lang.ClassLoader.preDefineClass(ClassLoader.java:487) at java.lang.ClassLoader.defineClass(ClassLoader.java:614) ... 30 more
Comment #2
Posted on Apr 25, 2008 by Happy CatException when run as Junit Plugin Test.
net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237) at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377) at net.sf.cglib.proxy.Enhancer.createClass(Enhancer.java:317) at org.mockito.internal.creation.MockFactory.createMock(MockFactory.java:29) at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:24) at org.mockito.Mockito.mock(Mockito.java:274) at MockitoTest.testMockito(MockitoTest.java:10) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at junit.framework.TestCase.runTest(TestCase.java:164) at junit.framework.TestCase.runBare(TestCase.java:130) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:120) at junit.framework.TestSuite.runTest(TestSuite.java:230) at junit.framework.TestSuite.run(TestSuite.java:225) at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) at org.eclipse.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:58) at org.eclipse.pde.internal.junit.runtime.CoreTestApplication.run(CoreTestApplication.java:24) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.eclipse.equinox.internal.app.EclipseAppContainer.callMethod(EclipseAppContainer.java:572) at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:171) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:106) at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:76) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:363) at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:176) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:508) at org.eclipse.equinox.launcher.Main.basicRun(Main.java:447) at org.eclipse.equinox.launcher.Main.run(Main.java:1173) at org.eclipse.equinox.launcher.Main.main(Main.java:1148) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:384) at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219) ... 43 more Caused by: java.lang.NoClassDefFoundError: net/sf/cglib/proxy/Factory at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:620) ... 49 more
Comment #3
Posted on Apr 25, 2008 by Massive MonkeyLooking at it...
Comment #4
Posted on Apr 25, 2008 by Massive MonkeyOk, I tried with the latest Eclipse distro (3.3.2) and I am able to reproduce the problem.
Comment #5
Posted on Apr 25, 2008 by Massive MonkeyProblem appears also in earlier versions of Mockito (tried with 1.2).
Comment #6
Posted on Apr 27, 2008 by Massive Monkey(No comment was entered for this change.)
Comment #7
Posted on Apr 27, 2008 by Massive MonkeyOk, I'm on this bug now (a bit hung-over after my last double night out in London but let's do it).
I tried both EasyMock and jmock. Only jmock works out of the box.
EasyMock works with your example only because you're mocking an interface (EM uses dynamic proxies for interfaces and cglib for classes, Mockito always uses cglib). But if you try to create easymock for a class from plugins (e.g: AbstractObservableMap), EM breaks the same way as mockito.
Comment #8
Posted on Apr 27, 2008 by Massive MonkeyFixed in trunk. Thanks a lot for detailed description and sample code!
Snapshot build to grab here: http://hudson.ramfelt.se/job/Mockito/lastSuccessfulBuild/artifact/trunk/target/mockito-all-snapshot.jar Other snapshot builds here: http://hudson.ramfelt.se/job/Mockito
We'll try to release it soon but it may be a week or two (I'm switching countries and also there is one feature half-done that should be finished).
Comment #9
Posted on Apr 29, 2008 by Happy CatHmm, I tried your snapshot release, but the error still is present. Tried with both JDK 5 and 6.
I debugged your code and the enhancer.setNamingPolicy(ALLOWS_MOCKING_CLASSES_IN_SIGNED_PACKAGES); call is correctly invoked.
When running the test as JUnit test I get the exception at Enhancer.registerCallbacks(mockClass, new Callback[] { filter });
When running the test as JUnit plugin test I get the exception at Class mockClass = enhancer.createClass();
Should I attach the exceptions?
BTW: I'm using the org.eclipse.core.databinding;bundle-version="1.0.1" reference in my plug-in.
Thanks, Ulli
Comment #10
Posted on Apr 29, 2008 by Massive MonkeyYes, please attach the stack trace.
Are you running exactly the same test as you did initially?
I'm double checking the fix...
Comment #11
Posted on Apr 29, 2008 by Massive MonkeyYou're right, the error still exists. In my environment the newer version of cglib was being picked up and that's why I thought the bug is fixed.
Looks like it was too optimistic to downgrade cglib from beta to latest stable. I'm gonna have to go back to using latest cglib beta. In future I will write kill the dependency to cglib and write the proxies straight with asm.
Comment #12
Posted on Apr 30, 2008 by Massive OxSwitching back to cglib beta will prevent us from releasing mockito-core to maven central repository as the latest beta has never been deployed there and we cannot release mockito-core with missing dependency. That's the Central upload policy.
Comment #13
Posted on May 3, 2008 by Massive MonkeyIn the short term, let's then prepare a downloadable with snapshot jar + cglib 2.2 beta. The download doesn't have to live on the main page but it should be there so that anyone who faces the problem mockito + eclipse plugins can solve it. This is something I can do on Monday because earlier I don't have much time. Ulli, you can wait for this download or if you are very keen on using mockito (and I hope you are :), then please grab mockito snapshot core jar and use it in your environment with cglib 2.2 beta jar (you can get this jar from cglib site or from zipped distribution of mockito with version < 1.3). Please mind other required jars(all in zipped distribution).
In the longer term I'm hoping to remove the dependency to cglib by implementing proxies by hand using ASM directly. C'mon, how hard can it be? :) This is something me or other contributor can do sometime later.
Comment #14
Posted on May 6, 2008 by Happy CatI've downloaded the snapshot and the beta version. No need to prepare a special release for me.
Comment #15
Posted on May 7, 2008 by Massive MonkeyOk then, I'm not going to prepare a special realease.
The current plan is to try using java.lang.instrument instead of cglib for creating proxies.
Comment #16
Posted on May 15, 2008 by Massive Monkeyjava.lang.instrument is no good because it requires java to run with agent. Going back to the idea of writing proxy code from scratch using ASM.
Comment #17
Posted on May 30, 2008 by Swift ElephantHi.
I run into the same problem. I've upgraded to mockito-all-snapshot.jar (2008.05.20).
Now I recognized another problem: Caused by: java.lang.SecurityException: class "org.osgi.framework.BundleContext$$FastClassByCGLIB$$f6f1d55f"'s signer information does not match signer information of other classes in the same package
May be it's trivial problem, but actually I can't resolve. Can you help me?
I've attached the full stack trace, a my test case class.
Cheers, Zsolt
- StackTrace.txt 3.96KB
Comment #18
Posted on May 30, 2008 by Massive MonkeyI will now produce a downloadable snapshot version with newer cglib so that this problem is solved in trunk.
Also, I nearly finished my own implementation of proxy (using bytecode generation from ASM). It's hard to commit to any dates but will try to release it in two weeks.
Comment #19
Posted on May 30, 2008 by Massive MonkeyComment deleted
Comment #20
Posted on May 30, 2008 by Massive Monkeyfixed in trunk: [http://hudson.ramfelt.se/job/Mockito/lastSuccessfulBuild/artifact/trunk/target/mockito-all-snapshot.jar mockito-all-snapshot.jar]
Started using a new version of cglib.
Comment #21
Posted on May 30, 2008 by Swift ElephantIt works. Thanks for your really immediate reaction!
Zsolt
Comment #22
Posted on Jun 6, 2008 by Happy CatShould this work for eclipse plug-in tests, too? I still get the exception if I run my tests as a plug-in test.
E.g. when calling in a Junit plug-in test
Object mock = Mockito.mock(ISelectionListener.class);
then the call toMock.getSigners() returns NULL (see code below). However, if I'm running as a JUnit test, then the same call returns the signers information and mockito works.
public T createMock(Class<T> toMock, final MethodInterceptorFilter filter) {
validateClass(toMock);
Enhancer enhancer = createEnhancer(toMock);
enhancer.setCallbackType(filter.getClass());
//This is required but I could not figure out the way to test it
//See issue #11
if (toMock.getSigners() != null) {
enhancer.setNamingPolicy(ALLOWS_MOCKING_CLASSES_IN_SIGNED_PACKAGES);
}
Class mockClass = enhancer.createClass();
Enhancer.registerCallbacks(mockClass, new Callback[] { filter });
Factory mock = createMock(mockClass);
filter.setMock(mock);
return (T) mock;
}
Comment #23
Posted on Jun 6, 2008 by Massive MonkeyWill look at it
Comment #24
Posted on Jun 10, 2008 by Massive MonkeyDon't know yet why it happens but I found jMock guys had similar problems. See here http://jira.codehaus.org/browse/JMOCK-127
I'm still looking at it but if you can please try Eclipse-BuddyPolicy / Eclipse-RegisterBuddy workaround (I don't know what it is... :)
Comment #25
Posted on Jun 10, 2008 by Happy CatI tried that already (the jmocks bugreport is also from me:-)
Typically a plug-in "sees" only its own classes and not the classes in other plug-ins. With Eclipse-RegisterBuddy I can increase the visibility of classes for the classloader of a plug-in. This works quite perfect for my own plugins but not for Eclipse plugins (which are read-only). So seems that an interface in an Eclipse plug-in is not visible for the classloader of the plug-in that has the tests in it (even though I have an dependecy).
See: http://www.eclipsezone.com/articles/eclipse-vms/
Ulli
Comment #26
Posted on Jun 12, 2008 by Massive MonkeyOk, thanks for info. The exception at the bottom is:
Caused by: java.lang.ClassNotFoundException: net.sf.cglib.proxy.Factory
I tried to play with buddies for various packages but no luck :(
Is this issue solved in JMock, then?
Comment #27
Posted on Jun 12, 2008 by Happy CatI think this is not solved. Since JMock uses proxies for interfaces this is no big problem in JMock (no cglib), so the bug was closed. Typically you need not to have mocks for Eclipse classes, you only mock interfaces.
Comment #28
Posted on Jun 17, 2008 by Massive MonkeyPossible solutions:
Make a special case for interfaces and use standard java mechanism for creating proxies. It would solve most problems (most plugin-related work in eclipse strongly uses interfaces).
Debug cglib+eclipse and find out why it doesn't work. I don't think it's related to mockito - it's rather a feature of combo cglib+eclipse.
Write own proxy implementation with ASM. I almost finished but stopped working once cglib 2.2 was released.
I prefer #2 but it will take some time. I don't think it will make it to the 1.4 which I want to release in a day or two.
Any help is much appreciated. Here are my observations about the problem:
The root exception is: java.lang.ClassNotFoundException: net.sf.cglib.proxy.Factory I tried to play with buddy settings using net.sf.cglib.proxy packages but no luck. The really interesting behavior is that net.sf.cglib.proxy.Factory IS loadable, because I can do this in the test (!?): net.sf.cglib.proxy.Factory.class.getName()
Comment #29
Posted on Jun 29, 2008 by Massive MonkeyDid #2
It's fixed in trunk.
Cglib takes the ClassLoader of the mocked class as default one if no ClassLoader provided. When running tests as separate Eclipse project, the default ClassLoader of mocked class was the Eclipse's one (which does not have access to classes from plugins, obviously). Fixed by setting ClassLoader on Enhancer.
Comment #30
Posted on Apr 19, 2009 by Massive Monkey(No comment was entered for this change.)
Status: Fixed
Labels:
Type-Defect
Priority-Medium
Milestone-Pre1.7