After upgrading to Spring 6.2.0 (spring boot 3.4.0) my tests with io.rest-assured mock mvc started to be flaky.
I discovered that the issue might be connected to ReflectionUtils
.
In RestAssuredMockMvc
there is call to
https://github.com/spring-projects/spring-framework/blob/main/spring-test/src/main/java/org/springframework/test/web/servlet/request/MockHttpServletRequestBuilder.java through ReflectionUtils
.
When
public static Method findMethod(Class<?> clazz, String name, @Nullable Class<?>... paramTypes)
is called, then method returns.
Sometimes, method.isVarArgs
returns true
, sometimes false
(when method.isBridge()
is true
).
Here's some test example to show the behavior:
@Test
void testMethod() {
var method = ReflectionUtils.findMethod(MockHttpServletRequestBuilder.class, "cookie", Cookie[].class);
System.out.println("IsBridge: " + method.isBridge());
System.out.println("IsVarArgs: " + method.isVarArgs());
assertTrue(method.isVarArgs());
}
```
If you run the test multiple times, it will fail, but not always. In previous spring version `method.isVarArgs` always returned `true`. (At least I think so, it would explain why tests never failed before)
**Comment From: facewise**
Hi. Can I pick up this issue? Filtering out bridge methods can be the way to provide consistent result of `findMethod`.
**Comment From: simonbasle**
@welovelain I see that you have opened an issue in `rest-assured`. I think this is a better avenue to explore, perhaps evolving the code there to use `BridgeMethodResolver.findBridgedMethod(method)`?
Unless you've investigated further and found an issue in `ReflectionUtils`?
@facewise thanks for the offer, but filtering out bridge methods in `findMethod` is a no-go as it is supposed to include such methods.
**Comment From: welovelain**
@simonbasle Yes, I created it there also, but it looks like the behavior still was changed, it might affect other libs too.
Because earlier it worked, tests and restassured, I mean.
If the behavior was changed and you think that it must have been changed, then ok. But to me it looks like a bug, when such method returns undetermined results, and it seems that it always returned determined results before 6.2.0
**Comment From: sbrannen**
Hi @welovelain,
> If you run the test multiple times, it will fail, but not always. In previous spring version method.isVarArgs always returned true. (At least I think so, it would explain why tests never failed before)
I cannot reproduce the failure you've described.
Although `method.isBridge()` sometimes returns `false` and sometimes returns `true`, `method.isVarArgs()` always returns `true` for me with Spring Framework `6.2.x` on JDK 17, JDK 21, and JDK 22 when using the Eclipse compiler.
What version of the JDK are you using?
And how are you running your test? From a Gradle or Maven build? Within an IDE (and if so, which one)?
If you would like us to investigate this further, we will need a minimal sample that reproduces the issue in the form of something that we can download and run (for example, a public Git repository or a ZIP file).
**Comment From: sbrannen**
@welovelain, can you confirm whether the following modified version of your test case consistently passes for you?
```java
@Test
void testMethod() {
Method method = ReflectionUtils.findMethod(MockHttpServletRequestBuilder.class, "cookie", Cookie[].class);
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
assertTrue(bridgedMethod.isVarArgs());
}
Comment From: welovelain
I checked it, using gradle 8.11.1, on Eclipse Temurin Adopt Open JDK for HotSpot 17.03 and Amazon Coretto 17.0.3, their results come true/false. JetBrains runtime consistently returns false for initial test.
Provided BridgeMethodResolver test consistently works ok.
I can see you wrote in Rest Assured issue as well. It seems that them changing the code will be the most correct way to address it. I still wonder why it worked previously.
What for me, I will migrate tests using MockMvcTester, it doesn't have such issues.
If you still think there is need for some example, please let me know, I think I could prepare some example with dockerfile, but it looks like you have already figured out the compiler differences.
Comment From: sbrannen
I checked it, using gradle 8.11, on Eclipse Temurin Adopt Open JDK for HotSpot 17.03 and Amazon Coretto 17.0.3, their results come true/false. JetBrains runtime consistently returns false for initial test.
Provided BridgeMethodResolver test consistently works ok.
Thanks for testing all of that, @welovelain. 👍
I still wonder why it worked previously.
@simonbasle researched this and noticed that the bridge method was introduced due to the introduction of AbstractMockHttpServletRequestBuilder
in 6.2:
https://github.com/spring-projects/spring-framework/blob/5024bb72279188f1d0dcfe19e8abdd4bdb9887c8/spring-test/src/main/java/org/springframework/test/web/servlet/request/AbstractMockHttpServletRequestBuilder.java#L451
Thus, prior to 6.2, there was only one declared cookie(Cookie...)
method in MockHttpServletRequestBuilder
, and now there are two: the actual method and the bridge method.
If you still think there is need for some example, please let me know, I think I could prepare some example with dockerfile, but it looks like you have already figured out the compiler differences.
Thanks for the offer, but you're right: I don't think we need a "reproducer" anymore.
I can see you wrote in Rest Assured issue as well. It seems that them changing the code will be the most correct way to address it.
Indeed, in light of that I am closing this issue.
Cheers,
Sam