Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression: MethodNotFoundException #717

Closed
andrei-ivanov opened this issue Nov 9, 2016 · 14 comments
Closed

Regression: MethodNotFoundException #717

andrei-ivanov opened this issue Nov 9, 2016 · 14 comments

Comments

@andrei-ivanov
Copy link

andrei-ivanov commented Nov 9, 2016

Trying to upgrade from 1.6.4 to 1.6.6, I ran into this error:

org.powermock.reflect.exceptions.MethodNotFoundException: No methods matching the name(s) accept were found in the class hierarchy of class java.lang.Object.
	at org.powermock.reflect.internal.WhiteboxImpl.getMethods(WhiteboxImpl.java:1720)
	at org.powermock.reflect.internal.WhiteboxImpl.getMethods(WhiteboxImpl.java:1745)
	at org.powermock.reflect.internal.WhiteboxImpl.getBestMethodCandidate(WhiteboxImpl.java:983)
	at org.powermock.core.MockGateway$MockInvocation.findMethodToInvoke(MockGateway.java:317)
	at org.powermock.core.MockGateway$MockInvocation.init(MockGateway.java:356)
	at org.powermock.core.MockGateway$MockInvocation.<init>(MockGateway.java:307)
	at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:142)
	at org.powermock.core.MockGateway.methodCall(MockGateway.java:125)
	at InstanceFacadeImplTest.pendingInstanceStatusProcessorShouldDoNothing(InstanceFacadeImplTest.java:91)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:316)
	at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
	at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:300)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:288)
	at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
	at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:208)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:147)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:121)
	at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
	at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:123)
	at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
	at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
	at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
public enum InstanceStatus {
	PENDING;
}
import java.util.function.Consumer;

public class InstanceFacadeImpl implements InstanceFacade {
	final Map<InstanceStatus, Consumer<Instance>> instanceStatusProcessors = new HashMap<>();

	{
		instanceStatusProcessors.put(InstanceStatus.PENDING, instance -> {
			// NOP
		});
	}
}
@RunWith(PowerMockRunner.class)
@PowerMockListener(AnnotationEnabler.class)
@PowerMockIgnore({ "javax.management.*" })
public class InstanceFacadeImplTest {

	private InstanceFacadeImpl instanceFacade;

	@Before
	public void setup() throws Exception {
		instanceFacade = new InstanceFacadeImpl();
	}

	@Test
	public void pendingInstanceStatusProcessorShouldDoNothing() throws Exception {
		replayAll();
		instanceFacade.instanceStatusProcessors.get(InstanceStatus.PENDING).accept(null);
		verifyAll();
	}
}
@andrei-ivanov
Copy link
Author

andrei-ivanov commented Nov 9, 2016

As far as I see, it reaches org.powermock.reflect.internal.proxy.ProxyFrameworks.isCglibProxyClass(Class<?> clazz), which mistakes the lambda as a cglib proxy...

instance = InstanceFacadeImpl$$Lambda$1/1881218633@87b5b49
methodName = accept

This is from org.powermock.reflect.internal.proxy.ProxyFrameworks.getUnproxiedType(Class<?> type)
After that, the type becomes java.lang.Object, where it doesn't find the method.

@thekingn0thing
Copy link
Member

Thank you for investigation! You're welcome to provide a pull request with fix :)

@andrei-ivanov
Copy link
Author

Hmm, I'm not sure how the fix should look.
As far as I see on StackOverflow, there's no proper way to identify a lambda.
Looking for $$Lambda is not guaranteed to be portable or to be the same in the future versions.

I did however found an answer on how to properly identify cglib proxies.
It's actually done that way in another place in PowerMock: org.powermock.api.easymock.PowerMock.isEasyMocked(Object mock):

import net.sf.cglib.proxy.Enhancer;

private static boolean isEasyMocked(Object mock) {
    return Enhancer.isEnhanced(mock.getClass()) || Proxy.isProxyClass(mock.getClass());
}

This would mean that powermock-reflect would have a compile dependency on cglib-nodep, not just test, like it is now.

@thekingn0thing
Copy link
Member

Unfortunately, we cannot introduce a new dependencies to powermock-reflect, because all other modules depends on it, and soon mockito module will not depend on cglib (Mockito 2 uses ByteBuddy instead CgLib).

I snooped the approach with CGLIB_CLASS_SEPARATOR from Spring.

Now, I think the right way will be to implement the same approach as in Enhancer.isEnhanced

    public boolean isCglibProxyClass(Class<?> clazz) {
        Method[] methods = class.getDeclaredMethod();
        for(Method m: method){
            if( "CGLIB$SET_THREAD_CALLBACKS".equals(m.getName() && m.getParameterTypes().lenght = 1)
                 return true;
        }
        return false;
    }

@andrei-ivanov
Copy link
Author

Indeed, as I've already tried the Enhancer.isEnhanced approach and it fails for Mockito CgLib generated classes, as they've modified the parameters of CGLIB$SET_THREAD_CALLBACKS.

@andrei-ivanov
Copy link
Author

I wonder how should I handle the unit test, as the project level is set to 1.6, which doesn't allow lambdas.

@thekingn0thing
Copy link
Member

You can handle the test as it did in mockito case. Just create a new module junit4-java8-test and set language level to 1.8.

Thank you a lot for your help!

@andrei-ivanov
Copy link
Author

Hmm, junit4-java8-test and not reflection-java8-test?

@thekingn0thing
Copy link
Member

It's a really good question. I meant create a module a put in it a test for your case. Case: using EasyMock + PowerMock with class with lambda (and maybe create a same case for Mockito).

But, you're right. ProxyFrameworks also has to be tested, that it correctly works with lambda classes. However, we can extends case and say that the ProxyFrameworks has to work correctly with any runtime generated class. It should returns true if argument is a proxy class of known frameworks and false otherwise.

@eBraund
Copy link

eBraund commented Nov 23, 2016

I have this exception too, in 2 places in my code. The tests did work previously with mockito 1.6.5 but started to fail when I switched to 1.6.6.

The first occurrence was when mocking a Map. I got around the problem by using a real map and just filling it with mock objects.

The second occurrence was when calling next() on a mock of java.sql.ResultSet. I've spent all afternoon trying to solve it but have now given up and switched back to 1.6.5 (which is a shame as going to 1.6.6 fixed some issues I was experiencing using EclEmma with Eclipse to get code coverage).

I wonder if it is anything to do with Map and ResultSet both being interfaces?

NB - I'm using mockito 1.10.19 and junit 4.10

@Aaron1011
Copy link

Aaron1011 commented Dec 19, 2016

@andrei-ivanov Are you still working on this? If not, I'd be willing to work on a fix.

thekingn0thing pushed a commit that referenced this issue Jan 26, 2017
Signed-off-by: Arthur Zagretdinov <arthur.zagretdinov@outlook.com>
thekingn0thing added a commit that referenced this issue Jan 26, 2017
Signed-off-by: Arthur Zagretdinov <arthur.zagretdinov@outlook.com>
@rushikeshr
Copy link

I have encountered the similar error.
I am unable to execute my junit testcases with PowerMockito 1.6.6 jars. I Get below error on executing any testcase after using PowerMockito 1.6.6 jars But when I use powerockito 1.6.2 my tastecase executes successfully.
org.powermock.reflect.exceptions.MethodNotFoundException: No methods matching the name(s) createStatement were found in the class hierarchy of class java.lang.Object. at

BUT I NEED TO USE POWERMOCKITO 1.6.6 AND ABOVE VERSION FOR COMPATIBLITY WITH OTHER TOOLS IN THE PROJECT. Is this issue fixed in POWERMOCKITO 1.6.7 ?

@thekingn0thing
Copy link
Member

@rushikeshr the issue is fixed in PowerMock 1.7.0 (Release notes). In Maven Central available PowerMock 1.7.0RC2 with this fix.

@richardkuiper
Copy link

Tested 1.7.0RC2 and it is fixed. This issue gave me headaches.

jgrandja added a commit to jgrandja/spring-security that referenced this issue Mar 9, 2017
* Spring IO  Athens-BUILD-SNAPSHOT -> Cairo-BUILD-SNAPSHOT
* CGLib  3.1 -> 3.2.5 latest release  Issue related to ASM cglib/cglib#20
* AssertJ  2.2.0 -> 3.6.2 latest release
* PowerMock  1.6.2 -> 1.6.5  latest release is 1.6.6 but has regression Issue powermock/powermock#717
jgrandja added a commit to jgrandja/spring-security that referenced this issue Apr 7, 2017
* Spring IO Athens-BUILD-SNAPSHOT -> Cairo-BUILD-SNAPSHOT
* CGLib 3.1 -> 3.2.5 latest release Issue related to ASM cglib/cglib#20
* AssertJ 2.2.0 -> 3.6.2 latest release
* PowerMock 1.6.2 -> 1.6.5 latest release is 1.6.6 but has regression Issue powermock/powermock#717
* Update maven-compiler-plugin source/target to 1.8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants