lishunli / powermock

Automatically exported from code.google.com/p/powermock
Apache License 2.0
0 stars 0 forks source link

TooManyFieldsFoundException when using PowerMock with IBM JRE #514

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1.  Create the following files:

StaticClass.java:

public class StaticClass
{
    public static String concat(final String str1, final String str2)
    {
        return str1 + " = " + str2;
    }
}

StaticTest.java:

@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticClass.class)
public class StaticTest
{
    @Test
    public void checkJunitClass()
    {
        PowerMockito.mockStatic(StaticClass.class);
        StaticClass.concat("four", "4");

        PowerMockito.verifyStatic(Mockito.never());
        StaticClass.concat("four", "4");
    }
}

2.  Run the test on a IBM WebSphere 7 JVM.

Expected output:

org.mockito.exceptions.verification.NeverWantedButInvoked: 
StaticClass.concat("four", "4");

Actual output:

org.powermock.reflect.exceptions.TooManyFieldsFoundException: Two or more 
fields matching type java.lang.String.

        at org.powermock.reflect.internal.WhiteboxImpl.findSingleFieldUsingStrategy(WhiteboxImpl.java:496)

        at org.powermock.reflect.internal.WhiteboxImpl.findFieldInHierarchy(WhiteboxImpl.java:455)

        at org.powermock.reflect.internal.WhiteboxImpl.setInternalState(WhiteboxImpl.java:327)

        at org.powermock.reflect.Whitebox.setInternalState(Whitebox.java:207)

        at org.powermock.api.mockito.internal.invocationcontrol.InvocationControlAssertionError.updateErrorMessageForMethodInvocation(InvocationControlAssertionError.java:75)

        at org.powermock.api.mockito.internal.invocationcontrol.MockitoMethodInvocationControl.performIntercept(MockitoMethodInvocationControl.java:300)

        at org.powermock.api.mockito.internal.invocationcontrol.MockitoMethodInvocationControl.invoke(MockitoMethodInvocationControl.java:194)

        at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:105)

        at org.powermock.core.MockGateway.methodCall(MockGateway.java:60)

        at StaticClass.getValue(StaticClass.java)

        at PowerMockTest.testStatic(PowerMockTest.java:56)

        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)

        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)

        at java.lang.reflect.Method.invoke(Method.java:600)

        at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)

        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:312)

        at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)

        at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)

        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:296)

        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:112)

        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:73)

        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:284)

        at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)

        at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)

        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:209)

        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:148)

        at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:122)

        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:120)

        at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:102)

        at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)

        at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:42)

        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)

        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.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

What version of the product are you using? On what operating system?

Platform is RSA 8 IDE, IBM WebSphere 7 JRE, Windows 7.
Product is Mockito 1.9.0, Powermock-Mockito 1.4.12, JUnit 4.10 (work 
environment is locked down and this is the latest version we have).

Please provide any additional information below.

Originally discussed here: 
https://groups.google.com/forum/#!topic/powermock/QgcAYl_Khr0

I can't personally test 1.5.5, but from looking at the PowerMock code, I think 
it has the same issue.

---

The version of java.lang.Throwable in the Sun/Oracle JRE has a field "private 
transient Object backtrace" which is similar to the "private transient Object 
walkback" field in the IBM JRE.  HOWEVER, this field is special-cased to not be 
exposed by reflection!

https://bugs.openjdk.java.net/browse/JDK-4763881

The IBM implementation apparently doesn't do this, and exposes that field via 
getDeclaredFields.  This confuses WhiteboxImpl.findSingleFieldUsingStrategy 
when the strategy is AssignableFromFieldTypeMatcherStrategy(String.class).

If you care to fix it, I think the simplest fix might be in WhiteboxImpl, to 
add a wrapper around getDeclaredFields.  If the class === 
java.lang.Throwable.class, then filter out any instance of a transient Object 
field from the results before returning them - or maybe specifically look for 
the IBM "backtrace" field.

I'd try to write a patch and test myself but, as I said, my work computer which 
has the IBM JRE on it is fairly locked down.

Original issue reported on code.google.com by mitchell...@gmail.com on 26 Aug 2014 at 5:25

GoogleCodeExporter commented 9 years ago
Hm, this is probably the same root cause as #444.

Also, sorry for the weird extra newlines in the "actual" above.

Original comment by mitchell...@gmail.com on 26 Aug 2014 at 2:38

GoogleCodeExporter commented 9 years ago

Original comment by johan.ha...@gmail.com on 28 Aug 2014 at 11:29