Permalink
Browse files

Fix #717: Regression: MethodNotFoundException (#741)

Signed-off-by: Arthur Zagretdinov <arthur.zagretdinov@outlook.com>
  • Loading branch information...
1 parent 540b92e commit ddda4681cddd0518a2d1863c0108afd96d4b3528 @thekingnothing thekingnothing committed on GitHub Jan 26, 2017
View
@@ -1,9 +1,10 @@
Change log 1.7.0
-----------------------------
-* Fix Issue #722 IllegalArgumentException is output to standard error (thanks to Kotaro Nanri @k-nanri for pull request)
-* #724 Optimizations in powermock-reflect (thanks to Roman Leventov @leventov for pull request)
-* #728 Migrate from Maven to Gradle
+* Optimizations in powermock-reflect (thanks to Roman Leventov @leventov for pull request) (#724)
+* Migrate from Maven to Gradle (#728)
* Support Mockito 2.4.0 for PowerMock 1.x (thanks to Gregor Stamac @gstamac for pull request)
+* Fix issue #722 IllegalArgumentException is output to standard error (thanks to Kotaro Nanri @k-nanri for pull request)
+* Fix issue #717 Regression: MethodNotFoundException
Change log 1.6.6 (2016-11-04)
-----------------------------
@@ -1,17 +1,10 @@
package org.powermock.reflect.internal.proxy;
+import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
-/**
- *
- */
public class ProxyFrameworks {
- /**
- * The CGLIB class separator character "$$"
- */
- public static final String CGLIB_CLASS_SEPARATOR = "$$";
-
public Class<?> getUnproxiedType(Class<?> type) {
if (type == null){
@@ -47,15 +40,19 @@ private boolean isJavaProxy(Class<?> clazz) {
* @param clazz the class to check
*/
public boolean isCglibProxyClass(Class<?> clazz) {
- return (clazz != null && isCglibProxyClassName(clazz.getName()));
+ if (clazz == null){
+ return false;
+ }
+ Method[] methods = clazz.getDeclaredMethods();
+ for(Method m: methods){
+ if(isCglibCallbackMethod(m)) {
+ return true;
+ }
+ }
+ return false;
}
-
- /**
- * Check whether the specified class name is a CGLIB-generated class.
- *
- * @param className the class name to check
- */
- public boolean isCglibProxyClassName(String className) {
- return (className != null && className.contains(CGLIB_CLASS_SEPARATOR));
+
+ private boolean isCglibCallbackMethod(Method m) {
+ return "CGLIB$SET_THREAD_CALLBACKS".equals(m.getName()) && m.getParameterTypes().length == 1;
}
}
@@ -1,12 +1,18 @@
package org.powermock.reflect.internal.proxy;
+import net.sf.cglib.asm.AnnotationVisitor;
+import net.sf.cglib.asm.ClassWriter;
+import net.sf.cglib.asm.FieldVisitor;
+import net.sf.cglib.asm.MethodVisitor;
+import net.sf.cglib.asm.Opcodes;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import java.net.URLClassLoader;
import static org.assertj.core.api.Assertions.assertThat;
@@ -57,4 +63,82 @@ public Object invoke(Object o, Method method, Object[] objects) throws Throwable
});
assertThat(proxyFrameworks.getUnproxiedType(someClass)).isEqualTo(SomeClass.class);
}
+
+ @Test
+ public void should_not_detect_synthetic_classes_as_cglib_proxy() throws Exception {
+ String className = "Some$$SyntheticClass$$Lambda";
+ byte[] bytes = ClassFactory.create(className);
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ CustomClassLoader customClassLoader = new CustomClassLoader(classLoader);
+
+ Class<?> defineClass = customClassLoader.defineClass(className, bytes);
+
+ assertThat(proxyFrameworks.getUnproxiedType(defineClass.newInstance())).isEqualTo(defineClass);
+ }
+
+ private static class CustomClassLoader extends URLClassLoader{
+
+ public CustomClassLoader(ClassLoader parent) {
+ super(((URLClassLoader)parent).getURLs(), parent);
+ }
+
+ public Class<?> defineClass(String name, byte[] b) {
+ return defineClass(name, b, 0, b.length);
+ }
+ }
+
+ private static class ClassFactory implements Opcodes {
+
+ private static byte[] create(String className) throws Exception {
+
+ ClassWriter cw = new ClassWriter(0);
+ FieldVisitor fv;
+ MethodVisitor mv;
+ AnnotationVisitor av0;
+
+ cw.visit(49,
+ ACC_PUBLIC + ACC_SUPER,
+ className,
+ null,
+ "java/lang/Object",
+ null);
+
+ cw.visitSource("Hello.java", null);
+
+ {
+ mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL,
+ "java/lang/Object",
+ "<init>",
+ "()V");
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+ {
+ mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
+ "main",
+ "([Ljava/lang/String;)V",
+ null,
+ null);
+ mv.visitFieldInsn(GETSTATIC,
+ "java/lang/System",
+ "out",
+ "Ljava/io/PrintStream;");
+ mv.visitLdcInsn("hello");
+ mv.visitMethodInsn(INVOKEVIRTUAL,
+ "java/io/PrintStream",
+ "println",
+ "(Ljava/lang/String;)V");
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(2, 1);
+ mv.visitEnd();
+ }
+ cw.visitEnd();
+
+ return cw.toByteArray();
+ }
+ }
+
}
View
@@ -42,6 +42,7 @@ include("tests:mockito:testng")
include("tests:java8:mockito-junit4")
include("tests:java8:mockito-junit4-agent")
include("tests:java8:mockito-junit4-rule-xstream")
+include("tests:java8:easymock-junit4")
include("powermock-release:powermock-easymock")
include("powermock-release:powermock-mockito")
include("powermock-release:powermock-mockito2")
@@ -1,26 +1,20 @@
List mockito1Libs = [
- project(":powermock-api:powermock-api-mockito"),"org.mockito:mockito-core:${mockito1Version}"
+ project(":powermock-api:powermock-api-mockito"), "org.mockito:mockito-core:${mockito1Version}"
]
List mockito2Lbs = [
- project(":powermock-api:powermock-api-mockito2"),"org.mockito:mockito-core:${mockito2Version}"
+ project(":powermock-api:powermock-api-mockito2"), "org.mockito:mockito-core:${mockito2Version}"
]
-configure(project.subprojects){ subproject ->
+configure(project.subprojects) { subproject ->
dependencies {
- testCompile("junit:junit:${junitVersion}"){
- exclude group:'org.hamcrest', module:'hamcrest-core'
+ testCompile("junit:junit:${junitVersion}") {
+ exclude group: 'org.hamcrest', module: 'hamcrest-core'
}
testCompile("org.hamcrest:hamcrest-core:${hamcrestVersion}")
testCompile("org.assertj:assertj-core:${assertjVersion}")
- testCompile mockito1Libs
- testCompile project(path:":powermock-api:powermock-api-mockito-common")
-
- mockito2 mockito2Lbs
- mockito2 project(path:":powermock-api:powermock-api-mockito-common", configuration: "mockito2")
-
testCompile files(project(":tests:mockito:junit4").sourceSets.test.output)
}
@@ -34,12 +28,12 @@ configure(project.subprojects){ subproject ->
targetCompatibility = 1.8
}
- compileMainMockito2Java{
+ compileMainMockito2Java {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
- compileTestMockito2Java{
+ compileTestMockito2Java {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
@@ -52,13 +46,37 @@ project(":tests:java8:mockito-junit4") {
dependencies {
testCompile project(":powermock-modules:powermock-module-junit4")
+
+ testCompile mockito1Libs
+ testCompile project(path: ":powermock-api:powermock-api-mockito-common")
+
+ mockito2 mockito2Lbs
+ mockito2 project(path: ":powermock-api:powermock-api-mockito-common", configuration: "mockito2")
+ }
+}
+
+project(":tests:java8:easymock-junit4") {
+ description = "Tests for Easymock module with JUnit 4.x. and Java8."
+
+ dependencies {
+ testCompile project(":powermock-api:powermock-api-easymock")
+ testCompile project(":powermock-modules:powermock-module-junit4")
+ testCompile("org.easymock:easymock:${easymockVersion}")
+ testCompile("org.assertj:assertj-core:${assertjVersion}")
+ testCompile("org.hamcrest:hamcrest-core:${hamcrestVersion}")
}
}
project(":tests:java8:mockito-junit4-agent") {
description = "Tests for Mockito module with JUnit 4.x. and Java8."
dependencies {
+ testCompile mockito1Libs
+ testCompile project(path: ":powermock-api:powermock-api-mockito-common")
+
+ mockito2 mockito2Lbs
+ mockito2 project(path: ":powermock-api:powermock-api-mockito-common", configuration: "mockito2")
+
testCompile project(":powermock-modules:powermock-module-junit4-rule-agent")
}
@@ -80,6 +98,12 @@ project(":tests:java8:mockito-junit4-rule-xstream") {
testCompile project(":powermock-modules:powermock-module-junit4-rule")
testCompile project(":powermock-classloading:powermock-classloading-xstream")
+ testCompile mockito1Libs
+ testCompile project(path: ":powermock-api:powermock-api-mockito-common")
+
+ mockito2 mockito2Lbs
+ mockito2 project(path: ":powermock-api:powermock-api-mockito-common", configuration: "mockito2")
+
testCompile files(project(":tests:mockito:junit4").sourceSets.test.output)
}
}
@@ -0,0 +1,4 @@
+package samples.powermockito.junit4.bugs.github717;
+
+public class Instance {
+}
@@ -0,0 +1,4 @@
+package samples.powermockito.junit4.bugs.github717;
+
+public interface InstanceFacade {
+}
@@ -0,0 +1,17 @@
+package samples.powermockito.junit4.bugs.github717;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+
+public class InstanceFacadeImpl implements InstanceFacade {
+
+ final Map<InstanceStatus, Consumer<Instance>> instanceStatusProcessors = new HashMap<>();
+
+ {
+ instanceStatusProcessors.put(InstanceStatus.PENDING, instance -> {
+ // NOP
+ });
+ }
+
+}
@@ -0,0 +1,5 @@
+package samples.powermockito.junit4.bugs.github717;
+
+public enum InstanceStatus {
+ PENDING
+}
@@ -0,0 +1,33 @@
+package samples.powermockito.junit4.bugs.github717;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.extension.listener.AnnotationEnabler;
+import org.powermock.core.classloader.annotations.PowerMockListener;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import static org.powermock.api.easymock.PowerMock.replayAll;
+import static org.powermock.api.easymock.PowerMock.verifyAll;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockListener(AnnotationEnabler.class)
+@PrepareForTest(InstanceFacadeImpl.class)
+public class InstanceFacadeImplTest {
+
+ private InstanceFacadeImpl instanceFacade;
+
+ @Before
+ public void setup() throws Exception {
+ instanceFacade = new InstanceFacadeImpl();
+ }
+
+ @Test
+ public void should_not_throw_exception() throws Exception {
+ replayAll();
+ instanceFacade.instanceStatusProcessors.get(InstanceStatus.PENDING).accept(null);
+ verifyAll();
+ }
+
+}
@@ -0,0 +1,17 @@
+/**
+ * Regression: MethodNotFoundException
+ * https://github.com/powermock/powermock/issues/717
+ *
+ * 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(InstanceFacadeI
+ *
+ */
+package samples.powermockito.junit4.bugs.github717;

0 comments on commit ddda468

Please sign in to comment.