Skip to content

Keep WithFormRead request filter order when moving them after the body handler - #56360

Merged
geoand merged 2 commits into
quarkusio:mainfrom
HuzaifaChaudary:fix/withformread-filter-priority-order
Sep 21, 2026
Merged

geoand merged 2 commits into
quarkusio:mainfrom
HuzaifaChaudary:fix/withformread-filter-priority-order

Conversation

@HuzaifaChaudary

@HuzaifaChaudary HuzaifaChaudary commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

RuntimeResourceDeployment moves @WithFormRead request filters to the end of the handler list once the body handler is in place. It walks the list backwards, because it removes by index as it goes, but it then appended the collected filters in that same backwards order, so the filters ended up reversed and priorities were applied in reverse.

The fix inserts each match at the front of the collected list instead, which keeps the order the handlers were already in. That is what the comment on the block already said should happen.

Added a test with three @WithFormRead filters at USER + 100, USER + 200 and USER + 300 that each append their name to a header, in the style of the existing ReadBodyRequestFilterTest. With the fix it gets first/second/third; without it the same test gets third/second/first.

ReadBodyRequestFilterTest, ImpliedReadBodyRequestFilterTest, WithFormBodyTest and AnotherValidNonBlockingFiltersTest still pass, 13 tests in total.

Copilot AI lite review requested due to automatic review settings September 1, 2026 18:45
@quarkus-bot quarkus-bot Bot added the area/rest label Sep 1, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes an ordering bug in RESTEasy Reactive runtime handler assembly where @WithFormRead request filters were moved after the body handler but ended up reversed due to backward iteration and append order.

Changes:

  • Preserve the original relative order of @WithFormRead request filters when relocating them after body handling.
  • Add a regression test that verifies multiple @WithFormRead filters execute according to their priority values.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/startup/RuntimeResourceDeployment.java Adjusts filter relocation logic to keep @WithFormRead filters in the same order they had before being moved.
extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/customproviders/WithFormReadFilterPriorityTest.java Adds a regression test ensuring @WithFormRead filters run in increasing priority order.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +305 to +309
for (int i = handlers.size() - 2; i >= 0; i--) {
var serverRestHandler = handlers.get(i);
if (serverRestHandler instanceof ResourceRequestFilterHandler resourceRequestFilterHandler) {
if (resourceRequestFilterHandler.isWithFormRead()) {
readBodyRequestFilters.add(handlers.remove(i));
readBodyRequestFilters.add(0, handlers.remove(i));
@HuzaifaChaudary

Copy link
Copy Markdown
Contributor Author

Taken, ea21c976 collects with a plain append and calls Collections.reverse once before appending.

For the record on the cost, the list only ever holds the @WithFormRead filters for a single resource method, and it is constructed as new ArrayList<>(1) because that is normally one or two entries, so the shifting was not going to show up in a startup profile. The reverse-once version reads better though, and it makes the reason for the backwards walk obvious at the point where it is undone, so it is the better shape either way.

Same verification as before, on ea21c976:

WithFormReadFilterPriorityTest        1 test, 0 failures
ReadBodyRequestFilterTest             4
ImpliedReadBodyRequestFilterTest      4
WithFormBodyTest                      2
AnotherValidNonBlockingFiltersTest    2
                                     13 tests, 0 failures

and with the Collections.reverse line removed and nothing else changed, the new test fails the same way it did against the original code:

Expected: "hello Quarkus first/second/third"
  Actual: hello Quarkus third/second/first

@cescoffier
cescoffier requested a review from geoand September 21, 2026 05:43
…y handler

The filters are collected while walking the handler list backwards, because
they are removed by index as we go, but the collected list was then appended
as it was. That reversed them, so priorities were applied in reverse order.

Insert each match at the front instead, which is what the existing comment
already says should happen.
…ront

Addresses review feedback: add(0, ..) on an ArrayList shifts elements on
every insert. Collect with a plain append and flip the list once before
appending it back.
@geoand
geoand force-pushed the fix/withformread-filter-priority-order branch from ea21c97 to d052944 Compare September 21, 2026 05:52
@quarkus-bot

quarkus-bot Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Status for workflow Quarkus CI

This is the status report for running Quarkus CI on commit d052944.

✅ The latest workflow run for the pull request has completed successfully.

It should be safe to merge provided you have a look at the other checks in the summary.

You can consult the Develocity build scans.


Flaky tests - Develocity

⚙️ JVM Tests - JDK 21

📦 extensions/opentelemetry/deployment

❌ io.quarkus.opentelemetry.deployment.traces.OpenTelemetrySamplerBeanTest. - History

  • java.lang.ExceptionInInitializerError
Details
java.lang.ExceptionInInitializerError
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:536)
	at java.base/java.lang.Class.forName(Class.java:515)
	at io.quarkus.runner.bootstrap.StartupActionImpl.run(StartupActionImpl.java:395)
	at io.quarkus.test.AbstractQuarkusExtensionTest.beforeAll(AbstractQuarkusExtensionTest.java:737)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: java.lang.RuntimeException: Failed to start quarkus

⚙️ Maven Tests - JDK 25 Semeru

📦 integration-tests/maven

❌ io.quarkus.maven.it.DevMojoIT.testThatInstrumentationBasedReloadWorks - History

  • Condition with Lambda expression in io.quarkus.test.devmode.util.DevModeClient was not fulfilled within 3 minutes. - org.awaitility.core.ConditionTimeoutException
Details
org.awaitility.core.ConditionTimeoutException: Condition with Lambda expression in io.quarkus.test.devmode.util.DevModeClient was not fulfilled within 3 minutes.
	at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:26)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1160)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1129)
	at io.quarkus.test.devmode.util.DevModeClient.getHttpResponse(DevModeClient.java:97)
	at io.quarkus.test.devmode.util.DevModeClient.getHttpResponse(DevModeClient.java:88)

❌ io.quarkus.maven.it.DevMojoIT.testThatInstrumentationBasedReloadWorks - History

  • Condition with Lambda expression in io.quarkus.test.devmode.util.DevModeClient was not fulfilled within 3 minutes. - org.awaitility.core.ConditionTimeoutException
Details
org.awaitility.core.ConditionTimeoutException: Condition with Lambda expression in io.quarkus.test.devmode.util.DevModeClient was not fulfilled within 3 minutes.
	at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:26)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1160)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1129)
	at io.quarkus.test.devmode.util.DevModeClient.getHttpResponse(DevModeClient.java:97)
	at io.quarkus.test.devmode.util.DevModeClient.getHttpResponse(DevModeClient.java:88)

⚙️ JVM Integration Tests - JDK 25

📦 integration-tests/aesh

❌ io.quarkus.it.aesh.AeshLauncherApiTest.resetOutputClearsAccumulator(AeshLauncher) - History

  • Command 'hello --name=After' did not complete within PT30S - java.lang.RuntimeException
Details
java.lang.RuntimeException: Command 'hello --name=After' did not complete within PT30S
	at io.quarkus.test.aesh.AeshLauncherImpl.execute(AeshLauncherImpl.java:122)
	at io.quarkus.test.aesh.AeshLauncher.execute(AeshLauncher.java:50)
	at io.quarkus.it.aesh.AeshLauncherApiTest.resetOutputClearsAccumulator(AeshLauncherApiTest.java:137)
  • REPL did not start within PT30S - java.lang.RuntimeException
Details
java.lang.RuntimeException: REPL did not start within PT30S
	at io.quarkus.test.aesh.AeshLauncherImpl.launch(AeshLauncherImpl.java:85)
	at io.quarkus.test.aesh.AeshLauncherImpl.execute(AeshLauncherImpl.java:95)
	at io.quarkus.test.aesh.AeshLauncher.execute(AeshLauncher.java:50)
	at io.quarkus.it.aesh.AeshLauncherApiTest.resetOutputClearsAccumulator(AeshLauncherApiTest.java:131)

❌ io.quarkus.it.aesh.AeshReplTest.testMultipleCommandsInSession(AeshLauncher) - History

  • Command 'hello --name=Second' did not complete within PT30S - java.lang.RuntimeException
Details
java.lang.RuntimeException: Command 'hello --name=Second' did not complete within PT30S
	at io.quarkus.test.aesh.AeshLauncherImpl.execute(AeshLauncherImpl.java:122)
	at io.quarkus.test.aesh.AeshLauncher.execute(AeshLauncher.java:50)
	at io.quarkus.it.aesh.AeshReplTest.testMultipleCommandsInSession(AeshReplTest.java:36)
  • REPL did not start within PT30S - java.lang.RuntimeException
Details
java.lang.RuntimeException: REPL did not start within PT30S
	at io.quarkus.test.aesh.AeshLauncherImpl.launch(AeshLauncherImpl.java:85)
	at io.quarkus.test.aesh.AeshLauncherImpl.execute(AeshLauncherImpl.java:95)
	at io.quarkus.test.aesh.AeshLauncher.execute(AeshLauncher.java:50)
	at io.quarkus.it.aesh.AeshReplTest.testMultipleCommandsInSession(AeshReplTest.java:35)

@geoand
geoand merged commit 7e181ce into quarkusio:main Sep 21, 2026
66 checks passed
@quarkus-bot quarkus-bot Bot added this to the 4.0 - main milestone Sep 21, 2026

This branch was previously deployed

1 inactive deployment
ci — d052944c Deployed Sep 21, 2026 by geoand via Wait for approval if Dependabot #70237
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reverse filter proprities when using readBody/withFormRead

3 participants