From 0929a4b1890b5fd674a53b6acae7465bf7230c87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Dec 2024 05:16:32 +0000 Subject: [PATCH 001/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 5.47.0 to 5.47.1 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 5.47.0 to 5.47.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v5.47.0...v5.47.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e939b7dd54..4908526626 100644 --- a/pom.xml +++ b/pom.xml @@ -991,7 +991,7 @@ org.openrewrite.maven rewrite-maven-plugin - 5.47.0 + 5.47.1 From 0a6f1ef428583b01734b661e25fa6f9e6895ac27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Dec 2024 05:32:35 +0000 Subject: [PATCH 002/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 5.47.1 to 5.47.2 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 5.47.1 to 5.47.2. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v5.47.1...v5.47.2) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4908526626..2cfac15cf5 100644 --- a/pom.xml +++ b/pom.xml @@ -991,7 +991,7 @@ org.openrewrite.maven rewrite-maven-plugin - 5.47.1 + 5.47.2 From 6a16e045e64e7d9f93102ca6675a83b488b179e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jan 2025 06:00:20 +0000 Subject: [PATCH 003/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 5.47.2 to 5.47.3 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 5.47.2 to 5.47.3. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v5.47.2...v5.47.3) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2cfac15cf5..f4467f1ef8 100644 --- a/pom.xml +++ b/pom.xml @@ -991,7 +991,7 @@ org.openrewrite.maven rewrite-maven-plugin - 5.47.2 + 5.47.3 From c4920c81172970e542fa06fa6ae02c1ba824dd45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 05:56:52 +0000 Subject: [PATCH 004/615] Bump org.assertj:assertj-core from 3.27.0 to 3.27.1 Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.27.0 to 3.27.1. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.0...assertj-build-3.27.1) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f4467f1ef8..07c089c791 100644 --- a/pom.xml +++ b/pom.xml @@ -179,7 +179,7 @@ 5.11.4 2.18.2 - 3.27.0 + 3.27.1 5.14.2 2.0.53 From 46fe7ee95a07da019aef0d8baf1081051c39d318 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 06:05:59 +0000 Subject: [PATCH 005/615] Bump org.json:json from 20240303 to 20241224 Bumps [org.json:json](https://github.com/douglascrockford/JSON-java) from 20240303 to 20241224. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/commits) --- updated-dependencies: - dependency-name: org.json:json dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 07c089c791..524ca20f81 100644 --- a/pom.xml +++ b/pom.xml @@ -174,7 +174,7 @@ 2.11.0 1.15.2 2.0.16 - 20240303 + 20241224 3.3.5 5.11.4 From 131e42129dac818749d7f61d2df018e0aa5bbc74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 05:31:10 +0000 Subject: [PATCH 006/615] Bump mockito.version from 5.14.2 to 5.15.2 Bumps `mockito.version` from 5.14.2 to 5.15.2. Updates `org.mockito:mockito-core` from 5.14.2 to 5.15.2 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.14.2...v5.15.2) Updates `org.mockito:mockito-junit-jupiter` from 5.14.2 to 5.15.2 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.14.2...v5.15.2) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- form-spring/pom.xml | 4 ++-- form/pom.xml | 4 ++-- pom.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 94c9fb2178..26d54d25f0 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -137,13 +137,13 @@ org.mockito mockito-core - 5.14.2 + 5.15.2 test org.mockito mockito-junit-jupiter - 5.14.2 + 5.15.2 test diff --git a/form/pom.xml b/form/pom.xml index 9bf4bfe121..46f7dd1167 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -99,13 +99,13 @@ org.mockito mockito-core - 5.14.2 + 5.15.2 test org.mockito mockito-junit-jupiter - 5.14.2 + 5.15.2 test diff --git a/pom.xml b/pom.xml index 524ca20f81..c6d936c659 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ 5.11.4 2.18.2 3.27.1 - 5.14.2 + 5.15.2 2.0.53 5.3 From a3f66eed7411c6e412b7315bb94899183c06fca4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 05:50:14 +0000 Subject: [PATCH 007/615] Bump org.assertj:assertj-core from 3.27.1 to 3.27.2 Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.27.1 to 3.27.2. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.1...assertj-build-3.27.2) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c6d936c659..3277e31bc3 100644 --- a/pom.xml +++ b/pom.xml @@ -179,7 +179,7 @@ 5.11.4 2.18.2 - 3.27.1 + 3.27.2 5.15.2 2.0.53 From c9e55c909629fa02968239229d97bf69a4ff33ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 05:11:38 +0000 Subject: [PATCH 008/615] Bump commons-codec:commons-codec from 1.17.1 to 1.17.2 Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.17.1 to 1.17.2. - [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.17.1...rel/commons-codec-1.17.2) --- updated-dependencies: - dependency-name: commons-codec:commons-codec dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- httpclient/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpclient/pom.xml b/httpclient/pom.xml index fb0c94de59..a5dae2c729 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -38,7 +38,7 @@ --> commons-codec commons-codec - 1.17.1 + 1.17.2 From 3e101c89d5322d7b18ecd2ddfecbf7399dffd14e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 05:32:41 +0000 Subject: [PATCH 009/615] Bump org.json:json from 20241224 to 20250107 Bumps [org.json:json](https://github.com/douglascrockford/JSON-java) from 20241224 to 20250107. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/commits) --- updated-dependencies: - dependency-name: org.json:json dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3277e31bc3..8548088594 100644 --- a/pom.xml +++ b/pom.xml @@ -174,7 +174,7 @@ 2.11.0 1.15.2 2.0.16 - 20241224 + 20250107 3.3.5 5.11.4 From acad24e659371ee465d3cbf7dd6b7e6ab7bdf8be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 05:28:10 +0000 Subject: [PATCH 010/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 2.24.0 to 2.24.1. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v2.24.0...v2.24.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8548088594..5dd8dfc78b 100644 --- a/pom.xml +++ b/pom.xml @@ -997,7 +997,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 2.24.0 + 2.24.1 org.openrewrite.recipe From c5b135248661bbde6bdcc5171cceb56e67ee9d22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 05:38:51 +0000 Subject: [PATCH 011/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 2.31.0 to 2.31.1 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 2.31.0 to 2.31.1. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v2.31.0...v2.31.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5dd8dfc78b..d2c92cd0f7 100644 --- a/pom.xml +++ b/pom.xml @@ -1002,7 +1002,7 @@ org.openrewrite.recipe rewrite-migrate-java - 2.31.0 + 2.31.1 From ac130b791bec76d092b9c5208b42df1f5839d161 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 06:00:25 +0000 Subject: [PATCH 012/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 2.31.1 to 3.0.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 2.31.1 to 3.0.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v2.31.1...v3.0.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d2c92cd0f7..6da5f6ba27 100644 --- a/pom.xml +++ b/pom.xml @@ -1002,7 +1002,7 @@ org.openrewrite.recipe rewrite-migrate-java - 2.31.1 + 3.0.0 From 5d471cdb60fb3c9751b0b39e26c4879c7df1a8aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 06:09:41 +0000 Subject: [PATCH 013/615] Bump com.alibaba.fastjson2:fastjson2 from 2.0.53 to 2.0.54 Bumps [com.alibaba.fastjson2:fastjson2](https://github.com/alibaba/fastjson2) from 2.0.53 to 2.0.54. - [Release notes](https://github.com/alibaba/fastjson2/releases) - [Commits](https://github.com/alibaba/fastjson2/compare/2.0.53...2.0.54) --- updated-dependencies: - dependency-name: com.alibaba.fastjson2:fastjson2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6da5f6ba27..99f6641b70 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ 2.18.2 3.27.2 5.15.2 - 2.0.53 + 2.0.54 5.3 3.13.0 From 529a8a6dd4e766b9e1d24b7e938c84abab014c38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 06:18:37 +0000 Subject: [PATCH 014/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 5.47.3 to 6.0.0 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 5.47.3 to 6.0.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v5.47.3...v6.0.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 99f6641b70..40c891d1f6 100644 --- a/pom.xml +++ b/pom.xml @@ -991,7 +991,7 @@ org.openrewrite.maven rewrite-maven-plugin - 5.47.3 + 6.0.0 From 959f27ac5494604b53abbf82c96175a1fd9c61dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 06:27:54 +0000 Subject: [PATCH 015/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 2.24.1 to 3.0.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v2.24.1...v3.0.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 40c891d1f6..099898c163 100644 --- a/pom.xml +++ b/pom.xml @@ -997,7 +997,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 2.24.1 + 3.0.0 org.openrewrite.recipe From 9b2d23d0a3e32b61284c9f315de3b3dce917845d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 05:25:39 +0000 Subject: [PATCH 016/615] Bump micrometer.version from 1.14.2 to 1.14.3 Bumps `micrometer.version` from 1.14.2 to 1.14.3. Updates `io.micrometer:micrometer-core` from 1.14.2 to 1.14.3 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.2...v1.14.3) Updates `io.micrometer:micrometer-test` from 1.14.2 to 1.14.3 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.2...v1.14.3) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 3fbc442388..aadb2505be 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.14.2 + 1.14.3 From 2ea3e7ac7fe1b5affa2b779b62868481a027a97a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 05:23:20 +0000 Subject: [PATCH 017/615] Bump netty.version from 4.1.116.Final to 4.1.117.Final Bumps `netty.version` from 4.1.116.Final to 4.1.117.Final. Updates `io.netty:netty-bom` from 4.1.116.Final to 4.1.117.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.116.Final...netty-4.1.117.Final) Updates `io.netty:netty-handler` from 4.1.116.Final to 4.1.117.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.116.Final...netty-4.1.117.Final) Updates `io.netty:netty-codec-http` from 4.1.116.Final to 4.1.117.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.116.Final...netty-4.1.117.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 7ea96c4954..1316a053f9 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.1.116.Final + 4.1.117.Final true From 905e336bbe34d2b535fe9d97908e4365baff0466 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 05:36:44 +0000 Subject: [PATCH 018/615] Bump io.dropwizard.metrics:metrics-core from 4.2.29 to 4.2.30 Bumps [io.dropwizard.metrics:metrics-core](https://github.com/dropwizard/metrics) from 4.2.29 to 4.2.30. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.29...v4.2.30) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- dropwizard-metrics4/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 584f1cfc17..e6c469eaa5 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -40,7 +40,7 @@ io.dropwizard.metrics metrics-core - 4.2.29 + 4.2.30 ${project.groupId} From fe1314df3723698c54ceef9e4fb951c9db7e9cad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 05:44:41 +0000 Subject: [PATCH 019/615] Bump reactor.version from 3.7.1 to 3.7.2 Bumps `reactor.version` from 3.7.1 to 3.7.2. Updates `io.projectreactor:reactor-core` from 3.7.1 to 3.7.2 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.1...v3.7.2) Updates `io.projectreactor:reactor-test` from 3.7.1 to 3.7.2 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.1...v3.7.2) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index 0494f428bf..db13a22b71 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.7.1 + 3.7.2 1.0.4 2.2.21 From ffc4e5daac1334ee1755a87abaf1cc0bac6774fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jan 2025 05:53:15 +0000 Subject: [PATCH 020/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.0.0 to 6.0.1 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.0.0...v6.0.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 099898c163..9d1538f32e 100644 --- a/pom.xml +++ b/pom.xml @@ -991,7 +991,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.0.0 + 6.0.1 From 81e45a062b846beb2a342a097991704277fb8a52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Jan 2025 05:32:52 +0000 Subject: [PATCH 021/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.0.1 to 6.0.2 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.0.1...v6.0.2) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9d1538f32e..3664b1fcd2 100644 --- a/pom.xml +++ b/pom.xml @@ -991,7 +991,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.0.1 + 6.0.2 From 0c83f360a78215a09254b5d40ea1ee94c4376182 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 05:28:39 +0000 Subject: [PATCH 022/615] Bump org.springframework:spring-context from 6.2.1 to 6.2.2 Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 6.2.1 to 6.2.2. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.1...v6.2.2) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index b944527c6d..05dfc70de5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - 6.2.1 + 6.2.2 test From b33412302c55d9c7306d809bfc6a6bc5e7bdc89f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 05:37:19 +0000 Subject: [PATCH 023/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.0.2 to 6.0.3 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.0.2...v6.0.3) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3664b1fcd2..c48311b547 100644 --- a/pom.xml +++ b/pom.xml @@ -991,7 +991,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.0.2 + 6.0.3 From 2596ae438cfe3d82af843725e9674c54aae43af8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 05:21:08 +0000 Subject: [PATCH 024/615] Bump org.assertj:assertj-core from 3.27.2 to 3.27.3 Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.27.2 to 3.27.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.2...assertj-build-3.27.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c48311b547..a0d6bec5a3 100644 --- a/pom.xml +++ b/pom.xml @@ -179,7 +179,7 @@ 5.11.4 2.18.2 - 3.27.2 + 3.27.3 5.15.2 2.0.54 From a49ac37d3388c4bc386a5870232b15f31e9d152e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 05:30:48 +0000 Subject: [PATCH 025/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.0.0 to 3.0.1 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.0.0 to 3.0.1. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.0.0...v3.0.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a0d6bec5a3..e221662e18 100644 --- a/pom.xml +++ b/pom.xml @@ -1002,7 +1002,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.0.0 + 3.0.1 From ea47ef0d83498c74a809742e2622217d5e0fa7d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 05:40:46 +0000 Subject: [PATCH 026/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.0.3 to 6.0.4 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.0.3 to 6.0.4. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.0.3...v6.0.4) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e221662e18..4771d3a74e 100644 --- a/pom.xml +++ b/pom.xml @@ -991,7 +991,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.0.3 + 6.0.4 From ff9e5adc2f430551178132596e02172c49ffb7f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2025 05:57:41 +0000 Subject: [PATCH 027/615] Bump com.gradle:develocity-maven-extension from 1.23 to 1.23.1 Bumps com.gradle:develocity-maven-extension from 1.23 to 1.23.1. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 298ad324a2..2e1c55bed6 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 1.23 + 1.23.1 com.gradle From 57d478eabc9ed5b59fd309a7060d3c89298734a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 05:57:34 +0000 Subject: [PATCH 028/615] Bump vertx.version from 4.5.11 to 4.5.12 Bumps `vertx.version` from 4.5.11 to 4.5.12. Updates `io.vertx:vertx-core` from 4.5.11 to 4.5.12 - [Commits](https://github.com/eclipse/vert.x/compare/4.5.11...4.5.12) Updates `io.vertx:vertx-junit5` from 4.5.11 to 4.5.12 --- updated-dependencies: - dependency-name: io.vertx:vertx-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-junit5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/pom.xml b/vertx/pom.xml index 27d0bd3d85..1ccf01b978 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -30,7 +30,7 @@ Implementation of Feign on Vertx web client. - 4.5.11 + 4.5.12 2.18.2 2.0.0-alpha6 2.35.2 From c6eca62735db2e38eaf7f207ba36eacd1be03ce7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 05:47:02 +0000 Subject: [PATCH 029/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.0.4 to 6.0.5 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.0.4 to 6.0.5. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.0.4...v6.0.5) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4771d3a74e..572fb5d4b5 100644 --- a/pom.xml +++ b/pom.xml @@ -991,7 +991,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.0.4 + 6.0.5 From e45c87ce505df84cb2f454e54742934c8b690ba4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 05:55:55 +0000 Subject: [PATCH 030/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.0.0...v3.1.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 572fb5d4b5..f29e9931f5 100644 --- a/pom.xml +++ b/pom.xml @@ -997,7 +997,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.0.0 + 3.1.0 org.openrewrite.recipe From 163aad4f8572397a13ff35c18de481e9015a9c01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jan 2025 06:05:33 +0000 Subject: [PATCH 031/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.0.1 to 3.1.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.0.1 to 3.1.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.0.1...v3.1.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f29e9931f5..09148bf73a 100644 --- a/pom.xml +++ b/pom.xml @@ -1002,7 +1002,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.0.1 + 3.1.0 From 71604b5e4dcc4e95d34bb2a61effb7fd8d90a753 Mon Sep 17 00:00:00 2001 From: Julen Garcia Leunda Date: Mon, 27 Jan 2025 17:31:09 +0100 Subject: [PATCH 032/615] Add gzip and deflate compression support in Http2Client (#2738) * Enable Http2Client tests * Fix Http2Client timeoutTest * Override some AbstractClientTests as Http2Client does not expose reason phrase * Add gzip and deflate compression support in Http2Client --- .../java/feign/client/AbstractClientTest.java | 12 +- .../java/feign/http2client/Http2Client.java | 17 +- .../http2client/test/Http2ClientTest.java | 184 ++++++++++++++++-- 3 files changed, 193 insertions(+), 20 deletions(-) diff --git a/core/src/test/java/feign/client/AbstractClientTest.java b/core/src/test/java/feign/client/AbstractClientTest.java index 7270bb16ca..bb01525c99 100644 --- a/core/src/test/java/feign/client/AbstractClientTest.java +++ b/core/src/test/java/feign/client/AbstractClientTest.java @@ -127,7 +127,7 @@ public void reasonPhraseIsOptional() throws IOException, InterruptedException { } @Test - void parsesErrorResponse() { + public void parsesErrorResponse() { server.enqueue(new MockResponse().setResponseCode(500).setBody("ARGHH")); @@ -244,7 +244,7 @@ public void noResponseBodyForPatch() { } @Test - void parsesResponseMissingLength() throws IOException { + public void parsesResponseMissingLength() throws IOException { server.enqueue(new MockResponse().setChunkedBody("foo", 1)); TestInterface api = @@ -332,7 +332,7 @@ public void contentTypeDefaultsToRequestCharset() throws Exception { } @Test - void defaultCollectionFormat() throws Exception { + public void defaultCollectionFormat() throws Exception { server.enqueue(new MockResponse().setBody("body")); TestInterface api = @@ -349,7 +349,7 @@ void defaultCollectionFormat() throws Exception { } @Test - void headersWithNullParams() throws InterruptedException { + public void headersWithNullParams() throws InterruptedException { server.enqueue(new MockResponse().setBody("body")); TestInterface api = @@ -367,7 +367,7 @@ void headersWithNullParams() throws InterruptedException { } @Test - void headersWithNotEmptyParams() throws InterruptedException { + public void headersWithNotEmptyParams() throws InterruptedException { server.enqueue(new MockResponse().setBody("body")); TestInterface api = @@ -385,7 +385,7 @@ void headersWithNotEmptyParams() throws InterruptedException { } @Test - void alternativeCollectionFormat() throws Exception { + public void alternativeCollectionFormat() throws Exception { server.enqueue(new MockResponse().setBody("body")); TestInterface api = diff --git a/java11/src/main/java/feign/http2client/Http2Client.java b/java11/src/main/java/feign/http2client/Http2Client.java index d20d03bb61..40d4548a22 100644 --- a/java11/src/main/java/feign/http2client/Http2Client.java +++ b/java11/src/main/java/feign/http2client/Http2Client.java @@ -15,7 +15,7 @@ */ package feign.http2client; -import static feign.Util.enumForName; +import static feign.Util.*; import feign.AsyncClient; import feign.Client; @@ -54,6 +54,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.zip.GZIPInputStream; +import java.util.zip.InflaterInputStream; public class Http2Client implements Client, AsyncClient { @@ -129,9 +131,20 @@ public CompletableFuture execute( protected Response toFeignResponse(Request request, HttpResponse httpResponse) { final OptionalLong length = httpResponse.headers().firstValueAsLong("Content-Length"); + InputStream body = httpResponse.body(); + + if (httpResponse.headers().allValues(CONTENT_ENCODING).contains(ENCODING_GZIP)) { + try { + body = new GZIPInputStream(body); + } catch (IOException ignored) { + } + } else if (httpResponse.headers().allValues(CONTENT_ENCODING).contains(ENCODING_DEFLATE)) { + body = new InflaterInputStream(body); + } + return Response.builder() .protocolVersion(enumForName(ProtocolVersion.class, httpResponse.version())) - .body(httpResponse.body(), length.isPresent() ? (int) length.getAsLong() : null) + .body(body, length.isPresent() ? (int) length.getAsLong() : null) .reason(httpResponse.headers().firstValue("Reason-Phrase").orElse(null)) .request(request) .status(httpResponse.statusCode()) diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientTest.java index 4887c17911..806b9321a5 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientTest.java @@ -15,28 +15,27 @@ */ package feign.http2client.test; +import static feign.Util.UTF_8; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; import static org.junit.jupiter.api.Assertions.assertThrows; -import feign.Body; -import feign.Feign; -import feign.FeignException; -import feign.Headers; -import feign.Request; -import feign.RequestLine; -import feign.Response; -import feign.Retryer; +import feign.*; +import feign.assertj.MockWebServerAssertions; import feign.client.AbstractClientTest; import feign.http2client.Http2Client; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.http.HttpTimeoutException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeUnit; import okhttp3.mockwebserver.MockResponse; -import org.junit.jupiter.api.Disabled; +import okhttp3.mockwebserver.RecordedRequest; import org.junit.jupiter.api.Test; /** Tests client-specific behavior, such as ensuring Content-Length is sent when specified. */ -@Disabled public class Http2ClientTest extends AbstractClientTest { public interface TestInterface { @@ -59,6 +58,24 @@ public interface TestInterface { @RequestLine("DELETE /anything") @Body("some request body") String deleteWithBody(); + + @RequestLine("POST /?foo=bar&foo=baz&qux=") + @Headers({"Foo: Bar", "Foo: Baz", "Qux: ", "Content-Type: text/plain"}) + Response post(String body); + + @RequestLine("GET /") + @Headers("Accept: text/plain") + String get(); + + @RequestLine("GET /?foo={multiFoo}") + Response get(@Param("multiFoo") List multiFoo); + + @Headers({"Authorization: {authorization}"}) + @RequestLine("GET /") + Response getWithHeaders(@Param("authorization") String authorization); + + @RequestLine(value = "GET /?foo={multiFoo}", collectionFormat = CollectionFormat.CSV) + Response getCSV(@Param("multiFoo") List multiFoo); } @Override @@ -117,12 +134,13 @@ public void veryLongResponseNullLength() { @Test void timeoutTest() { - server.enqueue(new MockResponse().setBody("foo").setBodyDelay(30, TimeUnit.SECONDS)); + server.enqueue(new MockResponse().setBody("foo").setHeadersDelay(1, TimeUnit.SECONDS)); final TestInterface api = newBuilder() .retryer(Retryer.NEVER_RETRY) - .options(new Request.Options(1, TimeUnit.SECONDS, 1, TimeUnit.SECONDS, true)) + .options( + new Request.Options(500, TimeUnit.MILLISECONDS, 500, TimeUnit.MILLISECONDS, true)) .target(TestInterface.class, server.url("/").toString()); FeignException exception = assertThrows(FeignException.class, () -> api.timeout()); @@ -145,6 +163,148 @@ void deleteWithRequestBody() { assertThat(result).contains("\"data\": \"some request body\""); } + @Override + @Test + public void parsesResponseMissingLength() throws IOException { + server.enqueue(new MockResponse().setChunkedBody("foo", 1)); + + TestInterface api = + newBuilder().target(TestInterface.class, "http://localhost:" + server.getPort()); + + Response response = api.post("testing"); + assertThat(response.status()).isEqualTo(200); + // assertThat(response.reason()).isEqualTo("OK"); + assertThat(response.body().length()).isNull(); + assertThat(response.body().asInputStream()) + .hasSameContentAs(new ByteArrayInputStream("foo".getBytes(UTF_8))); + } + + @Override + @Test + public void parsesErrorResponse() { + + server.enqueue(new MockResponse().setResponseCode(500).setBody("ARGHH")); + + TestInterface api = + newBuilder().target(TestInterface.class, "http://localhost:" + server.getPort()); + + Throwable exception = assertThrows(FeignException.class, () -> api.get()); + assertThat(exception.getMessage()) + .contains( + "[500] during [GET] to [http://localhost:" + + server.getPort() + + "/] [TestInterface#get()]: [ARGHH]"); + } + + @Override + @Test + public void defaultCollectionFormat() throws Exception { + server.enqueue(new MockResponse().setBody("body")); + + TestInterface api = + newBuilder().target(TestInterface.class, "http://localhost:" + server.getPort()); + + Response response = api.get(Arrays.asList("bar", "baz")); + + assertThat(response.status()).isEqualTo(200); + // assertThat(response.reason()).isEqualTo("OK"); + + MockWebServerAssertions.assertThat(server.takeRequest()) + .hasMethod("GET") + .hasPath("/?foo=bar&foo=baz"); + } + + @Override + @Test + public void headersWithNotEmptyParams() throws InterruptedException { + server.enqueue(new MockResponse().setBody("body")); + + TestInterface api = + newBuilder().target(TestInterface.class, "http://localhost:" + server.getPort()); + + Response response = api.getWithHeaders("token"); + + assertThat(response.status()).isEqualTo(200); + // assertThat(response.reason()).isEqualTo("OK"); + + MockWebServerAssertions.assertThat(server.takeRequest()) + .hasMethod("GET") + .hasPath("/") + .hasHeaders(entry("authorization", Collections.singletonList("token"))); + } + + @Override + @Test + public void headersWithNullParams() throws InterruptedException { + server.enqueue(new MockResponse().setBody("body")); + + TestInterface api = + newBuilder().target(TestInterface.class, "http://localhost:" + server.getPort()); + + Response response = api.getWithHeaders(null); + + assertThat(response.status()).isEqualTo(200); + // assertThat(response.reason()).isEqualTo("OK"); + + MockWebServerAssertions.assertThat(server.takeRequest()) + .hasMethod("GET") + .hasPath("/") + .hasNoHeaderNamed("Authorization"); + } + + @Test + public void alternativeCollectionFormat() throws Exception { + server.enqueue(new MockResponse().setBody("body")); + + TestInterface api = + newBuilder().target(TestInterface.class, "http://localhost:" + server.getPort()); + + Response response = api.getCSV(Arrays.asList("bar", "baz")); + + assertThat(response.status()).isEqualTo(200); + // assertThat(response.reason()).isEqualTo("OK"); + + // Some HTTP libraries percent-encode commas in query parameters and others + // don't. + MockWebServerAssertions.assertThat(server.takeRequest()) + .hasMethod("GET") + .hasOneOfPath("/?foo=bar,baz", "/?foo=bar%2Cbaz"); + } + + @Override + @Test + public void parsesRequestAndResponse() throws IOException, InterruptedException { + server.enqueue(new MockResponse().setBody("foo").addHeader("Foo: Bar")); + + TestInterface api = + newBuilder().target(TestInterface.class, "http://localhost:" + server.getPort()); + + Response response = api.post("foo"); + + assertThat(response.status()).isEqualTo(200); + // assertThat(response.reason()).isEqualTo("OK"); + assertThat(response.headers()) + .hasEntrySatisfying( + "Content-Length", + value -> { + assertThat(value).contains("3"); + }) + .hasEntrySatisfying( + "Foo", + value -> { + assertThat(value).contains("Bar"); + }); + assertThat(response.body().asInputStream()) + .hasSameContentAs(new ByteArrayInputStream("foo".getBytes(UTF_8))); + + RecordedRequest recordedRequest = server.takeRequest(); + assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("POST"); + assertThat(recordedRequest.getHeader("Foo")).isEqualToIgnoringCase("Bar, Baz"); + assertThat(recordedRequest.getHeader("Accept")).isEqualToIgnoringCase("*/*"); + assertThat(recordedRequest.getHeader("Content-Length")).isEqualToIgnoringCase("3"); + assertThat(recordedRequest.getBody().readUtf8()).isEqualToIgnoringCase("foo"); + } + @Override public Feign.Builder newBuilder() { return Feign.builder().client(new Http2Client()); From 34760ef721fdef085c8ec9bcb4d9bda0c687a052 Mon Sep 17 00:00:00 2001 From: Tyler Bertrand <121591679+tylerbertrand@users.noreply.github.com> Date: Mon, 27 Jan 2025 11:23:39 -0600 Subject: [PATCH 033/615] Enable Local Build Caching and Apply Optimizations (#2656) * Normalize manifest file * Remove develocity-workspace-id from version control This is an identifier captured by Develocity used to uniquely represent a given workspace should not be committed * Enable local build cache * Use develocity-actions/setup-maven to surface Build Scan links Don't add PR comment with build scan links - scans aren't published for PR builds against forks --- .github/workflows/codeql-analysis.yml | 8 ++++++-- .github/workflows/receive-pr.yml | 7 +++++-- .mvn/.develocity/develocity-workspace-id | 1 - .mvn/develocity.xml | 2 +- pom.xml | 16 ++++++++++++++++ 5 files changed, 28 insertions(+), 6 deletions(-) delete mode 100644 .mvn/.develocity/develocity-workspace-id diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index e442a7ff43..710211c27b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -92,10 +92,14 @@ jobs: distribution: 'temurin' java-version: '21' + - name: Setup Develocity + uses: gradle/develocity-actions/setup-maven@v1.2 + with: + add-pr-comment: false + develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} + - name: Compile project run: ./mvnw -B -ntp clean package -Pquickbuild -Dtoolchain.skip=true - env: - DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/receive-pr.yml b/.github/workflows/receive-pr.yml index 8945e262e0..684c5cdea8 100644 --- a/.github/workflows/receive-pr.yml +++ b/.github/workflows/receive-pr.yml @@ -28,6 +28,11 @@ jobs: java-version: '21' distribution: 'temurin' cache: 'maven' + - name: Setup Develocity + uses: gradle/develocity-actions/setup-maven@v1.2 + with: + add-pr-comment: false + develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} # Capture the PR number # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow @@ -43,8 +48,6 @@ jobs: # Execute recipes - name: Apply OpenRewrite recipes run: ./mvnw -Dtoolchain.skip=true -Dlicense.skip=true -DskipTests=true -P openrewrite clean install - env: - DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} # Capture the diff - name: Create patch diff --git a/.mvn/.develocity/develocity-workspace-id b/.mvn/.develocity/develocity-workspace-id deleted file mode 100644 index b79e6d0951..0000000000 --- a/.mvn/.develocity/develocity-workspace-id +++ /dev/null @@ -1 +0,0 @@ -h5io2ff2gzdbbjanvoljkzgzra \ No newline at end of file diff --git a/.mvn/develocity.xml b/.mvn/develocity.xml index 1fe2a983dc..4f9fdf42dc 100644 --- a/.mvn/develocity.xml +++ b/.mvn/develocity.xml @@ -33,7 +33,7 @@ - false + true false diff --git a/pom.xml b/pom.xml index 09148bf73a..aed5c72fc0 100644 --- a/pom.xml +++ b/pom.xml @@ -536,6 +536,22 @@ false + + + com.gradle + develocity-maven-extension + + + + + + true + + + + + + From 585faa33c89d0c8c222e4f14b38d54e6393d4994 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jan 2025 05:10:52 +0000 Subject: [PATCH 034/615] Bump commons-codec:commons-codec from 1.17.2 to 1.18.0 Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.17.2 to 1.18.0. - [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.17.2...rel/commons-codec-1.18.0) --- updated-dependencies: - dependency-name: commons-codec:commons-codec dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- httpclient/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpclient/pom.xml b/httpclient/pom.xml index a5dae2c729..162c4c86b6 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -38,7 +38,7 @@ --> commons-codec commons-codec - 1.17.2 + 1.18.0 From 97069830765fb0fe3eca0cf8de7181f2e498d8a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jan 2025 05:19:36 +0000 Subject: [PATCH 035/615] Bump kotlin.version from 2.1.0 to 2.1.10 Bumps `kotlin.version` from 2.1.0 to 2.1.10. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.1.0 to 2.1.10 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.0...v2.1.10) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.1.0 to 2.1.10 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.0...v2.1.10) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.1.0 to 2.1.10 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index cde3d217a5..f7458f4cf1 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.1.0 + 2.1.10 1.10.1 From 9bbf7227d8057a8be5d865120c317e83a99bc141 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Jan 2025 05:57:23 +0000 Subject: [PATCH 036/615] Bump com.google.code.gson:gson from 2.11.0 to 2.12.0 Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.11.0 to 2.12.0. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.11.0...gson-parent-2.12.0) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aed5c72fc0..ff2af87e80 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 4.12.0 33.4.0-jre 1.45.3 - 2.11.0 + 2.12.0 1.15.2 2.0.16 20250107 From 41fe83b3807b7df46c1bb37b307c8f44250a2c57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2025 05:59:37 +0000 Subject: [PATCH 037/615] Bump com.google.code.gson:gson from 2.12.0 to 2.12.1 Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.12.0 to 2.12.1. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.12.0...gson-parent-2.12.1) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ff2af87e80..8a4bd68e73 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 4.12.0 33.4.0-jre 1.45.3 - 2.12.0 + 2.12.1 1.15.2 2.0.16 20250107 From 37f17db66376690214c169edfd2781b0ab7a80b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 05:24:09 +0000 Subject: [PATCH 038/615] Bump org.apache.httpcomponents.client5:httpclient5 from 5.4.1 to 5.4.2 Bumps [org.apache.httpcomponents.client5:httpclient5](https://github.com/apache/httpcomponents-client) from 5.4.1 to 5.4.2. - [Changelog](https://github.com/apache/httpcomponents-client/blob/rel/v5.4.2/RELEASE_NOTES.txt) - [Commits](https://github.com/apache/httpcomponents-client/compare/rel/v5.4.1...rel/v5.4.2) --- updated-dependencies: - dependency-name: org.apache.httpcomponents.client5:httpclient5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- hc5/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hc5/pom.xml b/hc5/pom.xml index c90e950095..c59108c667 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -38,7 +38,7 @@ org.apache.httpcomponents.client5 httpclient5 - 5.4.1 + 5.4.2 From c32cd4f0044c275f8d27dad72b8e579c286d5bc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Feb 2025 05:07:24 +0000 Subject: [PATCH 039/615] Bump com.google.http-client:google-http-client from 1.45.3 to 1.46.0 Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 1.45.3 to 1.46.0. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v1.45.3...v1.46.0) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a4bd68e73..a2a4353e19 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 4.12.0 33.4.0-jre - 1.45.3 + 1.46.0 2.12.1 1.15.2 2.0.16 From 760d10968e7e04d502d7e34b8d9e942c40941eac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 05:29:24 +0000 Subject: [PATCH 040/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.1.0...v3.2.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a2a4353e19..81e2874ddb 100644 --- a/pom.xml +++ b/pom.xml @@ -1013,7 +1013,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.1.0 + 3.2.0 org.openrewrite.recipe From 259aecda16e1855e6d50087ede9a424c3541d649 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 05:39:22 +0000 Subject: [PATCH 041/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.1.0 to 3.2.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.1.0...v3.2.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 81e2874ddb..d30c712eca 100644 --- a/pom.xml +++ b/pom.xml @@ -1018,7 +1018,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.1.0 + 3.2.0 From 4adee5f9bb3d8ec2b203b63efb0927ceac95ac40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 05:48:56 +0000 Subject: [PATCH 042/615] Bump com.google.http-client:google-http-client from 1.46.0 to 1.46.1 Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 1.46.0 to 1.46.1. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v1.46.0...v1.46.1) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d30c712eca..2d9dcb6a84 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 4.12.0 33.4.0-jre - 1.46.0 + 1.46.1 2.12.1 1.15.2 2.0.16 From 79bf01cfa4ea215c10be35307cd1ed7e783e9b1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 05:58:45 +0000 Subject: [PATCH 043/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.0.5 to 6.1.0 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.0.5 to 6.1.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.0.5...v6.1.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2d9dcb6a84..b19d0fb65c 100644 --- a/pom.xml +++ b/pom.xml @@ -1007,7 +1007,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.0.5 + 6.1.0 From 6fe2e8c5e9ca4b0fd4bf313ba088974eca1bfbcc Mon Sep 17 00:00:00 2001 From: Marvin Date: Mon, 10 Feb 2025 07:03:15 -0300 Subject: [PATCH 044/615] Dependabot/maven/springboot.version 3.4.0 (#2716) * Bump org.springframework.cloud:spring-cloud-starter-openfeign Bumps [org.springframework.cloud:spring-cloud-starter-openfeign](https://github.com/spring-cloud/spring-cloud-openfeign) from 4.1.4 to 4.2.0. - [Release notes](https://github.com/spring-cloud/spring-cloud-openfeign/releases) - [Commits](https://github.com/spring-cloud/spring-cloud-openfeign/compare/v4.1.4...v4.2.0) --- updated-dependencies: - dependency-name: org.springframework.cloud:spring-cloud-starter-openfeign dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump org.springframework.cloud:spring-cloud-dependencies Bumps [org.springframework.cloud:spring-cloud-dependencies](https://github.com/spring-cloud/spring-cloud-release) from 2023.0.3 to 2024.0.0. - [Release notes](https://github.com/spring-cloud/spring-cloud-release/releases) - [Commits](https://github.com/spring-cloud/spring-cloud-release/compare/v2023.0.3...v2024.0.0) --- updated-dependencies: - dependency-name: org.springframework.cloud:spring-cloud-dependencies dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Bump springboot.version from 3.3.5 to 3.4.0 Bumps `springboot.version` from 3.3.5 to 3.4.0. Updates `org.springframework.boot:spring-boot-starter-web` from 3.3.5 to 3.4.0 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.5...v3.4.0) Updates `org.springframework.boot:spring-boot-starter-test` from 3.3.5 to 3.4.0 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.5...v3.4.0) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-web dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.springframework.boot:spring-boot-starter-test dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Fix dependencies hierarchy * Reset version changes, just keep new structure --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- example-wikipedia-with-springboot/pom.xml | 4 ++++ form-spring/pom.xml | 15 +-------------- form/pom.xml | 2 +- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 493a45209d..e999889996 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -51,6 +51,10 @@ io.github.openfeign feign-core + + io.github.openfeign + feign-form + io.github.openfeign feign-gson diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 26d54d25f0..64827e5d87 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -28,7 +28,7 @@ feign-form-spring - Open Feign Forms Extension for Spring + Feign Forms Extension for Spring 17 @@ -104,19 +104,6 @@ test - - io.undertow - undertow-core - 2.3.18.Final - test - - - io.appulse - utils-java - 1.18.0 - test - - org.junit.jupiter junit-jupiter-engine diff --git a/form/pom.xml b/form/pom.xml index 46f7dd1167..38a0010877 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -28,7 +28,7 @@ feign-form - Open Feign Forms Core + Feign Forms Core org.projectlombok From 715b3a7137e80bae17442a7c84fd83c124a22c3d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Feb 2025 10:10:20 +0000 Subject: [PATCH 045/615] Bump springboot.version from 3.3.5 to 3.4.2 Bumps `springboot.version` from 3.3.5 to 3.4.2. Updates `org.springframework.boot:spring-boot-starter-web` from 3.3.5 to 3.4.2 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.5...v3.4.2) Updates `org.springframework.boot:spring-boot-starter-test` from 3.3.5 to 3.4.2 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.5...v3.4.2) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-web dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.springframework.boot:spring-boot-starter-test dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b19d0fb65c..e277affee5 100644 --- a/pom.xml +++ b/pom.xml @@ -175,7 +175,7 @@ 1.15.2 2.0.16 20250107 - 3.3.5 + 3.4.2 5.11.4 2.18.2 From 4f0e52acb63192831fc098af4670418b4d1bbf65 Mon Sep 17 00:00:00 2001 From: Alexei KLENIN Date: Mon, 10 Feb 2025 15:49:57 +0100 Subject: [PATCH 046/615] CI: migrate build pipeline on GitHub actions (#2759) * CI: migrate build pipeline on GitHub actions * Deploy tags too Signed-off-by: Marvin Froeder * Never fail dependencies download Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder Co-authored-by: Marvin Froeder Co-authored-by: Marvin --- .circleci/config.yml | 140 ---------------------- {.circleci => .github/files}/settings.xml | 0 .github/files/toolchains.xml | 53 ++++++++ .github/workflows/build.yml | 92 ++++++++++++++ .github/workflows/comment-pr.yml | 56 --------- .github/workflows/receive-pr.yml | 59 --------- README.md | 1 - pom.xml | 7 ++ 8 files changed, 152 insertions(+), 256 deletions(-) delete mode 100644 .circleci/config.yml rename {.circleci => .github/files}/settings.xml (100%) create mode 100644 .github/files/toolchains.xml create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/comment-pr.yml delete mode 100644 .github/workflows/receive-pr.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index d1c8c0ac51..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,140 +0,0 @@ -# -# Copyright 2012-2020 The Feign Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except -# in compliance with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed under the License -# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions and limitations under -# the License. -# - -# common executors -executors: - java: - docker: - - image: velo/toolchains-4-ci-builds:with-21 - -# common commands -commands: - resolve-dependencies: - description: 'Download and prepare all dependencies' - steps: - - run: - name: 'Resolving Dependencies' - command: | - ./mvnw -ntp dependency:resolve-plugins go-offline:resolve-dependencies -DskipTests=true -B - verify-formatting: - steps: - - run: - name: 'Verify formatting' - command: | - scripts/no-git-changes.sh - configure-gpg: - steps: - - run: - name: 'Configure GPG keys' - command: | - echo -e "$GPG_KEY" | gpg --batch --no-tty --import --yes - nexus-deploy: - steps: - - run: - name: 'Deploy Core Modules Sonatype' - command: | - ./mvnw -ntp -nsu -s .circleci/settings.xml -P release -pl -:feign-benchmark -DskipTests=true deploy - -# our job defaults -defaults: &defaults - working_directory: ~/feign - environment: - # Customize the JVM maximum heap limit - MAVEN_OPTS: -Xmx3200m - -# branch filters -master-only: &master-only - branches: - only: master - -tags-only: &tags-only - branches: - ignore: /.*/ - tags: - only: /.*/ - -all-branches: &all-branches - branches: - ignore: master - tags: - ignore: /.*/ - -version: 2.1 - -jobs: - test: - executor: - name: java - <<: *defaults - steps: - - checkout - - restore_cache: - keys: - - feign-dependencies-v2-{{ checksum "pom.xml" }} - - feign-dependencies-v2- - - resolve-dependencies - - save_cache: - paths: - - ~/.m2/repository - key: feign-dependencies-v2-{{ checksum "pom.xml" }} - - run: - name: 'Test' - command: | - ./mvnw -ntp -B verify - - verify-formatting - - deploy: - executor: - name: java - <<: *defaults - steps: - - checkout - - restore_cache: - keys: - - feign-dependencies-v2-{{ checksum "pom.xml" }} - - feign-dependencies-v2- - - resolve-dependencies - - configure-gpg - - nexus-deploy - -workflows: - version: 2 - build: - jobs: - - test: - name: 'pr-build' - filters: - <<: *all-branches - - snapshot: - jobs: - - test: - name: 'snapshot' - filters: - <<: *master-only - - deploy: - name: 'deploy snapshot' - requires: - - 'snapshot' - context: Sonatype - filters: - <<: *master-only - - release: - jobs: - - deploy: - name: 'release to maven central' - context: Sonatype - filters: - <<: *tags-only diff --git a/.circleci/settings.xml b/.github/files/settings.xml similarity index 100% rename from .circleci/settings.xml rename to .github/files/settings.xml diff --git a/.github/files/toolchains.xml b/.github/files/toolchains.xml new file mode 100644 index 0000000000..7fb26e061e --- /dev/null +++ b/.github/files/toolchains.xml @@ -0,0 +1,53 @@ + + + + jdk + + 1.8 + + + /home/runner/.sdkman/candidates/java/8.0.382-tem + + + + jdk + + 11 + + + /home/runner/.sdkman/candidates/java/11.0.22-tem + + + + jdk + + 17 + + + /home/runner/.sdkman/candidates/java/17.0.10-tem + + + + jdk + + 21 + + + /home/runner/.sdkman/candidates/java/21.0.2-tem + + + \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..120780560e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,92 @@ +# +# Copyright 2012-2020 The Feign Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# +name: Build + +on: + push: + branches: + - master + tags: + - '*' # Runs on all new tags + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 30 + env: + # Customize the JVM maximum heap limit + MAVEN_OPTS: -Xmx3200m + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + + - name: Cache local Maven repository + uses: actions/cache@v3 + continue-on-error: true + with: + path: ~/.m2 + key: ${{ runner.os }}-maven-${{ matrix.language }} ${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven-${{ matrix.language }} + ${{ runner.os }}-maven- + + - name: Cache SDKMAN JDKs + uses: actions/cache@v4 + with: + path: ~/.sdkman + key: sdkman-java-${{ runner.os }}-${{ hashFiles('~/.m2/toolchains.xml') }} + restore-keys: sdkman-java-${{ runner.os }}- + + - name: Install SDKMAN! + run: | + if [ ! -d "$HOME/.sdkman" ]; then + curl -s "https://get.sdkman.io" | bash + fi + source "$HOME/.sdkman/bin/sdkman-init.sh" + + - name: Install JDKs (8, 11, 17, 21) + run: | + source "$HOME/.sdkman/bin/sdkman-init.sh" + jdk_versions=("8.0.382-tem" "11.0.22-tem" "17.0.10-tem" "21.0.2-tem") + for jdk_version in "${jdk_versions[@]}"; do + if [ ! -d "$HOME/.sdkman/candidates/java/$jdk_version" ]; then + yes n | sdk install java "$jdk_version" + fi + done + sdk default java 21.0.2-tem + + - name: Configure Maven Toolchain + run: | + mkdir -p ~/.m2 + cp .github/files/toolchains.xml ~/.m2/toolchains.xml + + - name: Download dependencies only + run: ./mvnw -ntp -B org.apache.maven.plugins:maven-dependency-plugin:3.8.1:go-offline de.qaware.maven:go-offline-maven-plugin:1.2.8:resolve-dependencies -fn + + - name: Build + run: ./mvnw -ntp -B clean install + + - name: Verify formatting + run: scripts/no-git-changes.sh + + - name: Nexus deploy + if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/') + run: | + cp .github/files/settings.xml ~/.m2/settings.xml + echo -e "$GPG_KEY" | gpg --batch --no-tty --import --yes + ./mvnw -ntp -nsu -P release -pl -:feign-benchmark -DskipTests=true deploy diff --git a/.github/workflows/comment-pr.yml b/.github/workflows/comment-pr.yml deleted file mode 100644 index 4aac84804a..0000000000 --- a/.github/workflows/comment-pr.yml +++ /dev/null @@ -1,56 +0,0 @@ -# Description: This workflow is triggered when the `receive-pr` workflow completes to post suggestions on the PR. -# Since this pull request has write permissions on the target repo, we should **NOT** execute any untrusted code. -# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ ---- -name: comment-pr - -on: - workflow_run: - workflows: ["receive-pr"] - types: - - completed - -jobs: - post-suggestions: - # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#running-a-workflow-based-on-the-conclusion-of-another-workflow - if: ${{ github.event.workflow_run.conclusion == 'success' }} - runs-on: ubuntu-latest - env: - # https://docs.github.com/en/actions/reference/authentication-in-a-workflow#permissions-for-the-github_token - ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} - timeout-minutes: 10 - steps: - - uses: actions/checkout@v4 - with: - ref: ${{github.event.workflow_run.head_branch}} - repository: ${{github.event.workflow_run.head_repository.full_name}} - - # Download the patch - - uses: actions/download-artifact@v4 - with: - name: patch - github-token: ${{ secrets.GITHUB_TOKEN }} - run-id: ${{ github.event.workflow_run.id }} - - name: Apply patch - run: | - git apply git-diff.patch --allow-empty - rm git-diff.patch - - # Download the PR number - - uses: actions/download-artifact@v4 - with: - name: pr_number - github-token: ${{ secrets.GITHUB_TOKEN }} - run-id: ${{ github.event.workflow_run.id }} - - name: Read pr_number.txt - run: | - PR_NUMBER=$(cat pr_number.txt) - echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV - rm pr_number.txt - - # Post suggestions as a comment on the PR - - uses: googleapis/code-suggester@v4 - with: - command: review - pull_number: ${{ env.PR_NUMBER }} - git_dir: '.' diff --git a/.github/workflows/receive-pr.yml b/.github/workflows/receive-pr.yml deleted file mode 100644 index 684c5cdea8..0000000000 --- a/.github/workflows/receive-pr.yml +++ /dev/null @@ -1,59 +0,0 @@ -# Description: This workflow runs OpenRewrite recipes against opened pull request and upload the patch. -# Since this pull request receives untrusted code, we should **NOT** have any secrets in the environment. -# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ ---- -name: receive-pr - -on: - pull_request: - types: [opened, synchronize] - branches: - - master - -concurrency: - group: '${{ github.workflow }} @ ${{ github.ref }}' - cancel-in-progress: true - -jobs: - upload-patch: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@v4 - with: - ref: ${{github.event.pull_request.head.ref}} - repository: ${{github.event.pull_request.head.repo.full_name}} - - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - cache: 'maven' - - name: Setup Develocity - uses: gradle/develocity-actions/setup-maven@v1.2 - with: - add-pr-comment: false - develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - - # Capture the PR number - # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow - - name: Create pr_number.txt - run: echo "${{ github.event.number }}" > pr_number.txt - - uses: actions/upload-artifact@v4 - with: - name: pr_number - path: pr_number.txt - - name: Remove pr_number.txt - run: rm -f pr_number.txt - - # Execute recipes - - name: Apply OpenRewrite recipes - run: ./mvnw -Dtoolchain.skip=true -Dlicense.skip=true -DskipTests=true -P openrewrite clean install - - # Capture the diff - - name: Create patch - run: | - git diff | tee git-diff.patch - - uses: actions/upload-artifact@v4 - with: - name: patch - path: git-diff.patch diff --git a/README.md b/README.md index a2a1466564..3474f34e9d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # Feign simplifies the process of writing Java HTTP clients [![Join the chat at https://gitter.im/OpenFeign/feign](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/OpenFeign/feign?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![CircleCI](https://circleci.com/gh/OpenFeign/feign/tree/master.svg?style=svg)](https://circleci.com/gh/OpenFeign/feign/tree/master) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.openfeign/feign-core/badge.png)](https://search.maven.org/artifact/io.github.openfeign/feign-core/) Feign is a Java to HTTP client binder inspired by [Retrofit](https://github.com/square/retrofit), [JAXRS-2.0](https://jax-rs-spec.java.net/nonav/2.0/apidocs/index.html), and [WebSocket](http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html). Feign's first goal was reducing the complexity of binding [Denominator](https://github.com/Netflix/Denominator) uniformly to HTTP APIs regardless of [ReSTfulness](http://www.slideshare.net/adrianfcole/99problems). diff --git a/pom.xml b/pom.xml index e277affee5..01227a7cb1 100644 --- a/pom.xml +++ b/pom.xml @@ -525,6 +525,13 @@ + + + org.junit.jupiter + junit-jupiter-engine + ${junit5.version} + + From 9287ebb23268ac956ebe343e39138c9661c17101 Mon Sep 17 00:00:00 2001 From: Marvin Date: Mon, 10 Feb 2025 12:27:18 -0300 Subject: [PATCH 047/615] Revert "Bump springboot.version from 3.3.5 to 3.4.2" (#2764) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 01227a7cb1..1b39445ccd 100644 --- a/pom.xml +++ b/pom.xml @@ -175,7 +175,7 @@ 1.15.2 2.0.16 20250107 - 3.4.2 + 3.3.5 5.11.4 2.18.2 From 7466d66e0201eda3e8959fcc39257dd162e08a09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 05:51:45 +0000 Subject: [PATCH 048/615] Bump micrometer.version from 1.14.3 to 1.14.4 Bumps `micrometer.version` from 1.14.3 to 1.14.4. Updates `io.micrometer:micrometer-core` from 1.14.3 to 1.14.4 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.3...v1.14.4) Updates `io.micrometer:micrometer-test` from 1.14.3 to 1.14.4 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.3...v1.14.4) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index aadb2505be..4cfd735683 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.14.3 + 1.14.4 From 7e71cbeb8e61f9420df43a753a605f83a5985560 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 06:00:14 +0000 Subject: [PATCH 049/615] Bump netty.version from 4.1.117.Final to 4.1.118.Final Bumps `netty.version` from 4.1.117.Final to 4.1.118.Final. Updates `io.netty:netty-bom` from 4.1.117.Final to 4.1.118.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.117.Final...netty-4.1.118.Final) Updates `io.netty:netty-handler` from 4.1.117.Final to 4.1.118.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.117.Final...netty-4.1.118.Final) Updates `io.netty:netty-codec-http` from 4.1.117.Final to 4.1.118.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.117.Final...netty-4.1.118.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 1316a053f9..f7031eeb84 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.1.117.Final + 4.1.118.Final true From 6c9b25e7a63496b6e7a7a699a5a0fb1aa272c9f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 06:02:31 +0000 Subject: [PATCH 050/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.1.0 to 6.1.1 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.1.0 to 6.1.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.1.0...v6.1.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1b39445ccd..625d76eda7 100644 --- a/pom.xml +++ b/pom.xml @@ -1014,7 +1014,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.1.0 + 6.1.1 From 4ced75fa0b1c8e99db9fbbf6047dfda88c213e3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 06:05:16 +0000 Subject: [PATCH 051/615] Bump vertx.version from 4.5.12 to 4.5.13 Bumps `vertx.version` from 4.5.12 to 4.5.13. Updates `io.vertx:vertx-core` from 4.5.12 to 4.5.13 - [Commits](https://github.com/eclipse/vert.x/compare/4.5.12...4.5.13) Updates `io.vertx:vertx-junit5` from 4.5.12 to 4.5.13 --- updated-dependencies: - dependency-name: io.vertx:vertx-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-junit5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/pom.xml b/vertx/pom.xml index 1ccf01b978..aa04c46e51 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -30,7 +30,7 @@ Implementation of Feign on Vertx web client. - 4.5.12 + 4.5.13 2.18.2 2.0.0-alpha6 2.35.2 From 18c7773d09143a2aba323a8dceb9bcf97b535306 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 05:22:26 +0000 Subject: [PATCH 052/615] Bump reactor.version from 3.7.2 to 3.7.3 Bumps `reactor.version` from 3.7.2 to 3.7.3. Updates `io.projectreactor:reactor-core` from 3.7.2 to 3.7.3 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.2...v3.7.3) Updates `io.projectreactor:reactor-test` from 3.7.2 to 3.7.3 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.2...v3.7.3) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index db13a22b71..18cf9e9e15 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.7.2 + 3.7.3 1.0.4 2.2.21 From bb87ff9e9411a175b74095cd13a486d3ec48332c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Feb 2025 05:05:27 +0000 Subject: [PATCH 053/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.1.1 to 6.1.2 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.1.1 to 6.1.2. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.1.1...v6.1.2) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 625d76eda7..c389b31542 100644 --- a/pom.xml +++ b/pom.xml @@ -1014,7 +1014,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.1.1 + 6.1.2 From 17c3e5b3c42039f83e49a353edcc52a1339da0ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Feb 2025 05:55:29 +0000 Subject: [PATCH 054/615] Bump org.springframework:spring-context from 6.2.2 to 6.2.3 Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 6.2.2 to 6.2.3. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.2...v6.2.3) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 05dfc70de5..aa2943ee40 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - 6.2.2 + 6.2.3 test From 1ef6cca57a62d26dbf192e4057dcf38981785abb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Feb 2025 06:03:26 +0000 Subject: [PATCH 055/615] Bump com.alibaba.fastjson2:fastjson2 from 2.0.54 to 2.0.55 Bumps [com.alibaba.fastjson2:fastjson2](https://github.com/alibaba/fastjson2) from 2.0.54 to 2.0.55. - [Release notes](https://github.com/alibaba/fastjson2/releases) - [Commits](https://github.com/alibaba/fastjson2/compare/2.0.54...2.0.55) --- updated-dependencies: - dependency-name: com.alibaba.fastjson2:fastjson2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c389b31542..d008687184 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ 2.18.2 3.27.3 5.15.2 - 2.0.54 + 2.0.55 5.3 3.13.0 From 621822d51a7e095f469247ab6ca7d22de879f792 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Feb 2025 06:06:40 +0000 Subject: [PATCH 056/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.1.2 to 6.1.3 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.1.2 to 6.1.3. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.1.2...v6.1.3) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d008687184..8a4cd73a77 100644 --- a/pom.xml +++ b/pom.xml @@ -1014,7 +1014,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.1.2 + 6.1.3 From 8fe2d79b34bbdac73452a83963a2f1dbfe023a2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2025 05:21:09 +0000 Subject: [PATCH 057/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.1.3 to 6.1.4 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.1.3 to 6.1.4. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.1.3...v6.1.4) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a4cd73a77..96ee367a8a 100644 --- a/pom.xml +++ b/pom.xml @@ -1014,7 +1014,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.1.3 + 6.1.4 From 9fa073be1287de212498bb7c369a22fcc3843292 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 05:04:23 +0000 Subject: [PATCH 058/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.1.4 to 6.2.0 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.1.4 to 6.2.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.1.4...v6.2.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 96ee367a8a..af1c52f319 100644 --- a/pom.xml +++ b/pom.xml @@ -1014,7 +1014,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.1.4 + 6.2.0 From 56e8a3a11f02acca313cefc7fbd3e0c24f578943 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 05:12:43 +0000 Subject: [PATCH 059/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.2.0 to 3.3.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.2.0 to 3.3.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.2.0...v3.3.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index af1c52f319..8dc4669931 100644 --- a/pom.xml +++ b/pom.xml @@ -1025,7 +1025,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.2.0 + 3.3.0 From 1357a1d593208348303393bac2184a02ab51299a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2025 05:15:04 +0000 Subject: [PATCH 060/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.2.0 to 3.3.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.2.0...v3.3.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8dc4669931..2760deff7f 100644 --- a/pom.xml +++ b/pom.xml @@ -1020,7 +1020,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.2.0 + 3.3.0 org.openrewrite.recipe From b480bde95bcdc8a49ead0e916536ef3f1676f39e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 05:47:23 +0000 Subject: [PATCH 061/615] Bump com.alibaba.fastjson2:fastjson2 from 2.0.55 to 2.0.56 Bumps [com.alibaba.fastjson2:fastjson2](https://github.com/alibaba/fastjson2) from 2.0.55 to 2.0.56. - [Release notes](https://github.com/alibaba/fastjson2/releases) - [Commits](https://github.com/alibaba/fastjson2/compare/2.0.55...2.0.56) --- updated-dependencies: - dependency-name: com.alibaba.fastjson2:fastjson2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2760deff7f..4a85d31f4e 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ 2.18.2 3.27.3 5.15.2 - 2.0.55 + 2.0.56 5.3 3.13.0 From 68f332a496e8522d33c571dc86be499edc4ec22e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2025 05:55:48 +0000 Subject: [PATCH 062/615] Bump org.apache.maven.plugins:maven-compiler-plugin Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.13.0 to 3.14.0. - [Release notes](https://github.com/apache/maven-compiler-plugin/releases) - [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.13.0...maven-compiler-plugin-3.14.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-compiler-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4a85d31f4e..30f7beb9da 100644 --- a/pom.xml +++ b/pom.xml @@ -184,7 +184,7 @@ 2.0.56 5.3 - 3.13.0 + 3.14.0 3.1.3 3.3.1 3.11.2 From 2bfebc94862d5567d6fbda9148aaed639fab40fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 05:52:49 +0000 Subject: [PATCH 063/615] Bump com.google.http-client:google-http-client from 1.46.1 to 1.46.2 Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 1.46.1 to 1.46.2. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v1.46.1...v1.46.2) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 30f7beb9da..505d4be2fd 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 4.12.0 33.4.0-jre - 1.46.1 + 1.46.2 2.12.1 1.15.2 2.0.16 From 975a62ad8485af0ce5b4a28046eb0c6bf9345b59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 06:01:03 +0000 Subject: [PATCH 064/615] Bump com.gradle:develocity-maven-extension from 1.23.1 to 1.23.2 Bumps com.gradle:develocity-maven-extension from 1.23.1 to 1.23.2. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 2e1c55bed6..0938661971 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 1.23.1 + 1.23.2 com.gradle From 382bf5a285c0ac0bdb4f0f968c03e68bf6f6d8fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Feb 2025 05:12:57 +0000 Subject: [PATCH 065/615] Bump com.google.http-client:google-http-client from 1.46.2 to 1.46.3 Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 1.46.2 to 1.46.3. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v1.46.2...v1.46.3) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 505d4be2fd..2572adc06f 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 4.12.0 33.4.0-jre - 1.46.2 + 1.46.3 2.12.1 1.15.2 2.0.16 From f1bfed944cb2a990b24fa6dcbd4d2af294e131bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Feb 2025 05:21:15 +0000 Subject: [PATCH 066/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.2.0 to 6.2.1 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.2.0 to 6.2.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.2.0...v6.2.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2572adc06f..e5a20424b8 100644 --- a/pom.xml +++ b/pom.xml @@ -1014,7 +1014,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.2.0 + 6.2.1 From 94d9773058a32914321c873a10a2840cf7cf2ff4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Feb 2025 05:23:42 +0000 Subject: [PATCH 067/615] Bump slf4j.version from 2.0.16 to 2.0.17 Bumps `slf4j.version` from 2.0.16 to 2.0.17. Updates `org.slf4j:slf4j-simple` from 2.0.16 to 2.0.17 Updates `org.slf4j:slf4j-nop` from 2.0.16 to 2.0.17 Updates `org.slf4j:slf4j-api` from 2.0.16 to 2.0.17 Updates `org.slf4j:slf4j-jdk14` from 2.0.16 to 2.0.17 --- updated-dependencies: - dependency-name: org.slf4j:slf4j-simple dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: org.slf4j:slf4j-nop dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.slf4j:slf4j-api dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: org.slf4j:slf4j-jdk14 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e5a20424b8..239075575b 100644 --- a/pom.xml +++ b/pom.xml @@ -173,7 +173,7 @@ 1.46.3 2.12.1 1.15.2 - 2.0.16 + 2.0.17 20250107 3.3.5 From 80e73aba25b022da1247c968b68c9607155c85d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 05:18:00 +0000 Subject: [PATCH 068/615] Bump org.apache.maven.plugins:maven-deploy-plugin from 3.1.3 to 3.1.4 Bumps [org.apache.maven.plugins:maven-deploy-plugin](https://github.com/apache/maven-deploy-plugin) from 3.1.3 to 3.1.4. - [Release notes](https://github.com/apache/maven-deploy-plugin/releases) - [Commits](https://github.com/apache/maven-deploy-plugin/compare/maven-deploy-plugin-3.1.3...maven-deploy-plugin-3.1.4) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-deploy-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 239075575b..8057653400 100644 --- a/pom.xml +++ b/pom.xml @@ -199,7 +199,7 @@ 2.1.0 2.18.0 3.2.7 - 3.1.3 + 3.1.4 1.2.2 1.2.2.Final From 1d91b7d4454364c72d511d174bb9c0e78316bd1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2025 05:26:14 +0000 Subject: [PATCH 069/615] Bump netty.version from 4.1.118.Final to 4.1.119.Final Bumps `netty.version` from 4.1.118.Final to 4.1.119.Final. Updates `io.netty:netty-bom` from 4.1.118.Final to 4.1.119.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.118.Final...netty-4.1.119.Final) Updates `io.netty:netty-handler` from 4.1.118.Final to 4.1.119.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.118.Final...netty-4.1.119.Final) Updates `io.netty:netty-codec-http` from 4.1.118.Final to 4.1.119.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.118.Final...netty-4.1.119.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index f7031eeb84..fecfa50c57 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.1.118.Final + 4.1.119.Final true From 4f92b365a7df3a4abd6428aa7e2b283f751ffa90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 05:21:57 +0000 Subject: [PATCH 070/615] Bump org.apache.maven.plugins:maven-install-plugin from 3.1.3 to 3.1.4 Bumps [org.apache.maven.plugins:maven-install-plugin](https://github.com/apache/maven-install-plugin) from 3.1.3 to 3.1.4. - [Release notes](https://github.com/apache/maven-install-plugin/releases) - [Commits](https://github.com/apache/maven-install-plugin/compare/maven-install-plugin-3.1.3...maven-install-plugin-3.1.4) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-install-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8057653400..0b29e24a91 100644 --- a/pom.xml +++ b/pom.xml @@ -185,7 +185,7 @@ 5.3 3.14.0 - 3.1.3 + 3.1.4 3.3.1 3.11.2 4.6 From 46de6732e1c086f1e61cd2168f79b23136cd74c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 05:30:11 +0000 Subject: [PATCH 071/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.2.1 to 6.2.2 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.2.1 to 6.2.2. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.2.1...v6.2.2) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0b29e24a91..fbaf6de25c 100644 --- a/pom.xml +++ b/pom.xml @@ -1014,7 +1014,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.2.1 + 6.2.2 From 6451e9972afed39dc4d47b60c72d56e00fb38041 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 05:17:18 +0000 Subject: [PATCH 072/615] Bump jackson.version from 2.18.2 to 2.18.3 Bumps `jackson.version` from 2.18.2 to 2.18.3. Updates `com.fasterxml.jackson.core:jackson-databind` from 2.18.2 to 2.18.3 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.core:jackson-core` from 2.18.2 to 2.18.3 - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.18.2...jackson-core-2.18.3) Updates `com.fasterxml.jackson.core:jackson-annotations` from 2.18.2 to 2.18.3 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.jr:jackson-jr-objects` from 2.18.2 to 2.18.3 - [Commits](https://github.com/FasterXML/jackson-jr/compare/jackson-jr-parent-2.18.2...jackson-jr-parent-2.18.3) Updates `com.fasterxml.jackson.jr:jackson-jr-annotation-support` from 2.18.2 to 2.18.3 - [Commits](https://github.com/FasterXML/jackson-jr/compare/jackson-jr-parent-2.18.2...jackson-jr-parent-2.18.3) Updates `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider` from 2.18.2 to 2.18.3 --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jr:jackson-jr-objects dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jr:jackson-jr-annotation-support dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fbaf6de25c..740c86e5c5 100644 --- a/pom.xml +++ b/pom.xml @@ -178,7 +178,7 @@ 3.3.5 5.11.4 - 2.18.2 + 2.18.3 3.27.3 5.15.2 2.0.56 From 1ac87e722d707b59f8f450d3ac8054121e824a05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 05:17:45 +0000 Subject: [PATCH 073/615] Bump com.fasterxml.jackson:jackson-bom from 2.18.2 to 2.18.3 Bumps [com.fasterxml.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 2.18.2 to 2.18.3. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.2...jackson-bom-2.18.3) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/pom.xml b/vertx/pom.xml index aa04c46e51..6b47910762 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -31,7 +31,7 @@ 4.5.13 - 2.18.2 + 2.18.3 2.0.0-alpha6 2.35.2 From ee7291044b3d677e14c9a1942cec9d818d5583e6 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 3 Mar 2025 10:35:13 -0300 Subject: [PATCH 074/615] Unify jackson version --- vertx/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/vertx/pom.xml b/vertx/pom.xml index 6b47910762..b7b500b240 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -31,7 +31,6 @@ 4.5.13 - 2.18.3 2.0.0-alpha6 2.35.2 From 7e360f6be5f9156d698ed1d03e4ae1d32d54d90d Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 3 Mar 2025 11:03:49 -0300 Subject: [PATCH 075/615] Fix test assertion Signed-off-by: Marvin Froeder --- .../src/test/java/feign/http2client/test/Http2ClientTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientTest.java index 806b9321a5..6f6db9b698 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientTest.java @@ -152,7 +152,7 @@ void getWithRequestBody() { final TestInterface api = newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); String result = api.getWithBody(); - assertThat(result).contains("\"data\": \"some request body\""); + assertThat(result).contains("\"data\":\"some request body\""); } @Test @@ -160,7 +160,7 @@ void deleteWithRequestBody() { final TestInterface api = newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); String result = api.deleteWithBody(); - assertThat(result).contains("\"data\": \"some request body\""); + assertThat(result).contains("\"data\":\"some request body\""); } @Override From be8925a1592db3a1fce10ce1d306dc1185e432a9 Mon Sep 17 00:00:00 2001 From: Alexei KLENIN Date: Mon, 3 Mar 2025 15:05:13 +0100 Subject: [PATCH 076/615] Update README.md (#2765) Add the build status badge and make it shine :) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3474f34e9d..fe0d7fc1bd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Feign simplifies the process of writing Java HTTP clients [![Join the chat at https://gitter.im/OpenFeign/feign](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/OpenFeign/feign?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![CI](https://github.com/OpenFeign/feign/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/OpenFeign/feign/actions/workflows/build.yml) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.openfeign/feign-core/badge.png)](https://search.maven.org/artifact/io.github.openfeign/feign-core/) Feign is a Java to HTTP client binder inspired by [Retrofit](https://github.com/square/retrofit), [JAXRS-2.0](https://jax-rs-spec.java.net/nonav/2.0/apidocs/index.html), and [WebSocket](http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html). Feign's first goal was reducing the complexity of binding [Denominator](https://github.com/Netflix/Denominator) uniformly to HTTP APIs regardless of [ReSTfulness](http://www.slideshare.net/adrianfcole/99problems). From 4a438b9a533ef873b9152e56d002ea984d464dc2 Mon Sep 17 00:00:00 2001 From: Alexei KLENIN Date: Mon, 3 Mar 2025 15:09:27 +0100 Subject: [PATCH 077/615] FEATURE: base feign-vertx on Vertx WebClient instead of bare vertx (#2756) * FEATURE: base feign-vertx on Vertx WebClient instead of bare vertx * REFACTOR: vertx tests --- pom.xml | 6 + vertx/README.md | 13 +- vertx/feign-vertx/pom.xml | 143 ++++++++ .../src/main/java/feign/VertxFeign.java | 72 ++-- .../java/feign/VertxInvocationHandler.java | 0 .../main/java/feign/VertxMethodHandler.java | 0 .../src/main/java/feign/package-info.java | 0 .../feign/vertx/VertxDelegatingContract.java | 0 .../java/feign/vertx/VertxHttpClient.java | 76 ++-- .../vertx/AbstractClientReconnectTest.java | 131 +++++++ .../feign/vertx/AbstractFeignVertxTest.java | 0 .../feign/vertx/ConnectionsLeakTests.java | 130 +++++++ .../vertx/Http11ClientReconnectTest.java | 46 +++ .../feign/vertx/Http2ClientReconnectTest.java | 47 +++ .../java/feign/vertx/QueryMapEncoderTest.java | 10 +- .../java/feign/vertx/RawContractTest.java | 3 +- .../feign/vertx/RequestPreProcessorTest.java | 15 +- .../test/java/feign/vertx/RetryingTest.java | 3 +- .../src/test/java/feign/vertx/TestUtils.java | 6 +- .../java/feign/vertx/TimeoutHandlingTest.java | 9 +- .../java/feign/vertx/VertxHttpClientTest.java | 20 +- .../feign/vertx/VertxHttpOptionsTest.java | 115 ++++++ .../feign/vertx/testcase/HelloServiceAPI.java | 0 .../vertx/testcase/IcecreamServiceApi.java | 0 .../testcase/IcecreamServiceApiBroken.java | 3 +- .../feign/vertx/testcase/RawServiceAPI.java | 0 .../feign/vertx/testcase/domain/Bill.java | 0 .../feign/vertx/testcase/domain/Flavor.java | 0 .../vertx/testcase/domain/IceCreamOrder.java | 0 .../feign/vertx/testcase/domain/Mixin.java | 0 .../vertx/testcase/domain/OrderGenerator.java | 0 .../src/test/resources/log4j.properties | 0 vertx/feign-vertx4-test/pom.xml | 115 ++++++ vertx/{ => feign-vertx4-test}/run-tests.zsh | 12 +- .../vertx/AbstractClientReconnectTest.java | 0 .../feign/vertx/AbstractFeignVertxTest.java | 44 +++ .../feign/vertx/ConnectionsLeakTests.java | 38 +- .../vertx/Http11ClientReconnectTest.java | 9 +- .../feign/vertx/Http2ClientReconnectTest.java | 11 +- .../java/feign/vertx/QueryMapEncoderTest.java | 121 +++++++ .../java/feign/vertx/RawContractTest.java | 125 +++++++ .../feign/vertx/RequestPreProcessorTest.java | 92 +++++ .../test/java/feign/vertx/RetryingTest.java | 141 ++++++++ .../java/feign/vertx/TimeoutHandlingTest.java | 125 +++++++ .../java/feign/vertx/VertxHttpClientTest.java | 330 ++++++++++++++++++ .../feign/vertx/VertxHttpOptionsTest.java | 23 +- vertx/feign-vertx5-test/pom.xml | 128 +++++++ vertx/feign-vertx5-test/run-tests.zsh | 38 ++ vertx/pom.xml | 106 ++---- 49 files changed, 2058 insertions(+), 248 deletions(-) create mode 100644 vertx/feign-vertx/pom.xml rename vertx/{ => feign-vertx}/src/main/java/feign/VertxFeign.java (86%) rename vertx/{ => feign-vertx}/src/main/java/feign/VertxInvocationHandler.java (100%) rename vertx/{ => feign-vertx}/src/main/java/feign/VertxMethodHandler.java (100%) rename vertx/{ => feign-vertx}/src/main/java/feign/package-info.java (100%) rename vertx/{ => feign-vertx}/src/main/java/feign/vertx/VertxDelegatingContract.java (100%) rename vertx/{ => feign-vertx}/src/main/java/feign/vertx/VertxHttpClient.java (62%) create mode 100644 vertx/feign-vertx/src/test/java/feign/vertx/AbstractClientReconnectTest.java rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/AbstractFeignVertxTest.java (100%) create mode 100644 vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java create mode 100644 vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java create mode 100644 vertx/feign-vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/QueryMapEncoderTest.java (92%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/RawContractTest.java (97%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/RequestPreProcessorTest.java (86%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/RetryingTest.java (98%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/TestUtils.java (87%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/TimeoutHandlingTest.java (93%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/VertxHttpClientTest.java (94%) create mode 100644 vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/testcase/HelloServiceAPI.java (100%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/testcase/IcecreamServiceApi.java (100%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/testcase/IcecreamServiceApiBroken.java (94%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/testcase/RawServiceAPI.java (100%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/testcase/domain/Bill.java (100%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/testcase/domain/Flavor.java (100%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/testcase/domain/IceCreamOrder.java (100%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/testcase/domain/Mixin.java (100%) rename vertx/{ => feign-vertx}/src/test/java/feign/vertx/testcase/domain/OrderGenerator.java (100%) rename vertx/{ => feign-vertx}/src/test/resources/log4j.properties (100%) create mode 100644 vertx/feign-vertx4-test/pom.xml rename vertx/{ => feign-vertx4-test}/run-tests.zsh (74%) rename vertx/{ => feign-vertx4-test}/src/test/java/feign/vertx/AbstractClientReconnectTest.java (100%) create mode 100644 vertx/feign-vertx4-test/src/test/java/feign/vertx/AbstractFeignVertxTest.java rename vertx/{ => feign-vertx4-test}/src/test/java/feign/vertx/ConnectionsLeakTests.java (76%) rename vertx/{ => feign-vertx4-test}/src/test/java/feign/vertx/Http11ClientReconnectTest.java (83%) rename vertx/{ => feign-vertx4-test}/src/test/java/feign/vertx/Http2ClientReconnectTest.java (80%) create mode 100644 vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java create mode 100644 vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java create mode 100644 vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java create mode 100644 vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java create mode 100644 vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java create mode 100644 vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java rename vertx/{ => feign-vertx4-test}/src/test/java/feign/vertx/VertxHttpOptionsTest.java (86%) create mode 100644 vertx/feign-vertx5-test/pom.xml create mode 100755 vertx/feign-vertx5-test/run-tests.zsh diff --git a/pom.xml b/pom.xml index fbaf6de25c..6a98cdb62d 100644 --- a/pom.xml +++ b/pom.xml @@ -357,6 +357,12 @@ ${project.version} + + ${project.groupId} + feign-vertx + ${project.version} + + ${project.groupId} feign-micrometer diff --git a/vertx/README.md b/vertx/README.md index b077fe0010..4e89037acc 100644 --- a/vertx/README.md +++ b/vertx/README.md @@ -2,7 +2,7 @@ Implementation of Feign on Vertx. Brings you the best of two worlds together : concise syntax of Feign to write client side API on fast, asynchronous and -non-blocking HTTP client of Vertx. +non-blocking WebClient of Vertx. ## Installation @@ -14,7 +14,6 @@ non-blocking HTTP client of Vertx. io.github.openfeign feign-vertx - 14.0 ... @@ -23,14 +22,14 @@ non-blocking HTTP client of Vertx. ### With Gradle ```groovy -compile group: 'io.github.openfeign', name: 'feign-vertx', version: '14.0' +compile group: 'io.github.openfeign', name: 'feign-vertx' ``` ## Compatibility Feign | Vertx ---------------------- | ---------------------- -14.x | 4.x +14.x | 4.x - 5.x ## Usage @@ -62,15 +61,15 @@ interface IcecreamServiceApi { Build the client : ```java -Vertx vertx = Vertx.vertx(); // get Vertx instance +WebClient webClient = WebClient.create(vertx); // create Vert.x WebClient /* Create instance of your API */ IcecreamServiceApi icecreamApi = VertxFeign .builder() - .vertx(vertx) // provide vertx instance + .webClient(webClient) // provide WebClient instance .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) - .target(IcecreamServiceApi.class, "http://www.icecreame.com"); + .target(IcecreamServiceApi.class, "https://www.icecream.com"); /* Execute requests asynchronously */ Future> flavorsFuture = icecreamApi.getAvailableFlavors(); diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml new file mode 100644 index 0000000000..648c7cbeb0 --- /dev/null +++ b/vertx/feign-vertx/pom.xml @@ -0,0 +1,143 @@ + + + + 4.0.0 + + io.github.openfeign + feign-vertx-parent + 13.6-SNAPSHOT + + + feign-vertx + + Feign Vertx + Implementation of Feign on Vertx web client. + + + 2.18.2 + + + + + + com.fasterxml.jackson + jackson-bom + ${jackson.version} + pom + import + + + + + + + + + io.github.openfeign + feign-core + + + + + io.vertx + vertx-core + ${vertx.version} + provided + + + + io.vertx + vertx-web-client + ${vertx.version} + provided + + + + + io.vertx + vertx-junit5 + ${vertx.version} + test + + + + org.assertj + assertj-core + test + + + + io.github.openfeign + feign-jackson + test + + + + com.fasterxml.jackson.core + jackson-annotations + test + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + test + + + + io.github.openfeign + feign-slf4j + test + + + + org.slf4j + slf4j-log4j12 + test + + + + com.github.tomakehurst + wiremock-jre8 + test + + + org.junit + junit-bom + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + + + diff --git a/vertx/src/main/java/feign/VertxFeign.java b/vertx/feign-vertx/src/main/java/feign/VertxFeign.java similarity index 86% rename from vertx/src/main/java/feign/VertxFeign.java rename to vertx/feign-vertx/src/main/java/feign/VertxFeign.java index df3e8706a7..e03e6e26a4 100644 --- a/vertx/src/main/java/feign/VertxFeign.java +++ b/vertx/feign-vertx/src/main/java/feign/VertxFeign.java @@ -25,10 +25,9 @@ import feign.querymap.FieldQueryMapEncoder; import feign.vertx.VertxDelegatingContract; import feign.vertx.VertxHttpClient; -import io.vertx.core.Vertx; -import io.vertx.core.http.HttpClient; -import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.http.HttpClientRequest; +import io.vertx.core.buffer.Buffer; +import io.vertx.ext.web.client.HttpRequest; +import io.vertx.ext.web.client.WebClient; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; @@ -92,7 +91,7 @@ public T newInstance(final Target target) { /** VertxFeign builder. */ public static final class Builder extends Feign.Builder { - private Vertx vertx; + private WebClient webClient; private final List requestInterceptors = new ArrayList<>(); private Logger.Level logLevel = Logger.Level.NONE; private Contract contract = new VertxDelegatingContract(new Contract.Default()); @@ -103,10 +102,9 @@ public static final class Builder extends Feign.Builder { private QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder(); private List capabilities = new ArrayList<>(); private ErrorDecoder errorDecoder = new ErrorDecoder.Default(); - private HttpClientOptions options = new HttpClientOptions(); private long timeout = -1; private boolean decode404; - private UnaryOperator requestPreProcessor = UnaryOperator.identity(); + private UnaryOperator> requestPreProcessor = UnaryOperator.identity(); /** Unsupported operation. */ @Override @@ -122,13 +120,13 @@ public Builder invocationHandlerFactory( } /** - * Sets a vertx instance to use to make the client. + * Sets a vertx WebClient. * - * @param vertx vertx instance + * @param webClient vertx WebClient * @return this builder */ - public Builder vertx(final Vertx vertx) { - this.vertx = checkNotNull(vertx, "Argument vertx must be not null"); + public Builder webClient(final WebClient webClient) { + this.webClient = checkNotNull(webClient, "Argument webClient must be not null"); return this; } @@ -263,34 +261,6 @@ public Builder errorDecoder(final ErrorDecoder errorDecoder) { return this; } - /** - * Sets request options using Vert.x {@link HttpClientOptions}. - * - * @param options {@code HttpClientOptions} for full customization of the underlying Vert.x - * {@link HttpClient} - * @return this builder - */ - public Builder options(final HttpClientOptions options) { - this.options = checkNotNull(options, "Argument options must be not null"); - return this; - } - - /** - * Sets request options using Feign {@link Request.Options}. - * - * @param options Feign {@code Request.Options} object - * @return this builder - */ - @Override - public Builder options(final Request.Options options) { - checkNotNull(options, "Argument options must be not null"); - this.options = - new HttpClientOptions() - .setConnectTimeout(options.connectTimeoutMillis()) - .setIdleTimeout(options.readTimeoutMillis()); - return this; - } - /** * Configures the amount of time in milliseconds after which if the request does not return any * data within the timeout period an {@link java.util.concurrent.TimeoutException} fails the @@ -307,8 +277,8 @@ public Builder timeout(long timeout) { } /** - * Defines operation to execute on each {@link HttpClientRequest} before it is sent. Used to - * make setup on request level. + * Defines operation to execute on each {@link HttpRequest} before it sent. Used to make setup + * on request level. * *

Example: * @@ -316,13 +286,13 @@ public Builder timeout(long timeout) { * var client = VertxFeign * .builder() * .vertx(vertx) - * .requestPreProcessor(req -> req.putHeader("version", "v1")); + * .requestPreProcessor(req -> req.ssl(true)); * * * @param requestPreProcessor operation to execute on each request * @return updated request */ - public Builder requestPreProcessor(UnaryOperator requestPreProcessor) { + public Builder requestPreProcessor(UnaryOperator> requestPreProcessor) { this.requestPreProcessor = checkNotNull(requestPreProcessor, "Argument requestPreProcessor must be not null"); return this; @@ -389,19 +359,24 @@ public T target(final Target target) { return build().newInstance(target); } + @Override + public Feign.Builder options(final Request.Options options) { + throw new UnsupportedOperationException( + "Options should be provided directly during construction of Vertx WebClient."); + } + @Override public VertxFeign internalBuild() { - checkNotNull(this.vertx, "Vertx instance wasn't provided in VertxFeign builder"); + checkNotNull( + this.webClient, "Vertx WebClient instance wasn't provided in VertxFeign builder"); - final VertxHttpClient client = - new VertxHttpClient(vertx, options, timeout, requestPreProcessor); + final VertxHttpClient client = new VertxHttpClient(webClient, timeout, requestPreProcessor); final VertxMethodHandler.Factory methodHandlerFactory = new VertxMethodHandler.Factory( client, retryer, requestInterceptors, logger, logLevel, decode404); final ParseHandlersByName handlersByName = new ParseHandlersByName( contract, - options, encoder, decoder, queryMapEncoder, @@ -417,7 +392,6 @@ public VertxFeign internalBuild() { private static final class ParseHandlersByName { private final Contract contract; - private final HttpClientOptions options; private final Encoder encoder; private final Decoder decoder; private final QueryMapEncoder queryMapEncoder; @@ -427,7 +401,6 @@ private static final class ParseHandlersByName { private ParseHandlersByName( final Contract contract, - final HttpClientOptions options, final Encoder encoder, final Decoder decoder, final QueryMapEncoder queryMapEncoder, @@ -435,7 +408,6 @@ private ParseHandlersByName( final ErrorDecoder errorDecoder, final VertxMethodHandler.Factory factory) { this.contract = contract; - this.options = options; this.factory = factory; this.encoder = encoder; this.decoder = decoder; diff --git a/vertx/src/main/java/feign/VertxInvocationHandler.java b/vertx/feign-vertx/src/main/java/feign/VertxInvocationHandler.java similarity index 100% rename from vertx/src/main/java/feign/VertxInvocationHandler.java rename to vertx/feign-vertx/src/main/java/feign/VertxInvocationHandler.java diff --git a/vertx/src/main/java/feign/VertxMethodHandler.java b/vertx/feign-vertx/src/main/java/feign/VertxMethodHandler.java similarity index 100% rename from vertx/src/main/java/feign/VertxMethodHandler.java rename to vertx/feign-vertx/src/main/java/feign/VertxMethodHandler.java diff --git a/vertx/src/main/java/feign/package-info.java b/vertx/feign-vertx/src/main/java/feign/package-info.java similarity index 100% rename from vertx/src/main/java/feign/package-info.java rename to vertx/feign-vertx/src/main/java/feign/package-info.java diff --git a/vertx/src/main/java/feign/vertx/VertxDelegatingContract.java b/vertx/feign-vertx/src/main/java/feign/vertx/VertxDelegatingContract.java similarity index 100% rename from vertx/src/main/java/feign/vertx/VertxDelegatingContract.java rename to vertx/feign-vertx/src/main/java/feign/vertx/VertxDelegatingContract.java diff --git a/vertx/src/main/java/feign/vertx/VertxHttpClient.java b/vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java similarity index 62% rename from vertx/src/main/java/feign/vertx/VertxHttpClient.java rename to vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java index 5e545c6d84..0b196b6ffb 100644 --- a/vertx/src/main/java/feign/vertx/VertxHttpClient.java +++ b/vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java @@ -20,11 +20,12 @@ import feign.Request; import feign.Response; import io.vertx.core.Future; -import io.vertx.core.MultiMap; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.*; -import io.vertx.core.http.impl.headers.HeadersMultiMap; +import io.vertx.ext.web.client.HttpRequest; +import io.vertx.ext.web.client.HttpResponse; +import io.vertx.ext.web.client.WebClient; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; @@ -43,28 +44,25 @@ */ @SuppressWarnings("unused") public final class VertxHttpClient { - private final HttpClient httpClient; + private final WebClient webClient; private final long timeout; - private final UnaryOperator requestPreProcessor; + private final UnaryOperator> requestPreProcessor; /** * Constructor from {@link Vertx} instance, HTTP client options and request timeout. * - * @param vertx vertx instance - * @param options HTTP options + * @param webClient vertx WebClient * @param timeout request timeout * @param requestPreProcessor request pre-processor */ public VertxHttpClient( - final Vertx vertx, - final HttpClientOptions options, + final WebClient webClient, final long timeout, - final UnaryOperator requestPreProcessor) { - checkNotNull(vertx, "Argument vertx must not be null"); - checkNotNull(options, "Argument options must be not null"); + final UnaryOperator> requestPreProcessor) { + checkNotNull(webClient, "Argument webClient must not be null"); checkNotNull(requestPreProcessor, "Argument requestPreProcessor must be not null"); - this.httpClient = vertx.createHttpClient(options); + this.webClient = webClient; this.timeout = timeout; this.requestPreProcessor = requestPreProcessor; } @@ -78,7 +76,7 @@ public VertxHttpClient( public Future execute(final Request request) { checkNotNull(request, "Argument request must be not null"); - final Future httpClientRequest; + final HttpRequest httpClientRequest; try { httpClientRequest = makeHttpClientRequest(request); @@ -86,9 +84,10 @@ public Future execute(final Request request) { return Future.failedFuture(unexpectedException); } - final Future responseFuture = - httpClientRequest.compose( - req -> request.body() != null ? req.send(Buffer.buffer(request.body())) : req.send()); + final Future> responseFuture = + request.body() != null + ? httpClientRequest.sendBuffer(Buffer.buffer(request.body())) + : httpClientRequest.send(); return responseFuture.compose( response -> { @@ -100,21 +99,20 @@ public Future execute(final Request request) { Collectors.mapping( Map.Entry::getValue, Collectors.toCollection(ArrayList::new)))); - return response - .body() - .map( - body -> - Response.builder() - .status(response.statusCode()) - .reason(response.statusMessage()) - .headers(responseHeaders) - .body(body.getBytes()) - .request(request) - .build()); + byte[] body = response.body() != null ? response.body().getBytes() : null; + + return Future.succeededFuture( + Response.builder() + .status(response.statusCode()) + .reason(response.statusMessage()) + .headers(responseHeaders) + .body(body) + .request(request) + .build()); }); } - private Future makeHttpClientRequest(final Request request) + private HttpRequest makeHttpClientRequest(final Request request) throws MalformedURLException { final URL url = new URL(request.url()); final String host = url.getHost(); @@ -129,20 +127,16 @@ private Future makeHttpClientRequest(final Request request) port = HttpClientOptions.DEFAULT_DEFAULT_PORT; } - final HttpMethod httpMethod = HttpMethod.valueOf(request.httpMethod().name()); - - final MultiMap headers = new HeadersMultiMap(); - request.headers().forEach((key, values) -> values.forEach(value -> headers.add(key, value))); + HttpRequest httpClientRequest = + webClient + .request(HttpMethod.valueOf(request.httpMethod().name()), port, host, requestUri) + .timeout(timeout); - final RequestOptions requestOptions = - new RequestOptions() - .setMethod(httpMethod) - .setHost(host) - .setPort(port) - .setURI(requestUri) - .setTimeout(timeout) - .setHeaders(headers); + /* Add headers to request */ + for (final Map.Entry> header : request.headers().entrySet()) { + httpClientRequest = httpClientRequest.putHeader(header.getKey(), header.getValue()); + } - return this.httpClient.request(requestOptions).map(requestPreProcessor); + return requestPreProcessor.apply(httpClientRequest); } } diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/AbstractClientReconnectTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/AbstractClientReconnectTest.java new file mode 100644 index 0000000000..9f9a809ac6 --- /dev/null +++ b/vertx/feign-vertx/src/test/java/feign/vertx/AbstractClientReconnectTest.java @@ -0,0 +1,131 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.WireMockServer; +import feign.vertx.testcase.HelloServiceAPI; +import io.vertx.core.AsyncResult; +import io.vertx.core.CompositeFuture; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.junit5.VertxTestContext; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.junit.jupiter.api.*; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +abstract class AbstractClientReconnectTest extends AbstractFeignVertxTest { + static String baseUrl; + static int serverPort; + + HelloServiceAPI client = null; + + @BeforeAll + static void setupMockServer() { + serverPort = wireMock.port(); + baseUrl = wireMock.baseUrl(); + wireMock.stubFor(get(anyUrl()).willReturn(aResponse().withStatus(200))); + } + + @BeforeAll + protected abstract void createClient(Vertx vertx); + + @Test + @DisplayName("All requests should be answered") + void allRequestsShouldBeAnswered(VertxTestContext testContext) { + sendRequests(10).compose(responses -> assertAllRequestsAnswered(responses, testContext)); + } + + @Nested + @DisplayName("After server has became unavailable") + class AfterServerBecameUnavailable { + + @BeforeEach + void shutDownServer() { + wireMock.stop(); + } + + @Test + @DisplayName("All requests should fail") + void allRequestsShouldFail(VertxTestContext testContext) { + sendRequests(10) + .onComplete( + responses -> + testContext.verify( + () -> { + if (responses.succeeded()) { + testContext.failNow( + new IllegalStateException( + "Client should not get responses from unavailable server")); + } + + try { + assertThat(responses.cause().getMessage()).startsWith("Connection "); + testContext.completeNow(); + } catch (Throwable assertionException) { + testContext.failNow(assertionException); + } + })); + } + + @Nested + @DisplayName("After server is available again") + class AfterServerIsBack { + WireMockServer restartedServer = new WireMockServer(options().port(serverPort)); + + @BeforeEach + void restartServer() { + restartedServer.start(); + restartedServer.stubFor(get(anyUrl()).willReturn(aResponse().withStatus(200))); + } + + @AfterEach + void shutDownServer() { + restartedServer.stop(); + } + + @Test + @DisplayName("All requests should be answered") + void allRequestsShouldBeAnswered(VertxTestContext testContext) { + sendRequests(10).compose(responses -> assertAllRequestsAnswered(responses, testContext)); + } + } + } + + CompositeFuture sendRequests(int requests) { + List> requestList = + IntStream.range(0, requests) + .mapToObj(ignored -> client.hello()) + .collect(Collectors.toList()); + return Future.all(requestList); + } + + Future assertAllRequestsAnswered( + AsyncResult responses, VertxTestContext testContext) { + if (responses.succeeded()) { + testContext.completeNow(); + return Future.succeededFuture(); + } else { + testContext.failNow(responses.cause()); + return Future.failedFuture(responses.cause()); + } + } +} diff --git a/vertx/src/test/java/feign/vertx/AbstractFeignVertxTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/AbstractFeignVertxTest.java similarity index 100% rename from vertx/src/test/java/feign/vertx/AbstractFeignVertxTest.java rename to vertx/feign-vertx/src/test/java/feign/vertx/AbstractFeignVertxTest.java diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java b/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java new file mode 100644 index 0000000000..4d236f1cbc --- /dev/null +++ b/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java @@ -0,0 +1,130 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import static java.util.stream.Collectors.toList; +import static org.assertj.core.api.Assertions.assertThat; + +import feign.VertxFeign; +import feign.jackson.JacksonDecoder; +import feign.jackson.JacksonEncoder; +import feign.vertx.testcase.HelloServiceAPI; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.core.http.*; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; +import io.vertx.junit5.VertxExtension; +import io.vertx.junit5.VertxTestContext; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.IntStream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(VertxExtension.class) +@DisplayName("Test that connections does not leak") +class ConnectionsLeakTests { + private static final HttpServerOptions serverOptions = + new HttpServerOptions().setLogActivity(true).setPort(8091).setSsl(false); + + HttpServer httpServer; + + private final Set connections = Collections.synchronizedSet(new HashSet<>()); + + @BeforeEach + void initServer(Vertx vertx) { + httpServer = vertx.createHttpServer(serverOptions); + httpServer.requestHandler( + request -> { + if (request.connection() != null) { + this.connections.add(request.connection()); + } + request.response().end("Hello world"); + }); + httpServer.listen(); + } + + @AfterEach + void shutdownServer() { + httpServer.close(); + connections.clear(); + } + + @Test + @DisplayName("when use HTTP 1.1") + void http11NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { + int poolSize = 3; + int nbRequests = 100; + + WebClientOptions options = new WebClientOptions(); + PoolOptions poolOptions = new PoolOptions().setHttp1MaxSize(poolSize); + WebClient webClient = WebClient.create(vertx, options, poolOptions); + + HelloServiceAPI client = + VertxFeign.builder() + .webClient(webClient) + .encoder(new JacksonEncoder()) + .decoder(new JacksonDecoder()) + .target(HelloServiceAPI.class, "http://localhost:8091"); + + assertNotLeaks(client, testContext, nbRequests, poolSize); + } + + @Test + @DisplayName("when use HTTP 2") + void http2NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { + int poolSize = 1; + int nbRequests = 100; + + WebClientOptions options = new WebClientOptions().setProtocolVersion(HttpVersion.HTTP_2); + PoolOptions poolOptions = new PoolOptions().setHttp2MaxSize(1); + WebClient webClient = WebClient.create(vertx, options, poolOptions); + + HelloServiceAPI client = + VertxFeign.builder() + .webClient(webClient) + .encoder(new JacksonEncoder()) + .decoder(new JacksonDecoder()) + .target(HelloServiceAPI.class, "http://localhost:8091"); + + assertNotLeaks(client, testContext, nbRequests, poolSize); + } + + void assertNotLeaks( + HelloServiceAPI client, VertxTestContext testContext, int nbRequests, int poolSize) { + List> futures = + IntStream.range(0, nbRequests).mapToObj(ignored -> client.hello()).collect(toList()); + + Future.all(futures) + .onComplete( + ignored -> + testContext.verify( + () -> { + try { + assertThat(this.connections).hasSize(poolSize); + testContext.completeNow(); + } catch (Throwable assertionFailure) { + testContext.failNow(assertionFailure); + } + })); + } +} diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java new file mode 100644 index 0000000000..fae9a70e9d --- /dev/null +++ b/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java @@ -0,0 +1,46 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import feign.VertxFeign; +import feign.jackson.JacksonDecoder; +import feign.jackson.JacksonEncoder; +import feign.vertx.testcase.HelloServiceAPI; +import io.vertx.core.Vertx; +import io.vertx.core.http.PoolOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("Tests of reconnection with HTTP 1.1") +class Http11ClientReconnectTest extends AbstractClientReconnectTest { + + @BeforeAll + @Override + protected void createClient(final Vertx vertx) { + WebClientOptions options = new WebClientOptions(); + PoolOptions poolOptions = new PoolOptions().setHttp1MaxSize(3); + WebClient webClient = WebClient.create(vertx, options, poolOptions); + + client = + VertxFeign.builder() + .webClient(webClient) + .encoder(new JacksonEncoder()) + .decoder(new JacksonDecoder()) + .target(HelloServiceAPI.class, baseUrl); + } +} diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java new file mode 100644 index 0000000000..cb75fb960a --- /dev/null +++ b/vertx/feign-vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import feign.VertxFeign; +import feign.jackson.JacksonDecoder; +import feign.jackson.JacksonEncoder; +import feign.vertx.testcase.HelloServiceAPI; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpVersion; +import io.vertx.core.http.PoolOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("Tests of reconnection with HTTP 2") +class Http2ClientReconnectTest extends AbstractClientReconnectTest { + + @BeforeAll + @Override + protected void createClient(Vertx vertx) { + WebClientOptions options = new WebClientOptions().setProtocolVersion(HttpVersion.HTTP_2); + PoolOptions poolOptions = new PoolOptions().setHttp2MaxSize(1); + WebClient webClient = WebClient.create(vertx, options, poolOptions); + + client = + VertxFeign.builder() + .webClient(webClient) + .encoder(new JacksonEncoder()) + .decoder(new JacksonDecoder()) + .target(HelloServiceAPI.class, baseUrl); + } +} diff --git a/vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java similarity index 92% rename from vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java rename to vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java index 7e6e4f6d30..39a43a8adb 100644 --- a/vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java @@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat; import feign.*; +import feign.VertxFeign; import feign.jackson.JacksonDecoder; import feign.slf4j.Slf4jLogger; import feign.vertx.testcase.domain.Bill; @@ -26,7 +27,8 @@ import feign.vertx.testcase.domain.IceCreamOrder; import io.vertx.core.Future; import io.vertx.core.Vertx; -import io.vertx.core.http.HttpClientOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; import io.vertx.junit5.VertxTestContext; import java.util.Collections; import java.util.Comparator; @@ -48,11 +50,13 @@ interface Api { @BeforeEach void createClient(Vertx vertx) { + WebClientOptions options = new WebClientOptions().setLogActivity(true); + WebClient webClient = WebClient.create(vertx, options); + client = VertxFeign.builder() - .vertx(vertx) + .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) - .options(new HttpClientOptions().setLogActivity(true)) .queryMapEncoder(new CustomQueryMapEncoder()) .logger(new Slf4jLogger()) .logLevel(Logger.Level.FULL) diff --git a/vertx/src/test/java/feign/vertx/RawContractTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java similarity index 97% rename from vertx/src/test/java/feign/vertx/RawContractTest.java rename to vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java index c08d38b788..48f46b4b49 100644 --- a/vertx/src/test/java/feign/vertx/RawContractTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java @@ -27,6 +27,7 @@ import feign.vertx.testcase.domain.Bill; import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; import io.vertx.junit5.VertxTestContext; import java.io.BufferedReader; import java.io.IOException; @@ -44,7 +45,7 @@ class RawContractTest extends AbstractFeignVertxTest { static void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) + .webClient(WebClient.create(vertx)) .encoder(new JacksonEncoder(TestUtils.MAPPER)) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .target(RawServiceAPI.class, wireMock.baseUrl()); diff --git a/vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java similarity index 86% rename from vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java rename to vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java index b2852a1238..87850cb9e3 100644 --- a/vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java @@ -27,7 +27,8 @@ import feign.vertx.testcase.domain.Flavor; import io.vertx.core.Future; import io.vertx.core.Vertx; -import io.vertx.core.http.HttpClientOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; import io.vertx.junit5.VertxTestContext; import java.util.Arrays; import java.util.Collection; @@ -41,12 +42,14 @@ class RequestPreProcessorTest extends AbstractFeignVertxTest { @BeforeEach void createClient(Vertx vertx) { + WebClientOptions options = new WebClientOptions().setLogActivity(true); + WebClient webClient = WebClient.create(vertx, options); + client = VertxFeign.builder() - .vertx(vertx) - .options(new HttpClientOptions().setLogActivity(true)) + .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) - .requestPreProcessor(req -> req.putHeader("version", "v1")) + .requestPreProcessor(req -> req.addQueryParam("version", "v1")) .logger(new Slf4jLogger()) .logLevel(Logger.Level.FULL) .target(IcecreamServiceApi.class, wireMock.baseUrl()); @@ -58,9 +61,9 @@ void requestPreProcessorMustApply(VertxTestContext testContext) { /* Given */ wireMock.stubFor( - get(urlEqualTo("/icecream/flavors")) + get(urlPathEqualTo("/icecream/flavors")) + .withQueryParam("version", equalTo("v1")) .withHeader("Accept", equalTo("application/json")) - .withHeader("version", equalTo("v1")) .willReturn( aResponse() .withStatus(200) diff --git a/vertx/src/test/java/feign/vertx/RetryingTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java similarity index 98% rename from vertx/src/test/java/feign/vertx/RetryingTest.java rename to vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java index dc657f9f0a..c5ce7cba3b 100644 --- a/vertx/src/test/java/feign/vertx/RetryingTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java @@ -32,6 +32,7 @@ import feign.vertx.testcase.domain.Flavor; import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; import io.vertx.junit5.VertxTestContext; import java.util.Arrays; import java.util.Collection; @@ -47,7 +48,7 @@ class RetryingTest extends AbstractFeignVertxTest { static void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) + .webClient(WebClient.create(vertx)) .decoder(new JacksonDecoder(MAPPER)) .retryer(new Retryer.Default(100, SECONDS.toMillis(1), 5)) .logger(new Slf4jLogger()) diff --git a/vertx/src/test/java/feign/vertx/TestUtils.java b/vertx/feign-vertx/src/test/java/feign/vertx/TestUtils.java similarity index 87% rename from vertx/src/test/java/feign/vertx/TestUtils.java rename to vertx/feign-vertx/src/test/java/feign/vertx/TestUtils.java index 6b9306eb14..96b4779d05 100644 --- a/vertx/src/test/java/feign/vertx/TestUtils.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/TestUtils.java @@ -19,14 +19,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -class TestUtils { - static final ObjectMapper MAPPER = new ObjectMapper(); +public class TestUtils { + public static final ObjectMapper MAPPER = new ObjectMapper(); static { MAPPER.registerModule(new JavaTimeModule()); } - static String encodeAsJsonString(final Object object) { + public static String encodeAsJsonString(final Object object) { try { return MAPPER.writeValueAsString(object); } catch (JsonProcessingException unexpectedException) { diff --git a/vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java similarity index 93% rename from vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java rename to vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java index d6e71af75f..29e7efa6e1 100644 --- a/vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java @@ -27,7 +27,8 @@ import feign.vertx.testcase.domain.Flavor; import io.vertx.core.Future; import io.vertx.core.Vertx; -import io.vertx.core.http.HttpClientOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; import io.vertx.junit5.VertxTestContext; import java.util.Arrays; import java.util.Collection; @@ -42,12 +43,14 @@ class TimeoutHandlingTest extends AbstractFeignVertxTest { @BeforeEach void createClient(Vertx vertx) { + WebClientOptions options = new WebClientOptions().setLogActivity(true); + WebClient webClient = WebClient.create(vertx, options); + client = VertxFeign.builder() - .vertx(vertx) + .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .timeout(1000) - .options(new HttpClientOptions().setLogActivity(true)) .logger(new Slf4jLogger()) .logLevel(Logger.Level.FULL) .target(IcecreamServiceApi.class, wireMock.baseUrl()); diff --git a/vertx/src/test/java/feign/vertx/VertxHttpClientTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java similarity index 94% rename from vertx/src/test/java/feign/vertx/VertxHttpClientTest.java rename to vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java index f47eef3478..eca7765385 100644 --- a/vertx/src/test/java/feign/vertx/VertxHttpClientTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java @@ -23,7 +23,6 @@ import feign.FeignException; import feign.Logger; -import feign.Request; import feign.VertxFeign; import feign.jackson.JacksonDecoder; import feign.jackson.JacksonEncoder; @@ -36,10 +35,11 @@ import feign.vertx.testcase.domain.Mixin; import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; import io.vertx.junit5.VertxTestContext; import java.util.Arrays; import java.util.Collection; -import java.util.concurrent.TimeUnit; import org.assertj.core.api.ThrowableAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -56,11 +56,17 @@ class WhenMakeGetRequest { @BeforeEach void createClient(Vertx vertx) { + WebClientOptions options = + new WebClientOptions() + .setConnectTimeout(5000) + .setIdleTimeout(5000) + .setFollowRedirects(true); + WebClient webClient = WebClient.create(vertx, options); + client = VertxFeign.builder() - .vertx(vertx) + .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) - .options(new Request.Options(5L, TimeUnit.SECONDS, 5L, TimeUnit.SECONDS, true)) .logger(new Slf4jLogger()) .logLevel(Logger.Level.FULL) .target(IcecreamServiceApi.class, wireMock.baseUrl()); @@ -211,7 +217,7 @@ class WhenMakePostRequest { void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) + .webClient(WebClient.create(vertx)) .encoder(new JacksonEncoder(TestUtils.MAPPER)) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .target(IcecreamServiceApi.class, wireMock.baseUrl()); @@ -301,7 +307,7 @@ void whenVertxMissing() { /* Then */ assertThatCode(instantiateContractForgottenVertx) .isInstanceOf(NullPointerException.class) - .hasMessage("Vertx instance wasn't provided in VertxFeign builder"); + .hasMessage("Vertx WebClient instance wasn't provided in VertxFeign builder"); } @Test @@ -312,7 +318,7 @@ void whenTryToInstantiateBrokenContract(Vertx vertx) { ThrowableAssert.ThrowingCallable instantiateBrokenContract = () -> VertxFeign.builder() - .vertx(vertx) + .webClient(WebClient.create(vertx)) .target(IcecreamServiceApiBroken.class, wireMock.baseUrl()); /* Then */ diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java new file mode 100644 index 0000000000..626376a347 --- /dev/null +++ b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java @@ -0,0 +1,115 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static feign.vertx.testcase.domain.Flavor.FLAVORS_JSON; +import static org.assertj.core.api.Assertions.assertThat; + +import feign.Logger; +import feign.VertxFeign; +import feign.jackson.JacksonDecoder; +import feign.slf4j.Slf4jLogger; +import feign.vertx.testcase.IcecreamServiceApi; +import feign.vertx.testcase.domain.Flavor; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpVersion; +import io.vertx.core.http.PoolOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; +import io.vertx.junit5.VertxTestContext; +import java.util.Arrays; +import java.util.Collection; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("FeignVertx client should be created from") +class VertxHttpOptionsTest extends AbstractFeignVertxTest { + + @BeforeAll + static void setupStub() { + wireMock.stubFor( + get(urlEqualTo("/icecream/flavors")) + .withHeader("Accept", equalTo("application/json")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(FLAVORS_JSON))); + } + + @Test + @DisplayName("HttpClientOptions from Vertx") + void httpClientOptions(Vertx vertx, VertxTestContext testContext) { + WebClientOptions options = + new WebClientOptions() + .setProtocolVersion(HttpVersion.HTTP_2) + .setConnectTimeout(5000) + .setIdleTimeout(5000); + PoolOptions poolOptions = new PoolOptions().setHttp2MaxSize(1); + WebClient webClient = WebClient.create(vertx, options, poolOptions); + + IcecreamServiceApi client = + VertxFeign.builder() + .webClient(webClient) + .decoder(new JacksonDecoder(TestUtils.MAPPER)) + .logger(new Slf4jLogger()) + .logLevel(Logger.Level.FULL) + .target(IcecreamServiceApi.class, wireMock.baseUrl()); + + testClient(client, testContext); + } + + @Test + @DisplayName("Request Options from Feign") + void requestOptions(Vertx vertx, VertxTestContext testContext) { + WebClientOptions options = + new WebClientOptions() + .setConnectTimeout(5000) + .setIdleTimeout(5000) + .setFollowRedirects(true); + WebClient webClient = WebClient.create(vertx, options); + + IcecreamServiceApi client = + VertxFeign.builder() + .webClient(webClient) + .decoder(new JacksonDecoder(TestUtils.MAPPER)) + .logger(new Slf4jLogger()) + .logLevel(Logger.Level.FULL) + .target(IcecreamServiceApi.class, wireMock.baseUrl()); + + testClient(client, testContext); + } + + private void testClient(IcecreamServiceApi client, VertxTestContext testContext) { + client + .getAvailableFlavors() + .onComplete( + res -> { + if (res.succeeded()) { + Collection flavors = res.result(); + + assertThat(flavors) + .hasSize(Flavor.values().length) + .containsAll(Arrays.asList(Flavor.values())); + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + }); + } +} diff --git a/vertx/src/test/java/feign/vertx/testcase/HelloServiceAPI.java b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/HelloServiceAPI.java similarity index 100% rename from vertx/src/test/java/feign/vertx/testcase/HelloServiceAPI.java rename to vertx/feign-vertx/src/test/java/feign/vertx/testcase/HelloServiceAPI.java diff --git a/vertx/src/test/java/feign/vertx/testcase/IcecreamServiceApi.java b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/IcecreamServiceApi.java similarity index 100% rename from vertx/src/test/java/feign/vertx/testcase/IcecreamServiceApi.java rename to vertx/feign-vertx/src/test/java/feign/vertx/testcase/IcecreamServiceApi.java diff --git a/vertx/src/test/java/feign/vertx/testcase/IcecreamServiceApiBroken.java b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/IcecreamServiceApiBroken.java similarity index 94% rename from vertx/src/test/java/feign/vertx/testcase/IcecreamServiceApiBroken.java rename to vertx/feign-vertx/src/test/java/feign/vertx/testcase/IcecreamServiceApiBroken.java index d50d7d9b76..44a1a86d71 100644 --- a/vertx/src/test/java/feign/vertx/testcase/IcecreamServiceApiBroken.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/IcecreamServiceApiBroken.java @@ -18,7 +18,6 @@ import feign.Headers; import feign.Param; import feign.RequestLine; -import feign.vertx.VertxDelegatingContract; import feign.vertx.testcase.domain.Bill; import feign.vertx.testcase.domain.Flavor; import feign.vertx.testcase.domain.IceCreamOrder; @@ -28,7 +27,7 @@ /** * API of an iceream web service with one method that doesn't returns {@link Future} and violates - * {@link VertxDelegatingContract}s rules. + * VertxDelegatingContract's rules. * * @author Alexei KLENIN */ diff --git a/vertx/src/test/java/feign/vertx/testcase/RawServiceAPI.java b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/RawServiceAPI.java similarity index 100% rename from vertx/src/test/java/feign/vertx/testcase/RawServiceAPI.java rename to vertx/feign-vertx/src/test/java/feign/vertx/testcase/RawServiceAPI.java diff --git a/vertx/src/test/java/feign/vertx/testcase/domain/Bill.java b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/Bill.java similarity index 100% rename from vertx/src/test/java/feign/vertx/testcase/domain/Bill.java rename to vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/Bill.java diff --git a/vertx/src/test/java/feign/vertx/testcase/domain/Flavor.java b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/Flavor.java similarity index 100% rename from vertx/src/test/java/feign/vertx/testcase/domain/Flavor.java rename to vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/Flavor.java diff --git a/vertx/src/test/java/feign/vertx/testcase/domain/IceCreamOrder.java b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/IceCreamOrder.java similarity index 100% rename from vertx/src/test/java/feign/vertx/testcase/domain/IceCreamOrder.java rename to vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/IceCreamOrder.java diff --git a/vertx/src/test/java/feign/vertx/testcase/domain/Mixin.java b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/Mixin.java similarity index 100% rename from vertx/src/test/java/feign/vertx/testcase/domain/Mixin.java rename to vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/Mixin.java diff --git a/vertx/src/test/java/feign/vertx/testcase/domain/OrderGenerator.java b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/OrderGenerator.java similarity index 100% rename from vertx/src/test/java/feign/vertx/testcase/domain/OrderGenerator.java rename to vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/OrderGenerator.java diff --git a/vertx/src/test/resources/log4j.properties b/vertx/feign-vertx/src/test/resources/log4j.properties similarity index 100% rename from vertx/src/test/resources/log4j.properties rename to vertx/feign-vertx/src/test/resources/log4j.properties diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml new file mode 100644 index 0000000000..828f5b8928 --- /dev/null +++ b/vertx/feign-vertx4-test/pom.xml @@ -0,0 +1,115 @@ + + + + 4.0.0 + + io.github.openfeign + feign-vertx-parent + 13.6-SNAPSHOT + + + feign-vertx4-test + + Feign Vertx (tests with Vertx 4.x) + Tests with Vertx 4.x. + + + 4.5.12 + + + + + + io.github.openfeign + feign-vertx + ${project.version} + tests + test-jar + test + + + + io.github.openfeign + feign-vertx + test + + + + io.vertx + vertx-junit5 + ${vertx.version} + test + + + + io.vertx + vertx-web-client + ${vertx.version} + test + + + + org.assertj + assertj-core + test + + + + io.github.openfeign + feign-jackson + test + + + + com.fasterxml.jackson.core + jackson-annotations + test + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + test + + + + io.github.openfeign + feign-slf4j + test + + + + org.slf4j + slf4j-log4j12 + test + + + + com.github.tomakehurst + wiremock-jre8 + test + + + org.junit + junit-bom + + + + + diff --git a/vertx/run-tests.zsh b/vertx/feign-vertx4-test/run-tests.zsh similarity index 74% rename from vertx/run-tests.zsh rename to vertx/feign-vertx4-test/run-tests.zsh index a0be64ca41..e55d8355a3 100755 --- a/vertx/run-tests.zsh +++ b/vertx/feign-vertx4-test/run-tests.zsh @@ -23,16 +23,6 @@ function print_result() { echo "\t${color}${version} ${mark}${NC}" } -feign_versions=( "12.5" "13.5" ) - -for feign_version in $feign_versions; do - echo "Tests with Feign ${version}:" - - printf "\tRun tests with Feign %s...\n" "${feign_version}" - mvn clean compile test -Dfeign.version="$feign_version" &> /dev/null - print_result "$feign_version" $? -done - declare -A vertx_versions vertx_versions=( [v40x]="4.0.x", [v41x]="4.1.x", [v42x]="4.2.x", [v43x]="4.3.x", [v44x]="4.4.x", [v45x]="4.5.x" ) v40x=( "4.0.2" ) @@ -40,7 +30,7 @@ v41x=( "4.1.8" ) v42x=( "4.2.7" ) v43x=( "4.3.2" ) v44x=( "4.4.9" ) -v45x=( "4.5.10" ) +v45x=( "4.5.12" ) for version in ${(k)vertx_versions}; do echo "Tests with Vertx ${vertx_versions[${version}]}:" diff --git a/vertx/src/test/java/feign/vertx/AbstractClientReconnectTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/AbstractClientReconnectTest.java similarity index 100% rename from vertx/src/test/java/feign/vertx/AbstractClientReconnectTest.java rename to vertx/feign-vertx4-test/src/test/java/feign/vertx/AbstractClientReconnectTest.java diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/AbstractFeignVertxTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/AbstractFeignVertxTest.java new file mode 100644 index 0000000000..3a4ab62649 --- /dev/null +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/AbstractFeignVertxTest.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; + +import com.github.tomakehurst.wiremock.WireMockServer; +import feign.vertx.testcase.domain.OrderGenerator; +import io.vertx.junit5.VertxExtension; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(VertxExtension.class) +public abstract class AbstractFeignVertxTest { + protected static WireMockServer wireMock = new WireMockServer(options().dynamicPort()); + protected static final OrderGenerator generator = new OrderGenerator(); + + @BeforeAll + @DisplayName("Setup WireMock server") + static void setupWireMockServer() { + wireMock.start(); + } + + @AfterAll + @DisplayName("Shutdown WireMock server") + static void shutdownWireMockServer() { + wireMock.stop(); + } +} diff --git a/vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java similarity index 76% rename from vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java rename to vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java index c66f648df7..cc67db08c0 100644 --- a/vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java @@ -25,10 +25,16 @@ import io.vertx.core.CompositeFuture; import io.vertx.core.Future; import io.vertx.core.Vertx; -import io.vertx.core.http.*; -import io.vertx.core.impl.ConcurrentHashSet; +import io.vertx.core.http.HttpConnection; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.core.http.HttpVersion; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; import io.vertx.junit5.VertxExtension; import io.vertx.junit5.VertxTestContext; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.IntStream; @@ -46,7 +52,7 @@ class ConnectionsLeakTests { HttpServer httpServer; - private final Set connections = new ConcurrentHashSet<>(); + private final Set connections = Collections.synchronizedSet(new HashSet<>()); @BeforeEach void initServer(Vertx vertx) { @@ -70,44 +76,44 @@ void shutdownServer() { @Test @DisplayName("when use HTTP 1.1") void http11NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { - int pollSize = 3; + int poolSize = 3; int nbRequests = 100; - HttpClientOptions options = new HttpClientOptions().setMaxPoolSize(pollSize); + WebClientOptions options = new WebClientOptions().setMaxPoolSize(poolSize); + WebClient webClient = WebClient.create(vertx, options); HelloServiceAPI client = VertxFeign.builder() - .vertx(vertx) - .options(options) + .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) .target(HelloServiceAPI.class, "http://localhost:8091"); - assertNotLeaks(client, testContext, nbRequests, pollSize); + assertNotLeaks(client, testContext, nbRequests, poolSize); } @Test @DisplayName("when use HTTP 2") void http2NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { - int pollSize = 1; + int poolSize = 1; int nbRequests = 100; - HttpClientOptions options = - new HttpClientOptions().setProtocolVersion(HttpVersion.HTTP_2).setHttp2MaxPoolSize(1); + WebClientOptions options = + new WebClientOptions().setProtocolVersion(HttpVersion.HTTP_2).setHttp2MaxPoolSize(1); + WebClient webClient = WebClient.create(vertx, options); HelloServiceAPI client = VertxFeign.builder() - .vertx(vertx) - .options(options) + .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) .target(HelloServiceAPI.class, "http://localhost:8091"); - assertNotLeaks(client, testContext, nbRequests, pollSize); + assertNotLeaks(client, testContext, nbRequests, poolSize); } void assertNotLeaks( - HelloServiceAPI client, VertxTestContext testContext, int nbRequests, int pollSize) { + HelloServiceAPI client, VertxTestContext testContext, int nbRequests, int poolSize) { List futures = IntStream.range(0, nbRequests).mapToObj(ignored -> client.hello()).collect(toList()); @@ -117,7 +123,7 @@ void assertNotLeaks( testContext.verify( () -> { try { - assertThat(this.connections).hasSize(pollSize); + assertThat(this.connections).hasSize(poolSize); testContext.completeNow(); } catch (Throwable assertionFailure) { testContext.failNow(assertionFailure); diff --git a/vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java similarity index 83% rename from vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java rename to vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java index da3e6a3fe0..207ae8a89e 100644 --- a/vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java @@ -20,7 +20,8 @@ import feign.jackson.JacksonEncoder; import feign.vertx.testcase.HelloServiceAPI; import io.vertx.core.Vertx; -import io.vertx.core.http.HttpClientOptions; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; @@ -30,12 +31,12 @@ class Http11ClientReconnectTest extends AbstractClientReconnectTest { @BeforeAll @Override protected void createClient(final Vertx vertx) { - HttpClientOptions options = new HttpClientOptions().setMaxPoolSize(3); + WebClientOptions options = new WebClientOptions().setMaxPoolSize(3); + WebClient webClient = WebClient.create(vertx, options); client = VertxFeign.builder() - .vertx(vertx) - .options(options) + .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) .target(HelloServiceAPI.class, baseUrl); diff --git a/vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http2ClientReconnectTest.java similarity index 80% rename from vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java rename to vertx/feign-vertx4-test/src/test/java/feign/vertx/Http2ClientReconnectTest.java index 536a6ae098..244b9f67de 100644 --- a/vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http2ClientReconnectTest.java @@ -20,8 +20,9 @@ import feign.jackson.JacksonEncoder; import feign.vertx.testcase.HelloServiceAPI; import io.vertx.core.Vertx; -import io.vertx.core.http.HttpClientOptions; import io.vertx.core.http.HttpVersion; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; @@ -31,13 +32,13 @@ class Http2ClientReconnectTest extends AbstractClientReconnectTest { @BeforeAll @Override protected void createClient(Vertx vertx) { - HttpClientOptions options = - new HttpClientOptions().setProtocolVersion(HttpVersion.HTTP_2).setHttp2MaxPoolSize(1); + WebClientOptions options = + new WebClientOptions().setProtocolVersion(HttpVersion.HTTP_2).setHttp2MaxPoolSize(1); + WebClient webClient = WebClient.create(vertx, options); client = VertxFeign.builder() - .vertx(vertx) - .options(options) + .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) .target(HelloServiceAPI.class, baseUrl); diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java new file mode 100644 index 0000000000..39a43a8adb --- /dev/null +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java @@ -0,0 +1,121 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static org.assertj.core.api.Assertions.assertThat; + +import feign.*; +import feign.VertxFeign; +import feign.jackson.JacksonDecoder; +import feign.slf4j.Slf4jLogger; +import feign.vertx.testcase.domain.Bill; +import feign.vertx.testcase.domain.Flavor; +import feign.vertx.testcase.domain.IceCreamOrder; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; +import io.vertx.junit5.VertxTestContext; +import java.util.Collections; +import java.util.Comparator; +import java.util.Map; +import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("Tests of QueryMapEncoder") +class QueryMapEncoderTest extends AbstractFeignVertxTest { + interface Api { + + @RequestLine("POST /icecream/orders") + Future makeOrder(@QueryMap IceCreamOrder order); + } + + Api client; + + @BeforeEach + void createClient(Vertx vertx) { + WebClientOptions options = new WebClientOptions().setLogActivity(true); + WebClient webClient = WebClient.create(vertx, options); + + client = + VertxFeign.builder() + .webClient(webClient) + .decoder(new JacksonDecoder(TestUtils.MAPPER)) + .queryMapEncoder(new CustomQueryMapEncoder()) + .logger(new Slf4jLogger()) + .logLevel(Logger.Level.FULL) + .target(Api.class, wireMock.baseUrl()); + } + + @Test + @DisplayName("QueryMapEncoder will be used") + void willMakeOrder(VertxTestContext testContext) { + + /* Given */ + IceCreamOrder order = new IceCreamOrder(); + order.addBall(Flavor.PISTACHIO); + order.addBall(Flavor.PISTACHIO); + order.addBall(Flavor.STRAWBERRY); + order.addBall(Flavor.BANANA); + order.addBall(Flavor.VANILLA); + + Bill bill = Bill.makeBill(order); + String billStr = TestUtils.encodeAsJsonString(bill); + + wireMock.stubFor( + post(urlPathEqualTo("/icecream/orders")) + .withQueryParam("balls", equalTo("BANANA:1,PISTACHIO:2,STRAWBERRY:1,VANILLA:1")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(billStr))); + + /* When */ + Future billFuture = client.makeOrder(order); + + /* Then */ + billFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + assertThat(res.result()).isEqualTo(bill); + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + })); + } + + class CustomQueryMapEncoder implements QueryMapEncoder { + @Override + public Map encode(final Object o) { + IceCreamOrder order = (IceCreamOrder) o; + + String balls = + order.getBalls().entrySet().stream() + .sorted(Comparator.comparing(en -> en.getKey().toString())) + .map(entry -> entry.getKey().toString() + ':' + entry.getValue()) + .collect(Collectors.joining(",")); + + return Collections.singletonMap("balls", balls); + } + } +} diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java new file mode 100644 index 0000000000..48f46b4b49 --- /dev/null +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java @@ -0,0 +1,125 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static feign.vertx.testcase.domain.Flavor.FLAVORS_JSON; +import static org.assertj.core.api.Assertions.assertThat; + +import feign.Response; +import feign.VertxFeign; +import feign.jackson.JacksonDecoder; +import feign.jackson.JacksonEncoder; +import feign.vertx.testcase.RawServiceAPI; +import feign.vertx.testcase.domain.Bill; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; +import io.vertx.junit5.VertxTestContext; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("When creating client from 'raw' contract") +class RawContractTest extends AbstractFeignVertxTest { + static RawServiceAPI client; + + @BeforeAll + static void createClient(Vertx vertx) { + client = + VertxFeign.builder() + .webClient(WebClient.create(vertx)) + .encoder(new JacksonEncoder(TestUtils.MAPPER)) + .decoder(new JacksonDecoder(TestUtils.MAPPER)) + .target(RawServiceAPI.class, wireMock.baseUrl()); + } + + @Test + @DisplayName("should get available flavors") + void getAvailableFlavors(VertxTestContext testContext) { + + /* Given */ + wireMock.stubFor( + get(urlEqualTo("/icecream/flavors")) + .withHeader("Accept", equalTo("application/json")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(FLAVORS_JSON))); + + /* When */ + Future flavorsFuture = client.getAvailableFlavors(); + + /* Then */ + flavorsFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + Response response = res.result(); + try { + String content = + new BufferedReader(new InputStreamReader(response.body().asInputStream())) + .lines() + .collect(Collectors.joining("\n")); + + assertThat(response.status()).isEqualTo(200); + assertThat(content).isEqualTo(FLAVORS_JSON); + testContext.completeNow(); + } catch (IOException ioException) { + testContext.failNow(ioException); + } + } else { + testContext.failNow(res.cause()); + } + })); + } + + @Test + @DisplayName("should pay bill") + void payBill(VertxTestContext testContext) { + + /* Given */ + Bill bill = Bill.makeBill(generator.generate()); + String billStr = TestUtils.encodeAsJsonString(bill); + + wireMock.stubFor( + post(urlEqualTo("/icecream/bills/pay")) + .withHeader("Content-Type", equalTo("application/json")) + .withRequestBody(equalToJson(billStr)) + .willReturn(aResponse().withStatus(200))); + + /* When */ + Future payedFuture = client.payBill(bill); + + /* Then */ + payedFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + })); + } +} diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java new file mode 100644 index 0000000000..87850cb9e3 --- /dev/null +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java @@ -0,0 +1,92 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static feign.vertx.testcase.domain.Flavor.FLAVORS_JSON; +import static org.assertj.core.api.Assertions.assertThat; + +import feign.Logger; +import feign.VertxFeign; +import feign.jackson.JacksonDecoder; +import feign.slf4j.Slf4jLogger; +import feign.vertx.testcase.IcecreamServiceApi; +import feign.vertx.testcase.domain.Flavor; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; +import io.vertx.junit5.VertxTestContext; +import java.util.Arrays; +import java.util.Collection; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("Test request pre processor") +class RequestPreProcessorTest extends AbstractFeignVertxTest { + IcecreamServiceApi client; + + @BeforeEach + void createClient(Vertx vertx) { + WebClientOptions options = new WebClientOptions().setLogActivity(true); + WebClient webClient = WebClient.create(vertx, options); + + client = + VertxFeign.builder() + .webClient(webClient) + .decoder(new JacksonDecoder(TestUtils.MAPPER)) + .requestPreProcessor(req -> req.addQueryParam("version", "v1")) + .logger(new Slf4jLogger()) + .logLevel(Logger.Level.FULL) + .target(IcecreamServiceApi.class, wireMock.baseUrl()); + } + + @Test + @DisplayName("request pre processor must be applied") + void requestPreProcessorMustApply(VertxTestContext testContext) { + + /* Given */ + wireMock.stubFor( + get(urlPathEqualTo("/icecream/flavors")) + .withQueryParam("version", equalTo("v1")) + .withHeader("Accept", equalTo("application/json")) + .willReturn( + aResponse() + .withStatus(200) + .withFixedDelay(100) + .withHeader("Content-Type", "application/json") + .withBody(FLAVORS_JSON))); + + Future> flavorsFuture = client.getAvailableFlavors(); + + /* Then */ + flavorsFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + Collection flavors = res.result(); + assertThat(flavors) + .hasSize(Flavor.values().length) + .containsAll(Arrays.asList(Flavor.values())); + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + })); + } +} diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java new file mode 100644 index 0000000000..c5ce7cba3b --- /dev/null +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java @@ -0,0 +1,141 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED; +import static feign.vertx.TestUtils.MAPPER; +import static feign.vertx.testcase.domain.Flavor.FLAVORS_JSON; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; + +import feign.Logger; +import feign.RetryableException; +import feign.Retryer; +import feign.VertxFeign; +import feign.jackson.JacksonDecoder; +import feign.slf4j.Slf4jLogger; +import feign.vertx.testcase.IcecreamServiceApi; +import feign.vertx.testcase.domain.Flavor; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; +import io.vertx.junit5.VertxTestContext; +import java.util.Arrays; +import java.util.Collection; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("When server ask client to retry") +class RetryingTest extends AbstractFeignVertxTest { + static IcecreamServiceApi client; + + @BeforeAll + static void createClient(Vertx vertx) { + client = + VertxFeign.builder() + .webClient(WebClient.create(vertx)) + .decoder(new JacksonDecoder(MAPPER)) + .retryer(new Retryer.Default(100, SECONDS.toMillis(1), 5)) + .logger(new Slf4jLogger()) + .logLevel(Logger.Level.FULL) + .target(IcecreamServiceApi.class, wireMock.baseUrl()); + } + + @Test + @DisplayName("should succeed when client retries less than max attempts") + void retryingSuccess(VertxTestContext testContext) { + + /* Given */ + String scenario = "testRetrying_success"; + + wireMock.stubFor( + get(urlEqualTo("/icecream/flavors")) + .withHeader("Accept", equalTo("application/json")) + .inScenario(scenario) + .whenScenarioStateIs(STARTED) + .willReturn(aResponse().withStatus(503).withHeader("Retry-After", "1")) + .willSetStateTo("attempt1")); + + wireMock.stubFor( + get(urlEqualTo("/icecream/flavors")) + .withHeader("Accept", equalTo("application/json")) + .inScenario(scenario) + .whenScenarioStateIs("attempt1") + .willReturn(aResponse().withStatus(503).withHeader("Retry-After", "1")) + .willSetStateTo("attempt2")); + + wireMock.stubFor( + get(urlEqualTo("/icecream/flavors")) + .withHeader("Accept", equalTo("application/json")) + .inScenario(scenario) + .whenScenarioStateIs("attempt2") + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(FLAVORS_JSON))); + + /* When */ + Future> flavorsFuture = client.getAvailableFlavors(); + + /* Then */ + flavorsFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + assertThat(res.result()) + .hasSize(Flavor.values().length) + .containsAll(Arrays.asList(Flavor.values())); + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + })); + } + + @Test + @DisplayName("should fail when after max number of attempts") + void retryingNoMoreAttempts(VertxTestContext testContext) { + + /* Given */ + wireMock.stubFor( + get(urlEqualTo("/icecream/flavors")) + .withHeader("Accept", equalTo("application/json")) + .willReturn(aResponse().withStatus(503).withHeader("Retry-After", "1"))); + + /* When */ + Future> flavorsFuture = client.getAvailableFlavors(); + + /* Then */ + flavorsFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.failed()) { + assertThat(res.cause()) + .isInstanceOf(RetryableException.class) + .hasMessageContaining("503 Service Unavailable"); + testContext.completeNow(); + } else { + testContext.failNow( + new IllegalStateException("RetryableException excepted but not occurred")); + } + })); + } +} diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java new file mode 100644 index 0000000000..29e7efa6e1 --- /dev/null +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java @@ -0,0 +1,125 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static feign.vertx.testcase.domain.Flavor.FLAVORS_JSON; +import static org.assertj.core.api.Assertions.assertThat; + +import feign.Logger; +import feign.VertxFeign; +import feign.jackson.JacksonDecoder; +import feign.slf4j.Slf4jLogger; +import feign.vertx.testcase.IcecreamServiceApi; +import feign.vertx.testcase.domain.Flavor; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; +import io.vertx.junit5.VertxTestContext; +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.TimeoutException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("Tests of handling of timeouts") +class TimeoutHandlingTest extends AbstractFeignVertxTest { + IcecreamServiceApi client; + + @BeforeEach + void createClient(Vertx vertx) { + WebClientOptions options = new WebClientOptions().setLogActivity(true); + WebClient webClient = WebClient.create(vertx, options); + + client = + VertxFeign.builder() + .webClient(webClient) + .decoder(new JacksonDecoder(TestUtils.MAPPER)) + .timeout(1000) + .logger(new Slf4jLogger()) + .logLevel(Logger.Level.FULL) + .target(IcecreamServiceApi.class, wireMock.baseUrl()); + } + + @Test + @DisplayName("when timeout is reached") + void whenTimeoutIsReached(VertxTestContext testContext) { + + /* Given */ + wireMock.stubFor( + get(urlEqualTo("/icecream/flavors")) + .withHeader("Accept", equalTo("application/json")) + .willReturn( + aResponse() + .withStatus(200) + .withFixedDelay(1500) + .withHeader("Content-Type", "application/json") + .withBody(FLAVORS_JSON))); + + Future> flavorsFuture = client.getAvailableFlavors(); + + /* Then */ + flavorsFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + testContext.failNow("should timeout!"); + } else { + assertThat(res.cause()) + .isInstanceOf(TimeoutException.class) + .hasMessageContaining("timeout"); + testContext.completeNow(); + } + })); + } + + @Test + @DisplayName("when timeout is not reached") + void whenTimeoutIsNotReached(VertxTestContext testContext) { + + /* Given */ + wireMock.stubFor( + get(urlEqualTo("/icecream/flavors")) + .withHeader("Accept", equalTo("application/json")) + .willReturn( + aResponse() + .withStatus(200) + .withFixedDelay(100) + .withHeader("Content-Type", "application/json") + .withBody(FLAVORS_JSON))); + + Future> flavorsFuture = client.getAvailableFlavors(); + + /* Then */ + flavorsFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + Collection flavors = res.result(); + assertThat(flavors) + .hasSize(Flavor.values().length) + .containsAll(Arrays.asList(Flavor.values())); + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + })); + } +} diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java new file mode 100644 index 0000000000..eca7765385 --- /dev/null +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java @@ -0,0 +1,330 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static feign.vertx.testcase.domain.Flavor.FLAVORS_JSON; +import static feign.vertx.testcase.domain.Mixin.MIXINS_JSON; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import feign.FeignException; +import feign.Logger; +import feign.VertxFeign; +import feign.jackson.JacksonDecoder; +import feign.jackson.JacksonEncoder; +import feign.slf4j.Slf4jLogger; +import feign.vertx.testcase.IcecreamServiceApi; +import feign.vertx.testcase.IcecreamServiceApiBroken; +import feign.vertx.testcase.domain.Bill; +import feign.vertx.testcase.domain.Flavor; +import feign.vertx.testcase.domain.IceCreamOrder; +import feign.vertx.testcase.domain.Mixin; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; +import io.vertx.junit5.VertxTestContext; +import java.util.Arrays; +import java.util.Collection; +import org.assertj.core.api.ThrowableAssert; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +@DisplayName("FeignVertx client") +public class VertxHttpClientTest extends AbstractFeignVertxTest { + + @Nested + @DisplayName("When make a GET request") + class WhenMakeGetRequest { + IcecreamServiceApi client; + + @BeforeEach + void createClient(Vertx vertx) { + WebClientOptions options = + new WebClientOptions() + .setConnectTimeout(5000) + .setIdleTimeout(5000) + .setFollowRedirects(true); + WebClient webClient = WebClient.create(vertx, options); + + client = + VertxFeign.builder() + .webClient(webClient) + .decoder(new JacksonDecoder(TestUtils.MAPPER)) + .logger(new Slf4jLogger()) + .logLevel(Logger.Level.FULL) + .target(IcecreamServiceApi.class, wireMock.baseUrl()); + } + + @Test + @DisplayName("will get flavors") + void willGetFlavors(VertxTestContext testContext) { + + /* Given */ + wireMock.stubFor( + get(urlEqualTo("/icecream/flavors")) + .withHeader("Accept", equalTo("application/json")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(FLAVORS_JSON))); + + /* When */ + Future> flavorsFuture = client.getAvailableFlavors(); + + /* Then */ + flavorsFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + Collection flavors = res.result(); + + assertThat(flavors) + .hasSize(Flavor.values().length) + .containsAll(Arrays.asList(Flavor.values())); + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + })); + } + + @Test + @DisplayName("will get mixins") + void willGetMixins(VertxTestContext testContext) { + + /* Given */ + wireMock.stubFor( + get(urlEqualTo("/icecream/mixins")) + .withHeader("Accept", equalTo("application/json")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(MIXINS_JSON))); + + /* When */ + Future> mixinsFuture = client.getAvailableMixins(); + + /* Then */ + mixinsFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + Collection mixins = res.result(); + + assertThat(mixins) + .hasSize(Mixin.values().length) + .containsAll(Arrays.asList(Mixin.values())); + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + })); + } + + @Test + @DisplayName("will get order by id") + void willGetOrderById(VertxTestContext testContext) { + + /* Given */ + IceCreamOrder order = generator.generate(); + int orderId = order.getId(); + String orderStr = TestUtils.encodeAsJsonString(order); + + wireMock.stubFor( + get(urlEqualTo("/icecream/orders/" + orderId)) + .withHeader("Accept", equalTo("application/json")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(orderStr))); + + /* When */ + Future orderFuture = client.findOrder(orderId); + + /* Then */ + orderFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + assertThat(res.result()).isEqualTo(order); + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + })); + } + + @Test + @DisplayName("will return 404 when try to get non-existing order by id") + void willReturn404WhenTryToGetNonExistingOrderById(VertxTestContext testContext) { + + /* Given */ + wireMock.stubFor( + get(urlEqualTo("/icecream/orders/123")) + .withHeader("Accept", equalTo("application/json")) + .willReturn(aResponse().withStatus(404))); + + /* When */ + Future orderFuture = client.findOrder(123); + + /* Then */ + orderFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.failed()) { + assertThat(res.cause()) + .isInstanceOf(FeignException.class) + .hasMessageContaining("404 Not Found"); + testContext.completeNow(); + } else { + testContext.failNow( + new IllegalStateException("FeignException excepted but not occurred")); + } + })); + } + } + + @Nested + @DisplayName("When make a POST request") + class WhenMakePostRequest { + IcecreamServiceApi client; + + @BeforeEach + void createClient(Vertx vertx) { + client = + VertxFeign.builder() + .webClient(WebClient.create(vertx)) + .encoder(new JacksonEncoder(TestUtils.MAPPER)) + .decoder(new JacksonDecoder(TestUtils.MAPPER)) + .target(IcecreamServiceApi.class, wireMock.baseUrl()); + } + + @Test + @DisplayName("will make an order") + void willMakeOrder(VertxTestContext testContext) { + + /* Given */ + IceCreamOrder order = generator.generate(); + Bill bill = Bill.makeBill(order); + String orderStr = TestUtils.encodeAsJsonString(order); + String billStr = TestUtils.encodeAsJsonString(bill); + + wireMock.stubFor( + post(urlEqualTo("/icecream/orders")) + .withHeader("Content-Type", equalTo("application/json")) + .withHeader("Accept", equalTo("application/json")) + .withRequestBody(equalToJson(orderStr)) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody(billStr))); + + /* When */ + Future billFuture = client.makeOrder(order); + + /* Then */ + billFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + assertThat(res.result()).isEqualTo(bill); + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + })); + } + + @Test + @DisplayName("will pay bill") + void willPayBill(VertxTestContext testContext) { + + /* Given */ + Bill bill = Bill.makeBill(generator.generate()); + String billStr = TestUtils.encodeAsJsonString(bill); + + wireMock.stubFor( + post(urlEqualTo("/icecream/bills/pay")) + .withHeader("Content-Type", equalTo("application/json")) + .withRequestBody(equalToJson(billStr)) + .willReturn(aResponse().withStatus(200))); + + /* When */ + Future payedFuture = client.payBill(bill); + + /* Then */ + payedFuture.onComplete( + res -> + testContext.verify( + () -> { + if (res.succeeded()) { + testContext.completeNow(); + } else { + testContext.failNow(res.cause()); + } + })); + } + } + + @Nested + @DisplayName("Should fail client instantiation") + class ShouldFailedClientInstantiation { + + @Test + @DisplayName("when Vertx is not provided") + void whenVertxMissing() { + + /* Given */ + ThrowableAssert.ThrowingCallable instantiateContractForgottenVertx = + () -> VertxFeign.builder().target(IcecreamServiceApi.class, wireMock.baseUrl()); + + /* Then */ + assertThatCode(instantiateContractForgottenVertx) + .isInstanceOf(NullPointerException.class) + .hasMessage("Vertx WebClient instance wasn't provided in VertxFeign builder"); + } + + @Test + @DisplayName("when try to instantiate contract that have method that not return future") + void whenTryToInstantiateBrokenContract(Vertx vertx) { + + /* Given */ + ThrowableAssert.ThrowingCallable instantiateBrokenContract = + () -> + VertxFeign.builder() + .webClient(WebClient.create(vertx)) + .target(IcecreamServiceApiBroken.class, wireMock.baseUrl()); + + /* Then */ + assertThatCode(instantiateBrokenContract) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("IcecreamServiceApiBroken#findOrder(int)"); + } + } +} diff --git a/vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java similarity index 86% rename from vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java rename to vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java index 49374c227d..0e83d3ea62 100644 --- a/vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java @@ -20,19 +20,18 @@ import static org.assertj.core.api.Assertions.assertThat; import feign.Logger; -import feign.Request; import feign.VertxFeign; import feign.jackson.JacksonDecoder; import feign.slf4j.Slf4jLogger; import feign.vertx.testcase.IcecreamServiceApi; import feign.vertx.testcase.domain.Flavor; import io.vertx.core.Vertx; -import io.vertx.core.http.HttpClientOptions; import io.vertx.core.http.HttpVersion; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; import io.vertx.junit5.VertxTestContext; import java.util.Arrays; import java.util.Collection; -import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -55,17 +54,17 @@ static void setupStub() { @Test @DisplayName("HttpClientOptions from Vertx") void httpClientOptions(Vertx vertx, VertxTestContext testContext) { - HttpClientOptions options = - new HttpClientOptions() + WebClientOptions options = + new WebClientOptions() .setProtocolVersion(HttpVersion.HTTP_2) .setHttp2MaxPoolSize(1) .setConnectTimeout(5000) .setIdleTimeout(5000); + WebClient webClient = WebClient.create(vertx, options); IcecreamServiceApi client = VertxFeign.builder() - .vertx(vertx) - .options(options) + .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) .logLevel(Logger.Level.FULL) @@ -77,10 +76,16 @@ void httpClientOptions(Vertx vertx, VertxTestContext testContext) { @Test @DisplayName("Request Options from Feign") void requestOptions(Vertx vertx, VertxTestContext testContext) { + WebClientOptions options = + new WebClientOptions() + .setConnectTimeout(5000) + .setIdleTimeout(5000) + .setFollowRedirects(true); + WebClient webClient = WebClient.create(vertx, options); + IcecreamServiceApi client = VertxFeign.builder() - .vertx(vertx) - .options(new Request.Options(5L, TimeUnit.SECONDS, 5L, TimeUnit.SECONDS, true)) + .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) .logLevel(Logger.Level.FULL) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml new file mode 100644 index 0000000000..197520222f --- /dev/null +++ b/vertx/feign-vertx5-test/pom.xml @@ -0,0 +1,128 @@ + + + + 4.0.0 + + io.github.openfeign + feign-vertx-parent + 13.6-SNAPSHOT + + + feign-vertx5-test + + Feign Vertx (tests with Vertx 5.x) + Tests with Vertx 5.x. + + + 5.0.0.CR4 + + + + + io.github.openfeign + feign-vertx + ${project.version} + tests + test-jar + test + + + + io.github.openfeign + feign-vertx + test + + + + io.vertx + vertx-junit5 + ${vertx.version} + test + + + + io.vertx + vertx-web-client + ${vertx.version} + test + + + + org.assertj + assertj-core + test + + + + io.github.openfeign + feign-jackson + test + + + + com.fasterxml.jackson.core + jackson-annotations + test + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + test + + + + io.github.openfeign + feign-slf4j + test + + + + org.slf4j + slf4j-log4j12 + test + + + + com.github.tomakehurst + wiremock-jre8 + test + + + org.junit + junit-bom + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + io.github.openfeign:feign-vertx:test-jar + + + + + + diff --git a/vertx/feign-vertx5-test/run-tests.zsh b/vertx/feign-vertx5-test/run-tests.zsh new file mode 100755 index 0000000000..49d01be0c2 --- /dev/null +++ b/vertx/feign-vertx5-test/run-tests.zsh @@ -0,0 +1,38 @@ +#!/usr/bin/env zsh + +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' + +CHECK_CHAR='\U2713' +CROSS_CHAR='\U2717' + +function print_result() { + version=$1 + result=$2 + + if [[ $result == 0 ]]; + then + mark=$CHECK_CHAR + color=$GREEN + else + mark=$CROSS_CHAR + color=$RED + fi + + echo "\t${color}${version} ${mark}${NC}" +} + +declare -A vertx_versions +vertx_versions=( [v50x]="5.0.x" ) +v50x=( "5.0.0.CR4" ) + +for version in ${(k)vertx_versions}; do + echo "Tests with Vertx ${vertx_versions[${version}]}:" + + for vertx_version in ${(P)version}; do + printf "\tRun tests with Vertx %s...\n" "${vertx_version}" + mvn clean compile test -Dvertx.version="$vertx_version" &> /dev/null + print_result "$vertx_version" $? + done +done diff --git a/vertx/pom.xml b/vertx/pom.xml index aa04c46e51..4703f0415d 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -24,16 +24,19 @@ 13.6-SNAPSHOT - feign-vertx + feign-vertx-parent + pom - Feign Vertx - Implementation of Feign on Vertx web client. + + feign-vertx + feign-vertx4-test + feign-vertx5-test + - 4.5.13 - 2.18.2 - 2.0.0-alpha6 - 2.35.2 + 5.0.0.CR4 + 2.0.16 + 3.0.1 @@ -45,79 +48,24 @@ pom import - - - - - - io.github.openfeign - feign-core - - - - - io.vertx - vertx-core - ${vertx.version} - provided - - - - - io.vertx - vertx-junit5 - ${vertx.version} - test - - - - org.assertj - assertj-core - test - - - - io.github.openfeign - feign-jackson - test - - - - com.fasterxml.jackson.core - jackson-annotations - test - - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - test - - - io.github.openfeign - feign-slf4j - test - + + io.github.openfeign + feign-vertx-common-test + ${project.version} + - - org.slf4j - slf4j-log4j12 - ${slf4j-log4j12.version} - test - + + org.slf4j + slf4j-log4j12 + ${slf4j-log4j12.version} + - - com.github.tomakehurst - wiremock-jre8 - ${wiremock.version} - test - - - org.junit - junit-bom - - - - + + com.github.tomakehurst + wiremock-jre8 + ${wiremock.version} + + + From 12316f7aba6ef01c414847ad432c2d2e310c1722 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 3 Mar 2025 11:03:49 -0300 Subject: [PATCH 078/615] Fix test assertion Signed-off-by: Marvin Froeder --- .../src/test/java/feign/http2client/test/Http2ClientTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientTest.java index 806b9321a5..6f6db9b698 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientTest.java @@ -152,7 +152,7 @@ void getWithRequestBody() { final TestInterface api = newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); String result = api.getWithBody(); - assertThat(result).contains("\"data\": \"some request body\""); + assertThat(result).contains("\"data\":\"some request body\""); } @Test @@ -160,7 +160,7 @@ void deleteWithRequestBody() { final TestInterface api = newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); String result = api.deleteWithBody(); - assertThat(result).contains("\"data\": \"some request body\""); + assertThat(result).contains("\"data\":\"some request body\""); } @Override From 468e7555648b2311296ca5f88ff03d55914c5bde Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Wed, 12 Mar 2025 12:27:03 -0300 Subject: [PATCH 079/615] Fix required JDK to build project Signed-off-by: Marvin Froeder --- vertx/feign-vertx/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 648c7cbeb0..bca19816e0 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -30,6 +30,7 @@ Implementation of Feign on Vertx web client. + 11 2.18.2 From 6d62680c3803ec70776b52895f6b2ea2fbb99ba1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:36:41 +0000 Subject: [PATCH 080/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.3.0...v3.4.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 92276455e5..09aaf34fc0 100644 --- a/pom.xml +++ b/pom.xml @@ -1026,7 +1026,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.3.0 + 3.4.0 org.openrewrite.recipe From c753664e2bbdf960e6a5ba29bb1ca27b57171ac7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:45:12 +0000 Subject: [PATCH 081/615] Bump io.sundr:sundr-maven-plugin from 0.200.0 to 0.200.3 Bumps [io.sundr:sundr-maven-plugin](https://github.com/sundrio/sundrio) from 0.200.0 to 0.200.3. - [Commits](https://github.com/sundrio/sundrio/compare/0.200.0...0.200.3) --- updated-dependencies: - dependency-name: io.sundr:sundr-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 09aaf34fc0..a38c9556c2 100644 --- a/pom.xml +++ b/pom.xml @@ -194,7 +194,7 @@ 6.0.0 0.1.1 3.5.2 - 0.200.0 + 0.200.3 file://${project.basedir}/src/config/bom.xml 2.1.0 2.18.0 From 1c65ca1cfebf681551a5d45321fc82f15d43abed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:51:07 +0000 Subject: [PATCH 082/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.2.2 to 6.3.0 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.2.2 to 6.3.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.2.2...v6.3.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a38c9556c2..da4fbccb0c 100644 --- a/pom.xml +++ b/pom.xml @@ -1020,7 +1020,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.2.2 + 6.3.0 From bc5a6e513f2af6350a181fcc09ea6e2b2ed7c2ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:54:11 +0000 Subject: [PATCH 083/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.3.0 to 3.4.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.3.0...v3.4.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index da4fbccb0c..eeae2f7ba0 100644 --- a/pom.xml +++ b/pom.xml @@ -1031,7 +1031,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.3.0 + 3.4.0 From b9c8e5e08bf94a749ef37d475ee6b53082396fbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:00:56 +0000 Subject: [PATCH 084/615] Bump mockito.version from 5.15.2 to 5.16.0 Bumps `mockito.version` from 5.15.2 to 5.16.0. Updates `org.mockito:mockito-core` from 5.15.2 to 5.16.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.15.2...v5.16.0) Updates `org.mockito:mockito-junit-jupiter` from 5.15.2 to 5.16.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.15.2...v5.16.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- form-spring/pom.xml | 4 ++-- form/pom.xml | 4 ++-- pom.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 64827e5d87..1aa60e2179 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -124,13 +124,13 @@ org.mockito mockito-core - 5.15.2 + 5.16.0 test org.mockito mockito-junit-jupiter - 5.15.2 + 5.16.0 test diff --git a/form/pom.xml b/form/pom.xml index 38a0010877..a11e75956f 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -99,13 +99,13 @@ org.mockito mockito-core - 5.15.2 + 5.16.0 test org.mockito mockito-junit-jupiter - 5.15.2 + 5.16.0 test diff --git a/pom.xml b/pom.xml index eeae2f7ba0..6506accc33 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ 5.11.4 2.18.3 3.27.3 - 5.15.2 + 5.16.0 2.0.56 5.3 From 2167a197a6ea10c6e2b44ff6b8621f6ef8b12b1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:03:43 +0000 Subject: [PATCH 085/615] Bump reactor.version from 3.7.3 to 3.7.4 Bumps `reactor.version` from 3.7.3 to 3.7.4. Updates `io.projectreactor:reactor-core` from 3.7.3 to 3.7.4 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.3...v3.7.4) Updates `io.projectreactor:reactor-test` from 3.7.3 to 3.7.4 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.3...v3.7.4) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index 18cf9e9e15..f9deed0ef7 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.7.3 + 3.7.4 1.0.4 2.2.21 From a3783d9eaed79b3a98675a531015097784e07681 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 16:07:18 +0000 Subject: [PATCH 086/615] Bump micrometer.version from 1.14.4 to 1.14.5 Bumps `micrometer.version` from 1.14.4 to 1.14.5. Updates `io.micrometer:micrometer-core` from 1.14.4 to 1.14.5 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.4...v1.14.5) Updates `io.micrometer:micrometer-test` from 1.14.4 to 1.14.5 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.4...v1.14.5) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 4cfd735683..22cd84ee62 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.14.4 + 1.14.5 From 9f6aacd410f335efc1afd7b29f5822c2093c276d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 05:49:13 +0000 Subject: [PATCH 087/615] Bump mockito.version from 5.16.0 to 5.16.1 Bumps `mockito.version` from 5.16.0 to 5.16.1. Updates `org.mockito:mockito-core` from 5.16.0 to 5.16.1 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.16.0...v5.16.1) Updates `org.mockito:mockito-junit-jupiter` from 5.16.0 to 5.16.1 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.16.0...v5.16.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- form-spring/pom.xml | 4 ++-- form/pom.xml | 4 ++-- pom.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 1aa60e2179..a7da262a87 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -124,13 +124,13 @@ org.mockito mockito-core - 5.16.0 + 5.16.1 test org.mockito mockito-junit-jupiter - 5.16.0 + 5.16.1 test diff --git a/form/pom.xml b/form/pom.xml index a11e75956f..3c3bd34f80 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -99,13 +99,13 @@ org.mockito mockito-core - 5.16.0 + 5.16.1 test org.mockito mockito-junit-jupiter - 5.16.0 + 5.16.1 test diff --git a/pom.xml b/pom.xml index 6506accc33..f1f74b7580 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ 5.11.4 2.18.3 3.27.3 - 5.16.0 + 5.16.1 2.0.56 5.3 From 129914d00552414b7c1eab980211c3afc01304b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 05:58:48 +0000 Subject: [PATCH 088/615] Bump org.springframework:spring-context from 6.2.3 to 6.2.4 Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 6.2.3 to 6.2.4. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.3...v6.2.4) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index aa2943ee40..f45f4bc770 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - 6.2.3 + 6.2.4 test From c965dad41f3b771bcf171f958a4511c94059df2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 06:08:07 +0000 Subject: [PATCH 089/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.3.0 to 6.3.1 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.3.0 to 6.3.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.3.0...v6.3.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f1f74b7580..0603e0de18 100644 --- a/pom.xml +++ b/pom.xml @@ -1020,7 +1020,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.3.0 + 6.3.1 From b6f012060cbcad9569e0eb87c38f903c2ff73d83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 05:39:14 +0000 Subject: [PATCH 090/615] Bump com.google.guava:guava from 33.4.0-jre to 33.4.5-jre Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.4.0-jre to 33.4.5-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0603e0de18..de641bfe54 100644 --- a/pom.xml +++ b/pom.xml @@ -169,7 +169,7 @@ ${main.java.version} 4.12.0 - 33.4.0-jre + 33.4.5-jre 1.46.3 2.12.1 1.15.2 From 2c439e0d1b33f3b7d53a911e233e82285ab7c478 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 05:48:43 +0000 Subject: [PATCH 091/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.3.1 to 6.3.2 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.3.1 to 6.3.2. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.3.1...v6.3.2) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index de641bfe54..9df669611c 100644 --- a/pom.xml +++ b/pom.xml @@ -1020,7 +1020,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.3.1 + 6.3.2 From 4b61b9231b1eace0e686c0c494c928b7425d293e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 05:52:14 +0000 Subject: [PATCH 092/615] Bump org.springframework:spring-context from 6.2.4 to 6.2.5 Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 6.2.4 to 6.2.5. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.4...v6.2.5) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index f45f4bc770..c4ee96797e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - 6.2.4 + 6.2.5 test From fd4c5febe6e9ce0cfd005e12219f7b2a440df3b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 05:34:38 +0000 Subject: [PATCH 093/615] Bump license-maven-plugin.version from 4.6 to 5.0.0 Bumps `license-maven-plugin.version` from 4.6 to 5.0.0. Updates `com.mycila:license-maven-plugin-git` from 4.6 to 5.0.0 - [Release notes](https://github.com/mathieucarbou/license-maven-plugin/releases) - [Commits](https://github.com/mathieucarbou/license-maven-plugin/compare/license-maven-plugin-4.6...v5.0.0) Updates `com.mycila:license-maven-plugin` from 4.6 to 5.0.0 - [Release notes](https://github.com/mathieucarbou/license-maven-plugin/releases) - [Commits](https://github.com/mathieucarbou/license-maven-plugin/compare/license-maven-plugin-4.6...v5.0.0) --- updated-dependencies: - dependency-name: com.mycila:license-maven-plugin-git dependency-type: direct:production update-type: version-update:semver-major - dependency-name: com.mycila:license-maven-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9df669611c..f36004f076 100644 --- a/pom.xml +++ b/pom.xml @@ -188,7 +188,7 @@ 3.1.4 3.3.1 3.11.2 - 4.6 + 5.0.0 3.4.2 3.1.1 6.0.0 From aed0f2341c1c9b5dde1387e83657192296d6ea71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 05:43:43 +0000 Subject: [PATCH 094/615] Bump kotlin.version from 2.1.10 to 2.1.20 Bumps `kotlin.version` from 2.1.10 to 2.1.20. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.1.10 to 2.1.20 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.10...v2.1.20) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.1.10 to 2.1.20 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.10...v2.1.20) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.1.10 to 2.1.20 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index f7458f4cf1..74e07de50b 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.1.10 + 2.1.20 1.10.1 From f466fafaa29146000dc3981972c7ed1f416f7bae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 05:56:58 +0000 Subject: [PATCH 095/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.4.0 to 3.5.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.4.0...v3.5.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f36004f076..58c21e57f0 100644 --- a/pom.xml +++ b/pom.xml @@ -1026,7 +1026,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.4.0 + 3.5.0 org.openrewrite.recipe From 82a7b30c31ec1eed3382ee88f9f3507287731f2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Mar 2025 05:17:17 +0000 Subject: [PATCH 096/615] Bump com.google.guava:guava from 33.4.5-jre to 33.4.6-jre Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.4.5-jre to 33.4.6-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 58c21e57f0..f7fc07400b 100644 --- a/pom.xml +++ b/pom.xml @@ -169,7 +169,7 @@ ${main.java.version} 4.12.0 - 33.4.5-jre + 33.4.6-jre 1.46.3 2.12.1 1.15.2 From 80fa076d2121b3aa76859613324a6515c2aa92c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 05:56:14 +0000 Subject: [PATCH 097/615] Bump org.apache.httpcomponents.client5:httpclient5 from 5.4.2 to 5.4.3 Bumps [org.apache.httpcomponents.client5:httpclient5](https://github.com/apache/httpcomponents-client) from 5.4.2 to 5.4.3. - [Changelog](https://github.com/apache/httpcomponents-client/blob/rel/v5.4.3/RELEASE_NOTES.txt) - [Commits](https://github.com/apache/httpcomponents-client/compare/rel/v5.4.2...rel/v5.4.3) --- updated-dependencies: - dependency-name: org.apache.httpcomponents.client5:httpclient5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- hc5/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hc5/pom.xml b/hc5/pom.xml index c59108c667..9bffa810e9 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -38,7 +38,7 @@ org.apache.httpcomponents.client5 httpclient5 - 5.4.2 + 5.4.3 From 66a59e2063ed00eb90ae68a4d4cdecde9150c45c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Mar 2025 06:00:46 +0000 Subject: [PATCH 098/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.5.0 to 3.5.1. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.5.0...v3.5.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f7fc07400b..07b8fe9c76 100644 --- a/pom.xml +++ b/pom.xml @@ -1026,7 +1026,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.5.0 + 3.5.1 org.openrewrite.recipe From 58c37101c20504d3ecc3daa3c16e1ca1d4e194eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Mar 2025 06:09:59 +0000 Subject: [PATCH 099/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.3.2 to 6.4.0 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.3.2 to 6.4.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.3.2...v6.4.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 07b8fe9c76..58f420dca4 100644 --- a/pom.xml +++ b/pom.xml @@ -1020,7 +1020,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.3.2 + 6.4.0 From 361ce8976320c026bcfcf837325a548f602d8d1a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Mar 2025 06:12:25 +0000 Subject: [PATCH 100/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.4.0 to 3.5.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.4.0 to 3.5.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.4.0...v3.5.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 58f420dca4..10f9f3e803 100644 --- a/pom.xml +++ b/pom.xml @@ -1031,7 +1031,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.4.0 + 3.5.0 From d0390cb81d35007cb50e840795edc7ffe59688de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 05:50:43 +0000 Subject: [PATCH 101/615] Bump com.alibaba.fastjson2:fastjson2 from 2.0.56 to 2.0.57 Bumps [com.alibaba.fastjson2:fastjson2](https://github.com/alibaba/fastjson2) from 2.0.56 to 2.0.57. - [Release notes](https://github.com/alibaba/fastjson2/releases) - [Commits](https://github.com/alibaba/fastjson2/commits) --- updated-dependencies: - dependency-name: com.alibaba.fastjson2:fastjson2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 10f9f3e803..fa07a52aaa 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ 2.18.3 3.27.3 5.16.1 - 2.0.56 + 2.0.57 5.3 3.14.0 From 2882fb2562cc32c5cbae84a7b7f9a84eab64a119 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 05:06:59 +0000 Subject: [PATCH 102/615] Bump org.projectlombok:lombok from 1.18.36 to 1.18.38 Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.36 to 1.18.38. - [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/projectlombok/lombok/compare/v1.18.36...v1.18.38) --- updated-dependencies: - dependency-name: org.projectlombok:lombok dependency-version: 1.18.38 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index a7da262a87..d9cc559d3a 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -43,7 +43,7 @@ org.projectlombok lombok - 1.18.36 + 1.18.38 provided diff --git a/form/pom.xml b/form/pom.xml index 3c3bd34f80..2e6442433a 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -33,7 +33,7 @@ org.projectlombok lombok - 1.18.36 + 1.18.38 provided From cff520ac90ba3ff12297b3c936a58e34bb03962d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 05:16:59 +0000 Subject: [PATCH 103/615] Bump netty.version from 4.1.119.Final to 4.2.0.Final Bumps `netty.version` from 4.1.119.Final to 4.2.0.Final. Updates `io.netty:netty-bom` from 4.1.119.Final to 4.2.0.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.119.Final...netty-4.2.0.Final) Updates `io.netty:netty-handler` from 4.1.119.Final to 4.2.0.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.119.Final...netty-4.2.0.Final) Updates `io.netty:netty-codec-http` from 4.1.119.Final to 4.2.0.Final - [Commits](https://github.com/netty/netty/compare/netty-4.1.119.Final...netty-4.2.0.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.0.Final dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.netty:netty-handler dependency-version: 4.2.0.Final dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.0.Final dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index fecfa50c57..e504d55142 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.1.119.Final + 4.2.0.Final true From 61de71269121c2e3b6ce02d29b509462fe09dfe1 Mon Sep 17 00:00:00 2001 From: Alexei KLENIN Date: Sat, 5 Apr 2025 03:07:55 +0200 Subject: [PATCH 104/615] FIX: inreliable JSON asserts in Java 11 project (#2816) Co-authored-by: Marvin --- java11/pom.xml | 5 +++++ .../java/feign/http2client/test/Http2ClientTest.java | 12 ++++++++---- json/pom.xml | 1 - pom.xml | 7 +++++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/java11/pom.xml b/java11/pom.xml index cfdc6294be..88abc8ff81 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -62,6 +62,11 @@ gson test + + org.skyscreamer + jsonassert + test + diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientTest.java index 6f6db9b698..a769bda6b2 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientTest.java @@ -33,7 +33,9 @@ import java.util.concurrent.TimeUnit; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.RecordedRequest; +import org.json.JSONException; import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; /** Tests client-specific behavior, such as ensuring Content-Length is sent when specified. */ public class Http2ClientTest extends AbstractClientTest { @@ -148,19 +150,21 @@ void timeoutTest() { } @Test - void getWithRequestBody() { + void getWithRequestBody() throws JSONException { final TestInterface api = newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); String result = api.getWithBody(); - assertThat(result).contains("\"data\":\"some request body\""); + String expected = "{ \"data\":\"some request body\" }"; + JSONAssert.assertEquals(expected, result, false); } @Test - void deleteWithRequestBody() { + void deleteWithRequestBody() throws JSONException { final TestInterface api = newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); String result = api.deleteWithBody(); - assertThat(result).contains("\"data\":\"some request body\""); + String expected = "{ \"data\":\"some request body\" }"; + JSONAssert.assertEquals(expected, result, false); } @Override diff --git a/json/pom.xml b/json/pom.xml index 22701d8bb8..4810e24d2a 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -47,7 +47,6 @@ org.skyscreamer jsonassert - 1.5.3 test diff --git a/pom.xml b/pom.xml index fa07a52aaa..55903e0217 100644 --- a/pom.xml +++ b/pom.xml @@ -182,6 +182,7 @@ 3.27.3 5.16.1 2.0.57 + 1.5.3 5.3 3.14.0 @@ -476,6 +477,12 @@ ${fastjson2.version} + + org.skyscreamer + jsonassert + ${jsonassert.version} + + From 1c3fe715c14a085785777bbc06ae406af0af5986 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 22:09:51 -0300 Subject: [PATCH 105/615] Bump vertx.version from 5.0.0.CR4 to 4.5.14 (#2837) * Bump vertx.version from 5.0.0.CR4 to 4.5.14 Bumps `vertx.version` from 5.0.0.CR4 to 4.5.14. Updates `io.vertx:vertx-core` from 5.0.0.CR4 to 4.5.14 - [Commits](https://github.com/eclipse/vert.x/compare/5.0.0.CR4...4.5.14) Updates `io.vertx:vertx-web-client` from 4.5.12 to 4.5.14 Updates `io.vertx:vertx-junit5` from 4.5.12 to 4.5.14 --- updated-dependencies: - dependency-name: io.vertx:vertx-core dependency-version: 4.5.14 dependency-type: direct:production update-type: version-update:semver-major - dependency-name: io.vertx:vertx-web-client dependency-version: 4.5.14 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-junit5 dependency-version: 4.5.14 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update pom.xml * Update pom.xml --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin --- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 828f5b8928..d9b52f391a 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 4.x. - 4.5.12 + 4.5.14 diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 197520222f..7ca7ec0d5f 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.0.0.CR4 + 5.0.0.CR5 diff --git a/vertx/pom.xml b/vertx/pom.xml index 4703f0415d..f5ecc99f3c 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -34,7 +34,7 @@ - 5.0.0.CR4 + 5.0.0.CR5 2.0.16 3.0.1 From 5afdd229c36aa85eb886de089ee4622a22459f3a Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Sat, 5 Apr 2025 08:16:34 -0300 Subject: [PATCH 106/615] Add missing secrets to nexus deploy Signed-off-by: Marvin Froeder --- .github/workflows/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 120780560e..db4325f9d5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -86,6 +86,10 @@ jobs: - name: Nexus deploy if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/') + env: + GPG_KEY: ${{ secrets.GPG_KEY }} + SONATYPE_USER: ${{ secrets.SONATYPE_USER }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} run: | cp .github/files/settings.xml ~/.m2/settings.xml echo -e "$GPG_KEY" | gpg --batch --no-tty --import --yes From bab7f2e56d69affeefe7e67198fbdc1a66215409 Mon Sep 17 00:00:00 2001 From: Marvin Date: Sat, 5 Apr 2025 08:50:42 -0300 Subject: [PATCH 107/615] Build project with mvnd (#2839) Signed-off-by: Marvin Froeder --- .mvn/wrapper/maven-wrapper.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index fe378a151d..332fe58e14 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -15,4 +15,5 @@ # specific language governing permissions and limitations # under the License. wrapperVersion=3.3.1 -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip +distributionUrl=https://downloads.apache.org/maven/mvnd/1.0.2/maven-mvnd-1.0.2-linux-amd64.zip +distributionType=mvnd From a45be66a76120e26693fe0ddd852603784b4586c Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Sat, 5 Apr 2025 09:13:49 -0300 Subject: [PATCH 108/615] prepare release 13.6 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 48 files changed, 48 insertions(+), 48 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 3aa74b802b..4ae33b8274 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index feec4a4505..d7acd63bcb 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index e504d55142..e76c6310da 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index c4ee96797e..a1c4f28e48 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index e6c469eaa5..bacc28907f 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 56a0fb3351..01e34ceb22 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 3d6e859c2c..bc697911a6 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 06b20996f2..62a08d5217 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index e999889996..c4a97ee3a1 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index d6726e10e0..c1a84b4260 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 4bc4fe3e29..aa63890d67 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index d9cc559d3a..2ac3dcb08f 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 2e6442433a..b99f26e1dc 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 6479b81121..77d7aec304 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-googlehttpclient diff --git a/gson/pom.xml b/gson/pom.xml index 315bb58f58..5d98617717 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 9bffa810e9..1701031e47 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 162c4c86b6..01d7564355 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 3902fff9c2..569d415f71 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 531b928276..1fda85b7f4 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 1598eec848..15a9a80cc2 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 8c8b833edc..c6fc1378c8 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-jackson diff --git a/jakarta/pom.xml b/jakarta/pom.xml index d1fab04839..9df611df7f 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 88abc8ff81..c8f5b6fcef 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index a5ec30f084..b29f5ec7d4 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 5d92def358..a1f51c22a9 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 4565710b52..bd127a06bd 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 8db040a751..77ac193009 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index d24aa92b27..7ebe5a806b 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 998cf46447..56fb096693 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 4810e24d2a..c29047e480 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 74e07de50b..12a5615c7c 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 22cd84ee62..5cdbf44b73 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index bf2e491ee7..1fe864cb8a 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 35c77234c6..7dc317de67 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index f5f6c5c319..a4700de633 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-okhttp diff --git a/pom.xml b/pom.xml index 55903e0217..c12aff0358 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index f9deed0ef7..d92b65a250 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index a8c3c718c8..9103a9d34c 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 2fb526b0d3..1ce3aa36c3 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 3747d53409..afd71dbb32 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index e528490d02..c3471855dd 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index a14cd22f21..b9f1a49751 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 56f4083d52..594b68ab22 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 99e97362d7..5546c3f13b 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index bca19816e0..d9e0300425 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.6-SNAPSHOT + 13.6 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index d9b52f391a..4e83250846 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.6-SNAPSHOT + 13.6 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 7ca7ec0d5f..704d2de683 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.6-SNAPSHOT + 13.6 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index f5ecc99f3c..c9da30bbdc 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6-SNAPSHOT + 13.6 feign-vertx-parent From d2ab1781611e3f311f211a4e619113cedcd55688 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Sat, 5 Apr 2025 09:14:03 -0300 Subject: [PATCH 109/615] [ci skip] updating versions to next development iteration 13.7-SNAPSHOT --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 48 files changed, 48 insertions(+), 48 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 4ae33b8274..0219332703 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index d7acd63bcb..5b2300803b 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index e76c6310da..3361ab3e58 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index a1c4f28e48..0ec13387f2 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index bacc28907f..b986c7e253 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 01e34ceb22..147eb20ac4 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index bc697911a6..5bb2f33fe2 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 62a08d5217..a42781cc98 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index c4a97ee3a1..6b5d58c97a 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index c1a84b4260..fa6adf436f 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index aa63890d67..880c1c5d0a 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 2ac3dcb08f..05cf9ce9d3 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index b99f26e1dc..7d1cb83485 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 77d7aec304..f4b0b5372d 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-googlehttpclient diff --git a/gson/pom.xml b/gson/pom.xml index 5d98617717..fe491cdca5 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 1701031e47..cae7fca816 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 01d7564355..8df8cfa4ff 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 569d415f71..4bb63a6d4b 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 1fda85b7f4..37dd1eed76 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 15a9a80cc2..6c796d7293 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index c6fc1378c8..1d620def7a 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-jackson diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 9df611df7f..f51d4e59bc 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index c8f5b6fcef..34589ca30f 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index b29f5ec7d4..ef766c168a 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index a1f51c22a9..971d08d7b1 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index bd127a06bd..350446796b 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 77ac193009..5abe192b80 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 7ebe5a806b..1f4fa0784c 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 56fb096693..ffbfa26df9 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index c29047e480..aff8a7fcce 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 12a5615c7c..f4cd2cae7e 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 5cdbf44b73..12bbca8a80 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 1fe864cb8a..226886b0df 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 7dc317de67..2e4a79255d 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index a4700de633..ea2de614d7 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index c12aff0358..42097ee5bf 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index d92b65a250..b94bffc05d 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 9103a9d34c..b701158f20 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 1ce3aa36c3..a374146987 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index afd71dbb32..8ada7374b0 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index c3471855dd..49df184304 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index b9f1a49751..d5fed136e2 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 594b68ab22..7b85d143a1 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 5546c3f13b..d24e8d163e 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index d9e0300425..b98e22c1a1 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.6 + 13.7-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 4e83250846..5254468fb4 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.6 + 13.7-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 704d2de683..a9bf70de67 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.6 + 13.7-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index c9da30bbdc..3c7b6bd333 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign parent - 13.6 + 13.7-SNAPSHOT feign-vertx-parent From bb59bfef3bbdccd6d93e12b9f8cb1eeaf72133c8 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Sat, 5 Apr 2025 09:25:08 -0300 Subject: [PATCH 110/615] Force single thread while deploying artifacts Signed-off-by: Marvin Froeder --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index db4325f9d5..77ea2f5a7b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -93,4 +93,4 @@ jobs: run: | cp .github/files/settings.xml ~/.m2/settings.xml echo -e "$GPG_KEY" | gpg --batch --no-tty --import --yes - ./mvnw -ntp -nsu -P release -pl -:feign-benchmark -DskipTests=true deploy + ./mvnw -ntp -nsu -P release -pl -:feign-benchmark -DskipTests=true deploy -T1 From abd43f761071653587ec10e98c03e749879485cc Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Sat, 5 Apr 2025 11:52:02 -0300 Subject: [PATCH 111/615] Generate jar for feign-vertx5-test Signed-off-by: Marvin Froeder --- .../src/main/java/feign/vertx5/package-info.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 vertx/feign-vertx5-test/src/main/java/feign/vertx5/package-info.java diff --git a/vertx/feign-vertx5-test/src/main/java/feign/vertx5/package-info.java b/vertx/feign-vertx5-test/src/main/java/feign/vertx5/package-info.java new file mode 100644 index 0000000000..0d3481ece1 --- /dev/null +++ b/vertx/feign-vertx5-test/src/main/java/feign/vertx5/package-info.java @@ -0,0 +1,16 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx5; From acaf7eb5c187a5b2c95cb2d99b251f0a1b89f4b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 06:15:32 +0000 Subject: [PATCH 112/615] Bump mockito.version from 5.16.1 to 5.17.0 Bumps `mockito.version` from 5.16.1 to 5.17.0. Updates `org.mockito:mockito-core` from 5.16.1 to 5.17.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.16.1...v5.17.0) Updates `org.mockito:mockito-junit-jupiter` from 5.16.1 to 5.17.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.16.1...v5.17.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.17.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-junit-jupiter dependency-version: 5.17.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- form-spring/pom.xml | 4 ++-- form/pom.xml | 4 ++-- pom.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 05cf9ce9d3..cb53a5ded2 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -124,13 +124,13 @@ org.mockito mockito-core - 5.16.1 + 5.17.0 test org.mockito mockito-junit-jupiter - 5.16.1 + 5.17.0 test diff --git a/form/pom.xml b/form/pom.xml index 7d1cb83485..2267eafb32 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -99,13 +99,13 @@ org.mockito mockito-core - 5.16.1 + 5.17.0 test org.mockito mockito-junit-jupiter - 5.16.1 + 5.17.0 test diff --git a/pom.xml b/pom.xml index 42097ee5bf..3f49d35171 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ 5.11.4 2.18.3 3.27.3 - 5.16.1 + 5.17.0 2.0.57 1.5.3 From 37c3be64bfeac06c660b99d1c525e89b97b0d3e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 05:45:17 +0000 Subject: [PATCH 113/615] Bump kotlinx.coroutines.version from 1.10.1 to 1.10.2 Bumps `kotlinx.coroutines.version` from 1.10.1 to 1.10.2. Updates `org.jetbrains.kotlinx:kotlinx-coroutines-jdk8` from 1.10.1 to 1.10.2 - [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases) - [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md) - [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.10.1...1.10.2) Updates `org.jetbrains.kotlinx:kotlinx-coroutines-reactor` from 1.10.1 to 1.10.2 - [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases) - [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md) - [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.10.1...1.10.2) --- updated-dependencies: - dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-jdk8 dependency-version: 1.10.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-reactor dependency-version: 1.10.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index f4cd2cae7e..9dd6371f0e 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -31,7 +31,7 @@ 2.1.20 - 1.10.1 + 1.10.2 From e29092330fd3149255fc6b33e88717355b1c15ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Apr 2025 05:48:37 +0000 Subject: [PATCH 114/615] Bump com.google.guava:guava from 33.4.6-jre to 33.4.7-jre Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.4.6-jre to 33.4.7-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-version: 33.4.7-jre dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3f49d35171..47fc76b3eb 100644 --- a/pom.xml +++ b/pom.xml @@ -169,7 +169,7 @@ ${main.java.version} 4.12.0 - 33.4.6-jre + 33.4.7-jre 1.46.3 2.12.1 1.15.2 From b6b350173e953de94584788f3368a03cdc83edcc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 05:19:31 +0000 Subject: [PATCH 115/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.5.0 to 3.6.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.5.0 to 3.6.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.5.0...v3.6.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 47fc76b3eb..b62bb91d72 100644 --- a/pom.xml +++ b/pom.xml @@ -1038,7 +1038,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.5.0 + 3.6.0 From 59ec154bb8531048d01faba91611208d5ff64c22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 05:23:15 +0000 Subject: [PATCH 116/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.5.1 to 3.6.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.5.1...v3.6.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b62bb91d72..328366309f 100644 --- a/pom.xml +++ b/pom.xml @@ -1033,7 +1033,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.5.1 + 3.6.0 org.openrewrite.recipe From e1b062690821114c725965d967676ab0d4c7fdf6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 05:25:10 +0000 Subject: [PATCH 117/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.4.0 to 6.5.0 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.4.0 to 6.5.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.4.0...v6.5.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 328366309f..bab1117187 100644 --- a/pom.xml +++ b/pom.xml @@ -1027,7 +1027,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.4.0 + 6.5.0 From e192b44783d7a472a13cf30c069753e6de38cd7f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Apr 2025 05:28:22 +0000 Subject: [PATCH 118/615] Bump com.gradle:develocity-maven-extension from 1.23.2 to 2.0 Bumps com.gradle:develocity-maven-extension from 1.23.2 to 2.0. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: '2.0' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 0938661971..968d977d56 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 1.23.2 + 2.0 com.gradle From b727e16c9d264230197dabb87ba900654941c311 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 05:19:00 +0000 Subject: [PATCH 119/615] Bump org.apache.commons:commons-text from 1.13.0 to 1.13.1 Bumps org.apache.commons:commons-text from 1.13.0 to 1.13.1. --- updated-dependencies: - dependency-name: org.apache.commons:commons-text dependency-version: 1.13.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index cb53a5ded2..568395ba81 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -38,7 +38,7 @@ org.apache.commons commons-text - 1.13.0 + 1.13.1 org.projectlombok diff --git a/form/pom.xml b/form/pom.xml index 2267eafb32..099d9b4050 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -50,7 +50,7 @@ org.apache.commons commons-text - 1.13.0 + 1.13.1 test From 57506e04e39d6215615fc8ae2a8a1494daa28f08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 05:25:30 +0000 Subject: [PATCH 120/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.5.0 to 6.6.1 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.5.0 to 6.6.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.5.0...v6.6.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.6.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bab1117187..aaefd1460a 100644 --- a/pom.xml +++ b/pom.xml @@ -1027,7 +1027,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.5.0 + 6.6.1 From 1eb646abdfa5003f33bd418e45d1c78ff79df32b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 05:27:55 +0000 Subject: [PATCH 121/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.6.0 to 3.6.1. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.6.0...v3.6.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.6.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aaefd1460a..b2912fdc54 100644 --- a/pom.xml +++ b/pom.xml @@ -1033,7 +1033,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.6.0 + 3.6.1 org.openrewrite.recipe From e9d73ab9dfe97dc3619def9b34636bd9ba79a55f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 05:30:05 +0000 Subject: [PATCH 122/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.6.0 to 3.7.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.6.0 to 3.7.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.6.0...v3.7.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b2912fdc54..65371fa609 100644 --- a/pom.xml +++ b/pom.xml @@ -1038,7 +1038,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.6.0 + 3.7.0 From f713ec3a13d09a6bcb36f1badbfb22195e22b6b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 05:09:45 +0000 Subject: [PATCH 123/615] Bump com.google.code.gson:gson from 2.12.1 to 2.13.0 Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.12.1 to 2.13.0. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.12.1...gson-parent-2.13.0) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-version: 2.13.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 65371fa609..51ae1ebafc 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 4.12.0 33.4.7-jre 1.46.3 - 2.12.1 + 2.13.0 1.15.2 2.0.17 20250107 From c648816c5064bdf35cd90af7844d1dab1182fdf0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 05:16:29 +0000 Subject: [PATCH 124/615] Bump micrometer.version from 1.14.5 to 1.14.6 Bumps `micrometer.version` from 1.14.5 to 1.14.6. Updates `io.micrometer:micrometer-core` from 1.14.5 to 1.14.6 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.5...v1.14.6) Updates `io.micrometer:micrometer-test` from 1.14.5 to 1.14.6 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.5...v1.14.6) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.14.6 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-version: 1.14.6 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 12bbca8a80..dcd586d57d 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.14.5 + 1.14.6 From 0ce435d638179af22f413012502ebd14d2478bd6 Mon Sep 17 00:00:00 2001 From: Marvin Date: Mon, 14 Apr 2025 12:31:06 -0300 Subject: [PATCH 125/615] Check code coverage project wide (#2857) * Rename top level project * Check code coverage project wide Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder --- .mvn/extensions.xml | 5 +++ annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 44 +++++++++++++++++++++-- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/pom.xml | 2 +- 46 files changed, 91 insertions(+), 46 deletions(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 968d977d56..f0bcfc4f78 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -26,4 +26,9 @@ common-custom-user-data-maven-extension 2.0.1 + + com.marvinformatics.jacoco + easy-jacoco-maven-plugin + 0.1.3 + diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 0219332703..760bc3d5bb 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index 5b2300803b..c3f2cf884d 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 3361ab3e58..7d6aac2a25 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/core/pom.xml b/core/pom.xml index 0ec13387f2..2a148c9be5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index b986c7e253..4258018c99 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -20,7 +20,7 @@ 4.0.0 io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT feign-dropwizard-metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 147eb20ac4..e825314f8a 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -20,7 +20,7 @@ 4.0.0 io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT feign-dropwizard-metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 5bb2f33fe2..8f98d4f867 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/example-github/pom.xml b/example-github/pom.xml index a42781cc98..bf66534cbc 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 6b5d58c97a..30868555b2 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index fa6adf436f..d37a44e0e0 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 880c1c5d0a..794e9a7179 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 568395ba81..708bcfc18e 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/form/pom.xml b/form/pom.xml index 099d9b4050..0e794684de 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index f4b0b5372d..928c422335 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/gson/pom.xml b/gson/pom.xml index fe491cdca5..d1a946b03f 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/hc5/pom.xml b/hc5/pom.xml index cae7fca816..dad65d4569 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 8df8cfa4ff..50d7583153 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 4bb63a6d4b..34eeaefaaa 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 37dd1eed76..2e79ad6bef 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 6c796d7293..061fbb380e 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/jackson/pom.xml b/jackson/pom.xml index 1d620def7a..5035d8b94b 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/jakarta/pom.xml b/jakarta/pom.xml index f51d4e59bc..e1cff99852 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/java11/pom.xml b/java11/pom.xml index 34589ca30f..deb84b4e07 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -20,7 +20,7 @@ 4.0.0 io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index ef766c168a..44b40a63bf 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 971d08d7b1..99ab6003db 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 350446796b..1584af5975 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 5abe192b80..2ddaf0f7f2 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 1f4fa0784c..762cacd2aa 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index ffbfa26df9..fde82d6bdb 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/json/pom.xml b/json/pom.xml index aff8a7fcce..127fd1b483 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 9dd6371f0e..5c6c606f26 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/micrometer/pom.xml b/micrometer/pom.xml index dcd586d57d..995d37a532 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -20,7 +20,7 @@ 4.0.0 io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT feign-micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 226886b0df..02a2863ed3 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/moshi/pom.xml b/moshi/pom.xml index 2e4a79255d..2b3d51cf18 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/okhttp/pom.xml b/okhttp/pom.xml index ea2de614d7..db203eac55 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/pom.xml b/pom.xml index 51ae1ebafc..52715bd155 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT pom @@ -533,7 +533,7 @@ true false - ${jvm.options} + ${jvm.options} ${argLine} @@ -909,6 +909,46 @@ + + + org.jacoco + jacoco-maven-plugin + 0.8.13 + + + feign/** + + + + + com.marvinformatics.jacoco + easy-jacoco-maven-plugin + 0.1.3 + + + + + + INSTRUCTION + COVEREDRATIO + 0.70 + + + + + true + + true + + + feign/** + + + feign-benchmark + feign-apt-test-generator + + + diff --git a/reactive/pom.xml b/reactive/pom.xml index b94bffc05d..f585a3701e 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -20,7 +20,7 @@ 4.0.0 io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index b701158f20..88a205f876 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/sax/pom.xml b/sax/pom.xml index a374146987..9ad392c4e9 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 8ada7374b0..4552ec48bc 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 49df184304..6c2328fffa 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/soap/pom.xml b/soap/pom.xml index d5fed136e2..f9057e4405 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/spring/pom.xml b/spring/pom.xml index 7b85d143a1..da3d8386fd 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/spring4/pom.xml b/spring4/pom.xml index d24e8d163e..0e480f31df 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT diff --git a/vertx/pom.xml b/vertx/pom.xml index 3c7b6bd333..dd77117391 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 io.github.openfeign - parent + feign-parent 13.7-SNAPSHOT From 8ab1cce225baff29b8d414a1090ef4fd5a175297 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Apr 2025 15:32:10 +0000 Subject: [PATCH 126/615] Bump junit5.version from 5.11.4 to 5.12.2 Bumps `junit5.version` from 5.11.4 to 5.12.2. Updates `org.junit:junit-bom` from 5.11.4 to 5.12.2 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.11.4...r5.12.2) Updates `org.junit.jupiter:junit-jupiter-engine` from 5.11.4 to 5.12.2 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.11.4...r5.12.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 5.12.2 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-version: 5.12.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 52715bd155..a2939d5871 100644 --- a/pom.xml +++ b/pom.xml @@ -177,7 +177,7 @@ 20250107 3.3.5 - 5.11.4 + 5.12.2 2.18.3 3.27.3 5.17.0 From fe877f46fefbfdd42846fdafecafff37474fbd1f Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 14 Apr 2025 12:36:23 -0300 Subject: [PATCH 127/615] Move junit-jupiter-engine dependency to project Signed-off-by: Marvin Froeder --- pom.xml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index a2939d5871..b47e87980c 100644 --- a/pom.xml +++ b/pom.xml @@ -492,6 +492,11 @@ junit-jupiter-api test + + org.junit.jupiter + junit-jupiter-engine + test + org.junit.jupiter junit-jupiter @@ -538,13 +543,6 @@ - - - org.junit.jupiter - junit-jupiter-engine - ${junit5.version} - - From 744ae8dd886d623a57a5c002f118c260549f960c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 05:12:23 +0000 Subject: [PATCH 128/615] Bump com.google.guava:guava from 33.4.7-jre to 33.4.8-jre Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.4.7-jre to 33.4.8-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-version: 33.4.8-jre dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b47e87980c..97a27a6622 100644 --- a/pom.xml +++ b/pom.xml @@ -169,7 +169,7 @@ ${main.java.version} 4.12.0 - 33.4.7-jre + 33.4.8-jre 1.46.3 2.13.0 1.15.2 From 47faecfc0e372ecf66d92f1f4ffa8686755fe308 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 05:28:25 +0000 Subject: [PATCH 129/615] Bump org.springframework:spring-context from 6.2.5 to 6.2.6 Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 6.2.5 to 6.2.6. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.5...v6.2.6) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 6.2.6 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 2a148c9be5..dccd10f12c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - 6.2.5 + 6.2.6 test From bda08fb6731e03973e70fb104fcf8309dc9e90a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Apr 2025 05:51:22 +0000 Subject: [PATCH 130/615] Bump com.google.code.gson:gson from 2.13.0 to 2.13.1 Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.13.0 to 2.13.1. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.13.0...gson-parent-2.13.1) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-version: 2.13.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 97a27a6622..443d32b764 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 4.12.0 33.4.8-jre 1.46.3 - 2.13.0 + 2.13.1 1.15.2 2.0.17 20250107 From c8e0e03406ef7541dd83b5273fb4f914fe0e062a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Apr 2025 05:08:46 +0000 Subject: [PATCH 131/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.6.1 to 3.7.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.6.1...v3.7.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 443d32b764..fe0df8d2fb 100644 --- a/pom.xml +++ b/pom.xml @@ -1071,7 +1071,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.6.1 + 3.7.0 org.openrewrite.recipe From 905b6ddbf473871733b1a304cca92084057880c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Apr 2025 05:15:01 +0000 Subject: [PATCH 132/615] Bump org.apache.httpcomponents.client5:httpclient5 from 5.4.3 to 5.4.4 Bumps [org.apache.httpcomponents.client5:httpclient5](https://github.com/apache/httpcomponents-client) from 5.4.3 to 5.4.4. - [Changelog](https://github.com/apache/httpcomponents-client/blob/rel/v5.4.4/RELEASE_NOTES.txt) - [Commits](https://github.com/apache/httpcomponents-client/compare/rel/v5.4.3...rel/v5.4.4) --- updated-dependencies: - dependency-name: org.apache.httpcomponents.client5:httpclient5 dependency-version: 5.4.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- hc5/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hc5/pom.xml b/hc5/pom.xml index dad65d4569..413a83e79e 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -38,7 +38,7 @@ org.apache.httpcomponents.client5 httpclient5 - 5.4.3 + 5.4.4 From a4882b838a4d52b4b94c2ce9007f8ba51cde9a14 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Apr 2025 05:17:18 +0000 Subject: [PATCH 133/615] Bump reactor.version from 3.7.4 to 3.7.5 Bumps `reactor.version` from 3.7.4 to 3.7.5. Updates `io.projectreactor:reactor-core` from 3.7.4 to 3.7.5 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.4...v3.7.5) Updates `io.projectreactor:reactor-test` from 3.7.4 to 3.7.5 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.4...v3.7.5) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.7.5 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.7.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index f585a3701e..47a82309cd 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.7.4 + 3.7.5 1.0.4 2.2.21 From 7844930058840080f70bf0ee2dd032890d4f0fa4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Apr 2025 05:23:31 +0000 Subject: [PATCH 134/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.6.1 to 6.7.0 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.6.1 to 6.7.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.6.1...v6.7.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fe0df8d2fb..c88170b627 100644 --- a/pom.xml +++ b/pom.xml @@ -1065,7 +1065,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.6.1 + 6.7.0 From 24f907733eb65081780a9f99e91b3dba10ef813e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Apr 2025 05:27:03 +0000 Subject: [PATCH 135/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.7.0 to 3.8.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.7.0 to 3.8.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.7.0...v3.8.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.8.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c88170b627..9363610199 100644 --- a/pom.xml +++ b/pom.xml @@ -1076,7 +1076,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.7.0 + 3.8.0 From 63ae14a228dec44e885ac7e2e110eeec740ec9d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Apr 2025 05:31:17 +0000 Subject: [PATCH 136/615] Bump jackson.version from 2.18.3 to 2.19.0 Bumps `jackson.version` from 2.18.3 to 2.19.0. Updates `com.fasterxml.jackson.core:jackson-databind` from 2.18.3 to 2.19.0 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.core:jackson-core` from 2.18.3 to 2.19.0 - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.18.3...jackson-core-2.19.0) Updates `com.fasterxml.jackson.core:jackson-annotations` from 2.18.3 to 2.19.0 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.jr:jackson-jr-objects` from 2.18.3 to 2.19.0 - [Commits](https://github.com/FasterXML/jackson-jr/compare/jackson-jr-parent-2.18.3...jackson-jr-parent-2.19.0) Updates `com.fasterxml.jackson.jr:jackson-jr-annotation-support` from 2.18.3 to 2.19.0 - [Commits](https://github.com/FasterXML/jackson-jr/compare/jackson-jr-parent-2.18.3...jackson-jr-parent-2.19.0) Updates `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider` from 2.18.3 to 2.19.0 Updates `com.fasterxml.jackson:jackson-bom` from 2.18.2 to 2.19.0 - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.2...jackson-bom-2.19.0) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.19.0 dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-version: 2.19.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-version: 2.19.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.jr:jackson-jr-objects dependency-version: 2.19.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.jr:jackson-jr-annotation-support dependency-version: 2.19.0 dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-version: 2.19.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.19.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9363610199..4fb476ba0e 100644 --- a/pom.xml +++ b/pom.xml @@ -178,7 +178,7 @@ 3.3.5 5.12.2 - 2.18.3 + 2.19.0 3.27.3 5.17.0 2.0.57 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index b98e22c1a1..b4f7496096 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -31,7 +31,7 @@ 11 - 2.18.2 + 2.19.0 From cdb8f537d08080597d5246d4ba6064804ae6a55f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 05:39:07 +0000 Subject: [PATCH 137/615] Bump com.google.http-client:google-http-client from 1.46.3 to 1.47.0 Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 1.46.3 to 1.47.0. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v1.46.3...v1.47.0) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-version: 1.47.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4fb476ba0e..017851951a 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 4.12.0 33.4.8-jre - 1.46.3 + 1.47.0 2.13.1 1.15.2 2.0.17 From 7ffc8e7a3015c1cd92613d77ea743da1e22fad75 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 May 2025 05:34:14 +0000 Subject: [PATCH 138/615] Bump com.gradle:common-custom-user-data-maven-extension Bumps [com.gradle:common-custom-user-data-maven-extension](https://github.com/gradle/common-custom-user-data-maven-extension) from 2.0.1 to 2.0.2. - [Release notes](https://github.com/gradle/common-custom-user-data-maven-extension/releases) - [Commits](https://github.com/gradle/common-custom-user-data-maven-extension/compare/v2.0.1...v2.0.2) --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-maven-extension dependency-version: 2.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index f0bcfc4f78..8cba52ac0f 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -24,7 +24,7 @@ com.gradle common-custom-user-data-maven-extension - 2.0.1 + 2.0.2 com.marvinformatics.jacoco From a612fce54c0fe37532e60fbdcf73f772efb466b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 05:18:45 +0000 Subject: [PATCH 139/615] Bump netty.version from 4.2.0.Final to 4.2.1.Final Bumps `netty.version` from 4.2.0.Final to 4.2.1.Final. Updates `io.netty:netty-bom` from 4.2.0.Final to 4.2.1.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.0.Final...netty-4.2.1.Final) Updates `io.netty:netty-handler` from 4.2.0.Final to 4.2.1.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.0.Final...netty-4.2.1.Final) Updates `io.netty:netty-codec-http` from 4.2.0.Final to 4.2.1.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.0.Final...netty-4.2.1.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.1.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.1.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.1.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 7d6aac2a25..4cbfb0720c 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.0.Final + 4.2.1.Final true From acb1684bf698dfeafbc4de6d5fd6d07990be960f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 05:50:02 +0000 Subject: [PATCH 140/615] Bump org.json:json from 20250107 to 20250517 Bumps [org.json:json](https://github.com/douglascrockford/JSON-java) from 20250107 to 20250517. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/commits) --- updated-dependencies: - dependency-name: org.json:json dependency-version: '20250517' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 017851951a..dcb7646915 100644 --- a/pom.xml +++ b/pom.xml @@ -174,7 +174,7 @@ 2.13.1 1.15.2 2.0.17 - 20250107 + 20250517 3.3.5 5.12.2 From 8e8864f21dfff46a31e8999addfbbfc43407dc62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 05:57:46 +0000 Subject: [PATCH 141/615] Bump com.marvinformatics.jacoco:easy-jacoco-maven-plugin Bumps [com.marvinformatics.jacoco:easy-jacoco-maven-plugin](https://github.com/velo/easy-jacoco-maven-plugin) from 0.1.3 to 0.1.4. - [Release notes](https://github.com/velo/easy-jacoco-maven-plugin/releases) - [Commits](https://github.com/velo/easy-jacoco-maven-plugin/compare/0.1.3...0.1.4) --- updated-dependencies: - dependency-name: com.marvinformatics.jacoco:easy-jacoco-maven-plugin dependency-version: 0.1.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 8cba52ac0f..757e62f354 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -29,6 +29,6 @@ com.marvinformatics.jacoco easy-jacoco-maven-plugin - 0.1.3 + 0.1.4 diff --git a/pom.xml b/pom.xml index dcb7646915..c080f02e85 100644 --- a/pom.xml +++ b/pom.xml @@ -921,7 +921,7 @@ com.marvinformatics.jacoco easy-jacoco-maven-plugin - 0.1.3 + 0.1.4 From 0ef110b40baeb7888515b420ae9bfab84415fd74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 06:00:21 +0000 Subject: [PATCH 142/615] Bump kotlin.version from 2.1.20 to 2.1.21 Bumps `kotlin.version` from 2.1.20 to 2.1.21. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.1.20 to 2.1.21 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.20...v2.1.21) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.1.20 to 2.1.21 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.20...v2.1.21) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.1.20 to 2.1.21 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-version: 2.1.21 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-version: 2.1.21 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-version: 2.1.21 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 5c6c606f26..72411af6f1 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.1.20 + 2.1.21 1.10.2 From 84d209694b2f226911a2bf1fe001f088d37df1e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 06:08:11 +0000 Subject: [PATCH 143/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.7.0 to 6.8.1 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.7.0 to 6.8.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.7.0...v6.8.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.8.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c080f02e85..a56ed280bb 100644 --- a/pom.xml +++ b/pom.xml @@ -1065,7 +1065,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.7.0 + 6.8.1 From 0d022a06526566ff5a8aa593acbac35060f1e931 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 06:10:29 +0000 Subject: [PATCH 144/615] Bump org.springframework:spring-context from 6.2.6 to 6.2.7 Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 6.2.6 to 6.2.7. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.6...v6.2.7) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 6.2.7 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index dccd10f12c..facc2217a0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - 6.2.6 + 6.2.7 test From 7e2a9b254ac90bfd1dda7bf7122810d22de24ea5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 06:12:29 +0000 Subject: [PATCH 145/615] Bump micrometer.version from 1.14.6 to 1.15.0 Bumps `micrometer.version` from 1.14.6 to 1.15.0. Updates `io.micrometer:micrometer-core` from 1.14.6 to 1.15.0 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.6...v1.15.0) Updates `io.micrometer:micrometer-test` from 1.14.6 to 1.15.0 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.14.6...v1.15.0) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.15.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.micrometer:micrometer-test dependency-version: 1.15.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 995d37a532..fe526488e9 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.14.6 + 1.15.0 From d06f6c021e221e503750a2700a65a9e81ce573a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 06:15:18 +0000 Subject: [PATCH 146/615] Bump io.sundr:sundr-maven-plugin from 0.200.3 to 0.200.4 Bumps [io.sundr:sundr-maven-plugin](https://github.com/sundrio/sundrio) from 0.200.3 to 0.200.4. - [Commits](https://github.com/sundrio/sundrio/commits) --- updated-dependencies: - dependency-name: io.sundr:sundr-maven-plugin dependency-version: 0.200.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a56ed280bb..1e00318c37 100644 --- a/pom.xml +++ b/pom.xml @@ -195,7 +195,7 @@ 6.0.0 0.1.1 3.5.2 - 0.200.3 + 0.200.4 file://${project.basedir}/src/config/bom.xml 2.1.0 2.18.0 From 9834ff70c3928a3098a98dfd21c83f2cd1e56cbd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 06:17:42 +0000 Subject: [PATCH 147/615] Bump reactor.version from 3.7.5 to 3.7.6 Bumps `reactor.version` from 3.7.5 to 3.7.6. Updates `io.projectreactor:reactor-core` from 3.7.5 to 3.7.6 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.5...v3.7.6) Updates `io.projectreactor:reactor-test` from 3.7.5 to 3.7.6 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.5...v3.7.6) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.7.6 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.7.6 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index 47a82309cd..f8e747762d 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.7.5 + 3.7.6 1.0.4 2.2.21 From 0caa66942a11abd6b39d1e5f56d3a9bffa8e76a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 May 2025 05:52:47 +0000 Subject: [PATCH 148/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.8.1 to 6.9.0 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.8.1 to 6.9.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.8.1...v6.9.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.9.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1e00318c37..3a43a67687 100644 --- a/pom.xml +++ b/pom.xml @@ -1065,7 +1065,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.8.1 + 6.9.0 From 30096c0075436354c6508950f27d25575ad0a38d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 05:19:59 +0000 Subject: [PATCH 149/615] Bump mockito.version from 5.17.0 to 5.18.0 Bumps `mockito.version` from 5.17.0 to 5.18.0. Updates `org.mockito:mockito-core` from 5.17.0 to 5.18.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.17.0...v5.18.0) Updates `org.mockito:mockito-junit-jupiter` from 5.17.0 to 5.18.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.17.0...v5.18.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.18.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-junit-jupiter dependency-version: 5.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- form-spring/pom.xml | 4 ++-- form/pom.xml | 4 ++-- pom.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 708bcfc18e..72e0fc755f 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -124,13 +124,13 @@ org.mockito mockito-core - 5.17.0 + 5.18.0 test org.mockito mockito-junit-jupiter - 5.17.0 + 5.18.0 test diff --git a/form/pom.xml b/form/pom.xml index 0e794684de..496a4bdcad 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -99,13 +99,13 @@ org.mockito mockito-core - 5.17.0 + 5.18.0 test org.mockito mockito-junit-jupiter - 5.17.0 + 5.18.0 test diff --git a/pom.xml b/pom.xml index 3a43a67687..4b5502b38d 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ 5.12.2 2.19.0 3.27.3 - 5.17.0 + 5.18.0 2.0.57 1.5.3 From 57440c248a69eccc2fa5bbe840308cb59fc2757e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 05:27:33 +0000 Subject: [PATCH 150/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.7.0 to 3.9.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.7.0...v3.9.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.9.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4b5502b38d..35c33e2c35 100644 --- a/pom.xml +++ b/pom.xml @@ -1071,7 +1071,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.7.0 + 3.9.0 org.openrewrite.recipe From a6129c96af2eedee52b1edf1e1308c7af2640dc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 05:45:18 +0000 Subject: [PATCH 151/615] Bump org.apache.httpcomponents.client5:httpclient5 from 5.4.4 to 5.5 Bumps [org.apache.httpcomponents.client5:httpclient5](https://github.com/apache/httpcomponents-client) from 5.4.4 to 5.5. - [Changelog](https://github.com/apache/httpcomponents-client/blob/master/RELEASE_NOTES.txt) - [Commits](https://github.com/apache/httpcomponents-client/compare/rel/v5.4.4...rel/v5.5) --- updated-dependencies: - dependency-name: org.apache.httpcomponents.client5:httpclient5 dependency-version: '5.5' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- hc5/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hc5/pom.xml b/hc5/pom.xml index 413a83e79e..cca2e72999 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -38,7 +38,7 @@ org.apache.httpcomponents.client5 httpclient5 - 5.4.4 + 5.5 From d635f6a3c5f04a506e82b980e8b4b9b4395eca9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 05:53:00 +0000 Subject: [PATCH 152/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.8.0 to 3.10.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.8.0 to 3.10.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.8.0...v3.10.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.10.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 35c33e2c35..1b5cac160e 100644 --- a/pom.xml +++ b/pom.xml @@ -1076,7 +1076,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.8.0 + 3.10.0 From 7bc027848f4fce05a47ac7f1f983bdf2cf558470 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 May 2025 05:21:59 +0000 Subject: [PATCH 153/615] Bump org.apache.commons:commons-exec from 1.4.0 to 1.5.0 Bumps org.apache.commons:commons-exec from 1.4.0 to 1.5.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-exec dependency-version: 1.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 8f98d4f867..6d8762e891 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -45,7 +45,7 @@ org.apache.commons commons-exec - 1.4.0 + 1.5.0 test diff --git a/example-github/pom.xml b/example-github/pom.xml index bf66534cbc..bda16b4808 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -41,7 +41,7 @@ org.apache.commons commons-exec - 1.4.0 + 1.5.0 test diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 30868555b2..4785568870 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -66,7 +66,7 @@ org.apache.commons commons-exec - 1.4.0 + 1.5.0 test diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index d37a44e0e0..6e12e2fa90 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -42,7 +42,7 @@ org.apache.commons commons-exec - 1.4.0 + 1.5.0 test From 589450cc0d8926fc1dc81657292e5059ee800b0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 May 2025 05:29:46 +0000 Subject: [PATCH 154/615] Bump io.dropwizard.metrics:metrics-core from 4.2.30 to 4.2.32 Bumps [io.dropwizard.metrics:metrics-core](https://github.com/dropwizard/metrics) from 4.2.30 to 4.2.32. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.30...v4.2.32) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-version: 4.2.32 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- dropwizard-metrics4/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 4258018c99..9c479fa3ac 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -40,7 +40,7 @@ io.dropwizard.metrics metrics-core - 4.2.30 + 4.2.32 ${project.groupId} From 7ed003e3baf311e6879ff16fc9a5ac141f245e34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 May 2025 05:32:13 +0000 Subject: [PATCH 155/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.10.0 to 3.10.1 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.10.0 to 3.10.1. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.10.0...v3.10.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.10.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1b5cac160e..23f3caad4c 100644 --- a/pom.xml +++ b/pom.xml @@ -1076,7 +1076,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.10.0 + 3.10.1 From d87b24d8c2769b4719341034ff90cdaa86c11da3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 May 2025 20:07:24 +0000 Subject: [PATCH 156/615] Bump org.springframework:spring-web from 6.1.13 to 6.1.14 in /spring Bumps [org.springframework:spring-web](https://github.com/spring-projects/spring-framework) from 6.1.13 to 6.1.14. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.13...v6.1.14) --- updated-dependencies: - dependency-name: org.springframework:spring-web dependency-version: 6.1.14 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- spring/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring/pom.xml b/spring/pom.xml index da3d8386fd..94247d58e8 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -31,7 +31,7 @@ 17 - 6.1.13 + 6.1.14 From 546c30191eff7d6465b9d5894f4c246a8cc11fe1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 05:52:42 +0000 Subject: [PATCH 157/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.9.0 to 6.10.0 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.9.0 to 6.10.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.9.0...v6.10.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.10.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 23f3caad4c..4ddcefefbf 100644 --- a/pom.xml +++ b/pom.xml @@ -1065,7 +1065,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.9.0 + 6.10.0 From 8659684c2815893e404d294c7a64b841eb228f4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 06:00:17 +0000 Subject: [PATCH 158/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.9.0 to 3.10.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.9.0...v3.10.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.10.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4ddcefefbf..92e0e15b49 100644 --- a/pom.xml +++ b/pom.xml @@ -1071,7 +1071,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.9.0 + 3.10.0 org.openrewrite.recipe From f24a76db9c505b4ab03710c102ae5f4af9f311d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 06:02:29 +0000 Subject: [PATCH 159/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.10.1 to 3.11.0 Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.10.1 to 3.11.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.10.1...v3.11.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.11.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 92e0e15b49..bc950b0b02 100644 --- a/pom.xml +++ b/pom.xml @@ -1076,7 +1076,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.10.1 + 3.11.0 From ed34f970d23d606d9a9ebcad5d99778ca087eb1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 06:10:18 +0000 Subject: [PATCH 160/615] Bump org.springframework:spring-web in /form-spring Bumps [org.springframework:spring-web](https://github.com/spring-projects/spring-framework) from 6.1.13 to 6.1.14. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.13...v6.1.14) --- updated-dependencies: - dependency-name: org.springframework:spring-web dependency-version: 6.1.14 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- form-spring/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 72e0fc755f..2f7dd9d807 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -57,7 +57,7 @@ org.springframework spring-web - 6.1.13 + 6.1.14 compile From a1af7a4866a3398f5844b41e868b56c8863ae926 Mon Sep 17 00:00:00 2001 From: Ross Sullivan Date: Thu, 29 May 2025 21:16:35 +0900 Subject: [PATCH 161/615] docs(readme): Added java syntax highlighting to metrics code snippets (#2884) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fe0d7fc1bd..9f4115cbcb 100644 --- a/README.md +++ b/README.md @@ -1135,7 +1135,7 @@ Metric Capabilities provide a first-class Metrics API that users can tap into to #### Dropwizard Metrics 4 -``` +```java public class MyApp { public static void main(String[] args) { GitHub github = Feign.builder() @@ -1150,7 +1150,7 @@ public class MyApp { #### Dropwizard Metrics 5 -``` +```java public class MyApp { public static void main(String[] args) { GitHub github = Feign.builder() @@ -1165,7 +1165,7 @@ public class MyApp { #### Micrometer -``` +```java public class MyApp { public static void main(String[] args) { GitHub github = Feign.builder() From abfc2ba555f1a54f68dfea7ddf868cbd5e3e7d53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 05:04:09 +0000 Subject: [PATCH 162/615] Bump org.springframework.cloud:spring-cloud-dependencies Bumps [org.springframework.cloud:spring-cloud-dependencies](https://github.com/spring-cloud/spring-cloud-release) from 2023.0.3 to 2025.0.0. - [Release notes](https://github.com/spring-cloud/spring-cloud-release/releases) - [Commits](https://github.com/spring-cloud/spring-cloud-release/compare/v2023.0.3...v2025.0.0) --- updated-dependencies: - dependency-name: org.springframework.cloud:spring-cloud-dependencies dependency-version: 2025.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- example-wikipedia-with-springboot/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 4785568870..514e986546 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -39,7 +39,7 @@ org.springframework.cloud spring-cloud-dependencies - 2023.0.3 + 2025.0.0 pom import From 7d46329df39a26343594e1dc133def60c39610b4 Mon Sep 17 00:00:00 2001 From: JaeSeong Oh <41769568+rojae@users.noreply.github.com> Date: Sun, 15 Jun 2025 21:27:45 +0900 Subject: [PATCH 163/615] Add. hint message for missing @Param value (#2874) - Added a helpful hint in the exception message when @Param is missing a value and parameter name can't be resolved. - Added a unit test to cover this case. - The test is skipped if the code was compiled with the `-parameters` compiler flag. Files affected: - Contract.java - DefaultContractTest.java Fixes #2337 Co-authored-by: Marvin --- core/src/main/java/feign/Contract.java | 7 +++- .../test/java/feign/DefaultContractTest.java | 42 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/feign/Contract.java b/core/src/main/java/feign/Contract.java index 41e4fd88a5..e014121a36 100644 --- a/core/src/main/java/feign/Contract.java +++ b/core/src/main/java/feign/Contract.java @@ -327,7 +327,12 @@ public Default() { name = annotationName; } checkState( - emptyToNull(name) != null, "Param annotation was empty on param %s.", paramIndex); + emptyToNull(name) != null, + "Param annotation was empty on param %s.\nHint: %s", + paramIndex, + "Prefer using @Param(value=\"name\"), or compile your code with the -parameters flag.\n" + + "If the value is missing, Feign attempts to retrieve the parameter name from bytecode, " + + "which only works if the class was compiled with the -parameters flag."); nameParam(data, name, paramIndex); final Class expander = paramAnnotation.expander(); if (expander != Param.ToStringExpander.class) { diff --git a/core/src/test/java/feign/DefaultContractTest.java b/core/src/test/java/feign/DefaultContractTest.java index 4dbc240886..e704ca57ab 100644 --- a/core/src/test/java/feign/DefaultContractTest.java +++ b/core/src/test/java/feign/DefaultContractTest.java @@ -26,6 +26,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.net.URI; import java.time.Clock; import java.time.Instant; @@ -37,6 +39,7 @@ import java.util.Map; import java.util.SortedMap; import org.assertj.core.api.Fail; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; /** @@ -901,4 +904,43 @@ public Instant instant() { return Instant.ofEpochMilli(millis); } } + + interface NoValueParamsInterface { + @RequestLine("GET /getSomething?id={id}") + String getSomething(@Param String id); + } + + @Test + void errorMessageOnMissingParamNames() { + Assumptions.assumeTrue( + !isCompiledWithParameters(NoValueParamsInterface.class), "Skip if -parameters is enabled"); + + Throwable exception = + assertThrows( + IllegalStateException.class, + () -> contract.parseAndValidateMetadata(NoValueParamsInterface.class)); + + assertThat(exception.getMessage()) + .contains("Param annotation was empty on param 0") + .contains("Hint"); + } + + /** + * Checks whether the given class was compiled with the `-parameters` compiler flag. If parameter + * names are preserved (i.e., not default like arg0, arg1...), we assume it was. + * + * @param clazz the class to inspect + * @return true if `-parameters` was likely used, false otherwise + */ + private static boolean isCompiledWithParameters(Class clazz) { + for (Method method : clazz.getDeclaredMethods()) { + for (Parameter parameter : method.getParameters()) { + String paramName = parameter.getName(); + if (!paramName.matches("arg\\d+")) { + return true; + } + } + } + return false; + } } From b1fca1bc7edda8a3e1ba1ddef5d24ceee8591c42 Mon Sep 17 00:00:00 2001 From: JaeSeong Oh <41769568+rojae@users.noreply.github.com> Date: Sun, 15 Jun 2025 21:29:38 +0900 Subject: [PATCH 164/615] Add. two new constructors to RetryableException: (#2871) - A constructor without retryAfter and without cause - A constructor without retryAfter but with cause Standardized JavaDoc across all RetryableException constructors These new constructors remove overload ambiguity when retryAfter is not needed. Add. a unit test to verify the new constructors. - canCreateRetryableExceptionWithoutRetryAfter - canCreateRetryableExceptionWithoutRetryAfterAndWithCause Fixes #2458 --- .../main/java/feign/RetryableException.java | 112 +++++++++++++++++- core/src/test/java/feign/RetryerTest.java | 27 +++++ 2 files changed, 134 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/feign/RetryableException.java b/core/src/main/java/feign/RetryableException.java index 60f9648bd2..2e210fef6d 100644 --- a/core/src/main/java/feign/RetryableException.java +++ b/core/src/main/java/feign/RetryableException.java @@ -32,8 +32,58 @@ public class RetryableException extends FeignException { private final HttpMethod httpMethod; /** - * @param retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header. If you - * don't want to retry, set null. + * Represents a non-retryable exception when Retry-After information is explicitly not provided. + * + *

Use this constructor when the server response does not include a Retry-After header or when + * retries are not expected. + * + * @param status the HTTP status code + * @param message the exception message + * @param httpMethod the HTTP method (GET, POST, etc.) + * @param request the original HTTP request + */ + public RetryableException(int status, String message, HttpMethod httpMethod, Request request) { + super(status, message, request); + this.httpMethod = httpMethod; + this.retryAfter = null; + } + + /** + * Represents a non-retryable exception when Retry-After information is explicitly not provided. + * + *

Use this constructor when the server response does not include a Retry-After header or when + * retries are not expected. + * + * @param status the HTTP status code + * @param message the exception message + * @param httpMethod the HTTP method (GET, POST, etc.) + * @param cause the underlying cause of the exception + * @param request the original HTTP request + */ + public RetryableException( + int status, String message, HttpMethod httpMethod, Throwable cause, Request request) { + super(status, message, request, cause); + this.httpMethod = httpMethod; + this.retryAfter = null; + } + + /** + * Represents a retryable exception when Retry-After information is available. + * + *

Use this constructor when the server response includes a Retry-After header specifying the + * delay in milliseconds before retrying. + * + *

If {@code retryAfter} is {@code null}, prefer using {@link #RetryableException(int, String, + * HttpMethod, Throwable, Request)} instead. + * + * @param status the HTTP status code + * @param message the exception message + * @param httpMethod the HTTP method (GET, POST, etc.) + * @param cause the underlying cause of the exception + * @param retryAfter the retry delay in milliseconds retryAfter usually corresponds to the {@link + * feign.Util#RETRY_AFTER} header. If you don't want to retry, use {@link + * #RetryableException(int, String, HttpMethod, Throwable, Request)}. + * @param request the original HTTP request */ public RetryableException( int status, @@ -47,6 +97,17 @@ public RetryableException( this.retryAfter = retryAfter; } + /** + * @deprecated Use {@link #RetryableException(int, String, HttpMethod, Throwable, Long, Request)} + * instead. This constructor uses {@link Date} for retryAfter, which has been replaced by + * {@link Long}. + * @param status the HTTP status code + * @param message the exception message + * @param httpMethod the HTTP method (GET, POST, etc.) + * @param cause the underlying cause of the exception + * @param retryAfter the retry-after time as a {@link Date} + * @param request the original HTTP request + */ @Deprecated public RetryableException( int status, @@ -61,8 +122,17 @@ public RetryableException( } /** - * @param retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header. If you - * don't want to retry, set null. + * Represents a retryable exception when Retry-After information is available. + * + *

Use this constructor when the server response includes a Retry-After header. + * + * @param status the HTTP status code + * @param message the exception message + * @param httpMethod the HTTP method (GET, POST, etc.) + * @param retryAfter the retry delay in milliseconds retryAfter usually corresponds to the {@link + * feign.Util#RETRY_AFTER} header. If you don't want to retry, use {@link + * #RetryableException(int, String, HttpMethod, Request)} + * @param request the original HTTP request */ public RetryableException( int status, String message, HttpMethod httpMethod, Long retryAfter, Request request) { @@ -71,6 +141,15 @@ public RetryableException( this.retryAfter = retryAfter; } + /** + * @deprecated Use {@link #RetryableException(int, String, HttpMethod, Long, Request)} instead. + * This constructor uses {@link Date} for retryAfter, which has been replaced by {@link Long}. + * @param status the HTTP status code + * @param message the exception message + * @param httpMethod the HTTP method (GET, POST, etc.) + * @param retryAfter the retry-after time as a {@link Date} + * @param request the original HTTP request + */ @Deprecated public RetryableException( int status, String message, HttpMethod httpMethod, Date retryAfter, Request request) { @@ -80,7 +159,18 @@ public RetryableException( } /** - * @param retryAfter usually corresponds to the {@link feign.Util#RETRY_AFTER} header. + * Represents a retryable exception with response body and headers. + * + *

Use this constructor when handling HTTP responses that include Retry-After information. + * + * @param status the HTTP status code + * @param message the exception message + * @param httpMethod the HTTP method (GET, POST, etc.) + * @param retryAfter the retry delay in milliseconds retryAfter usually corresponds to the {@link + * feign.Util#RETRY_AFTER} header. + * @param request the original HTTP request + * @param responseBody the HTTP response body + * @param responseHeaders the HTTP response headers */ public RetryableException( int status, @@ -95,6 +185,18 @@ public RetryableException( this.retryAfter = retryAfter; } + /** + * @deprecated Use {@link #RetryableException(int, String, HttpMethod, Long, Request, byte[], + * Map)} instead. This constructor uses {@link Date} for retryAfter, which has been replaced + * by {@link Long}. + * @param status the HTTP status code + * @param message the exception message + * @param httpMethod the HTTP method (GET, POST, etc.) + * @param retryAfter the retry-after time as a {@link Date} + * @param request the original HTTP request + * @param responseBody the HTTP response body + * @param responseHeaders the HTTP response headers + */ @Deprecated public RetryableException( int status, diff --git a/core/src/test/java/feign/RetryerTest.java b/core/src/test/java/feign/RetryerTest.java index 8750c3862b..2b1d604819 100644 --- a/core/src/test/java/feign/RetryerTest.java +++ b/core/src/test/java/feign/RetryerTest.java @@ -96,4 +96,31 @@ void defaultRetryerFailsOnInterruptedException() { assertThat(e).as("Unexpected exception found").isEqualTo(expected); } } + + @Test + void canCreateRetryableExceptionWithoutRetryAfter() { + RetryableException exception = + new RetryableException(500, "Internal Server Error", Request.HttpMethod.GET, REQUEST); + + assertThat(exception.status()).isEqualTo(500); + assertThat(exception.getMessage()).contains("Internal Server Error"); + assertThat(exception.method()).isEqualTo(Request.HttpMethod.GET); + assertThat(exception.retryAfter()).isNull(); + } + + @Test + void canCreateRetryableExceptionWithoutRetryAfterAndWithCause() { + Throwable cause = new IllegalArgumentException("Illegal argument exception"); + + try { + throw new RetryableException( + 500, "Internal Server Error", Request.HttpMethod.GET, cause, REQUEST); + } catch (RetryableException exception) { + assertThat(exception.status()).isEqualTo(500); + assertThat(exception.getMessage()).contains("Internal Server Error"); + assertThat(exception.method()).isEqualTo(Request.HttpMethod.GET); + assertThat(exception.retryAfter()).isNull(); + assertThat(exception.getCause()).isEqualTo(cause); + } + } } From ed7f8a4f24d207dfa580628464dd866643191be8 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 18 Jul 2025 03:18:33 -0300 Subject: [PATCH 165/615] Add CLAUDE.md with development guidance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provides essential build commands, project architecture overview, and development notes for future Claude Code instances working with this repository. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- CLAUDE.md | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..8eab9bf87e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,81 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Build Commands + +### Essential Build Commands +- `mvn clean install` - Default build command (installs all modules) +- `mvn clean install -Pdev` - **ALWAYS use this profile for development** - enables code formatting and other dev tools +- `mvn clean install -Pquickbuild` - Skip tests and validation for faster builds +- `mvn test` - Run all tests +- `mvn test -Dtest=ClassName` - Run specific test class + +### Module-specific Commands +- `mvn clean install -pl core` - Build only the core module +- `mvn clean install -pl core,gson` - Build specific modules +- `mvn clean test -pl core -Dtest=FeignTest` - Run specific test in specific module + +### Code Quality +- Code is automatically formatted using Google Java Format via git hooks +- License headers are enforced via maven-license-plugin +- Use `mvn validate` to check formatting and license compliance + +## Project Architecture + +### Core Architecture +Feign is a declarative HTTP client library with a modular design: + +**Core Module (`core/`)**: Contains the main Feign API and implementation +- `Feign.java` - Main factory class for creating HTTP clients +- `Client.java` - HTTP client abstraction (default implementation + pluggable alternatives) +- `Contract.java` - Annotation processing interface (Default, JAX-RS, Spring contracts) +- `Encoder/Decoder.java` - Request/response serialization interfaces +- `Target.java` - Represents the remote HTTP service to invoke +- `RequestTemplate.java` - Template for building HTTP requests with parameter substitution +- `MethodMetadata.java` - Metadata about interface methods and their annotations + +**Integration Modules**: Each module provides integration with specific libraries: +- `gson/`, `jackson/`, `fastjson2/` - JSON serialization +- `okhttp/`, `httpclient/`, `hc5/`, `java11/` - HTTP client implementations +- `jaxrs/`, `jaxrs2/`, `jaxrs3/` - JAX-RS annotation support +- `spring/` - Spring MVC annotation support +- `hystrix/` - Circuit breaker integration +- `micrometer/`, `dropwizard-metrics4/5/` - Metrics integration + +### Key Design Patterns +- **Builder Pattern**: `Feign.builder()` for configuring clients +- **Factory Pattern**: `Feign.newInstance(Target)` creates proxy instances +- **Strategy Pattern**: Pluggable `Client`, `Encoder`, `Decoder`, `Contract` implementations +- **Template Method**: `RequestTemplate` for building HTTP requests with parameter substitution +- **Proxy Pattern**: Dynamic proxies created for interface-based clients + +### Multi-module Maven Structure +- Parent POM manages dependencies and common configuration +- Each integration is a separate Maven module +- Modules can be built independently: `mvn clean install -pl module-name` +- Example modules depend on `feign-core` and their respective 3rd party libraries + +### Testing Strategy +- `feign-core` contains `AbstractClientTest` base class for testing HTTP clients +- Each module has its own test suite +- Integration tests use MockWebServer for HTTP mocking +- Tests are run with JUnit 5 and AssertJ assertions + +## Development Notes + +### Code Style +- Google Java Format is enforced via git hooks +- Code is formatted automatically on commit +- Package-private visibility is preferred over public when possible +- 3rd party dependencies are minimized in core module + +### Module Dependencies +- Core module: Minimal dependencies (only what's needed for HTTP client abstraction) +- Integration modules: Add specific 3rd party libraries (Jackson, OkHttp, etc.) +- BOM (Bill of Materials) manages version consistency across modules + +### Java Version Support +- Source/target: Java 8 (for `src/main`) +- Tests: Java 21 (for `src/test`) +- Maintains backwards compatibility with Java 8 in main codebase \ No newline at end of file From 196f2820c19f8a40bc27738ba2e57ce5d7e78081 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Sun, 20 Jul 2025 11:54:10 -0300 Subject: [PATCH 166/615] Temporarily disable Http2ClientReconnectTest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disabling these tests to prevent build failures while seeking assistance from contributors familiar with the HTTP/2 reconnection test implementation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../src/test/java/feign/vertx/Http2ClientReconnectTest.java | 2 ++ .../src/test/java/feign/vertx/Http2ClientReconnectTest.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java index cb75fb960a..522edac847 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/Http2ClientReconnectTest.java @@ -25,9 +25,11 @@ import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.client.WebClientOptions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; @DisplayName("Tests of reconnection with HTTP 2") +@Disabled("Temporarily disabled - requires assistance from contributors familiar with this test") class Http2ClientReconnectTest extends AbstractClientReconnectTest { @BeforeAll diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http2ClientReconnectTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http2ClientReconnectTest.java index 244b9f67de..e6612729c3 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http2ClientReconnectTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http2ClientReconnectTest.java @@ -24,9 +24,11 @@ import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.client.WebClientOptions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; @DisplayName("Tests of reconnection with HTTP 2") +@Disabled("Temporarily disabled - requires assistance from contributors familiar with this test") class Http2ClientReconnectTest extends AbstractClientReconnectTest { @BeforeAll From e0204ae111ea508d0ebea22cf20d05a44f8d0224 Mon Sep 17 00:00:00 2001 From: Marvin Date: Mon, 21 Jul 2025 05:50:42 -0300 Subject: [PATCH 167/615] Restore CircleCI configuration (#2959) * Restore CircleCI configuration Signed-off-by: Marvin Froeder * Convert CircleCI to VM with SDKMAN Java installation for testcontainer support * Cache dependencies Signed-off-by: Marvin Froeder * Remove build githubaction Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder --- .circleci/config.yml | 210 ++++++++++++++++++++++++++++++++++++ .circleci/settings.xml | 38 +++++++ .circleci/toolchains.xml | 53 +++++++++ .github/workflows/build.yml | 96 ----------------- 4 files changed, 301 insertions(+), 96 deletions(-) create mode 100644 .circleci/config.yml create mode 100644 .circleci/settings.xml create mode 100644 .circleci/toolchains.xml delete mode 100644 .github/workflows/build.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000..8ee1d4300c --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,210 @@ +# +# Copyright 2012-2020 The Feign Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed under the License +# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +# or implied. See the License for the specific language governing permissions and limitations under +# the License. +# + +# common executors +executors: + java: + machine: + image: ubuntu-2204:2023.10.1 + +# common commands +commands: + setup-build-environment: + description: 'Setup Java and Maven dependencies with unified caching' + steps: + - restore_cache: + keys: + - dependencies-v1-{{ checksum "pom.xml" }} + - run: + name: 'Check if cache was restored' + command: | + if [ -d "$HOME/.sdkman/candidates/java/21.0.2-tem" ] && [ -d ~/.m2/repository/io/github/openfeign ]; then + echo "Complete cache hit detected - SDKMAN and Maven dependencies available." + circleci step halt + elif [ -d "$HOME/.sdkman/candidates/java/21.0.2-tem" ]; then + echo "SDKMAN cache hit detected, but need to download Maven dependencies." + elif [ -d ~/.m2/repository/io/github/openfeign ]; then + echo "Maven cache hit detected, but need to install SDKMAN." + else + echo "No cache hit, setting up complete build environment." + fi + - run: + name: 'Install SDKMAN!' + command: | + if [ ! -d "$HOME/.sdkman" ]; then + curl -s "https://get.sdkman.io" | bash + fi + source "$HOME/.sdkman/bin/sdkman-init.sh" + - run: + name: 'Install JDKs (8, 11, 17, 21)' + command: | + source "$HOME/.sdkman/bin/sdkman-init.sh" + jdk_versions=("8.0.382-tem" "11.0.22-tem" "17.0.10-tem" "21.0.2-tem") + for jdk_version in "${jdk_versions[@]}"; do + if [ ! -d "$HOME/.sdkman/candidates/java/$jdk_version" ]; then + echo "n" | sdk install java "$jdk_version" || true + fi + done + sdk default java 21.0.2-tem + - run: + name: 'Configure Maven Toolchain' + command: | + mkdir -p ~/.m2 + cp .circleci/toolchains.xml ~/.m2/toolchains.xml + - run: + name: 'Download Maven dependencies' + command: | + source "$HOME/.sdkman/bin/sdkman-init.sh" + ./mvnw -ntp -B \ + org.apache.maven.plugins:maven-dependency-plugin:3.8.1:go-offline \ + de.qaware.maven:go-offline-maven-plugin:1.2.8:resolve-dependencies \ + -T2 -pl -:feign-benchmark + - save_cache: + paths: + - ~/.sdkman + - ~/.m2 + key: dependencies-v1-{{ checksum "pom.xml" }} + restore-build-environment: + description: 'Restore cached build environment' + steps: + - restore_cache: + keys: + - dependencies-v1-{{ checksum "pom.xml" }} + verify-formatting: + steps: + - run: + name: 'Verify formatting' + command: | + scripts/no-git-changes.sh + configure-gpg: + steps: + - run: + name: 'Configure GPG keys' + command: | + echo -e "$GPG_KEY" | gpg --batch --no-tty --import --yes + nexus-deploy: + steps: + - run: + name: 'Deploy Core Modules Sonatype' + command: | + source "$HOME/.sdkman/bin/sdkman-init.sh" + ./mvnw -ntp -nsu -s .circleci/settings.xml -P release -pl -:feign-benchmark -DskipTests=true deploy + +# our job defaults +defaults: &defaults + working_directory: ~/feign + environment: + # Customize the JVM maximum heap limit + MAVEN_OPTS: -Xmx3200m + +# branch filters +master-only: &master-only + branches: + only: master + +tags-only: &tags-only + branches: + ignore: /.*/ + tags: + only: /.*/ + +all-branches: &all-branches + branches: + ignore: master + tags: + ignore: /.*/ + +version: 2.1 + +jobs: + setup-build-environment: + executor: + name: java + <<: *defaults + steps: + - checkout + - setup-build-environment + + test: + executor: + name: java + <<: *defaults + steps: + - checkout + - restore-build-environment + - run: + name: 'Test' + command: | + source "$HOME/.sdkman/bin/sdkman-init.sh" + ./mvnw -ntp -B verify + - verify-formatting + + deploy: + executor: + name: java + <<: *defaults + steps: + - checkout + - restore-build-environment + - configure-gpg + - nexus-deploy + +workflows: + version: 2 + build: + jobs: + - setup-build-environment: + name: 'setup-environment' + filters: + <<: *all-branches + - test: + name: 'pr-build' + requires: + - 'setup-environment' + filters: + <<: *all-branches + + snapshot: + jobs: + - setup-build-environment: + name: 'setup-environment-snapshot' + filters: + <<: *master-only + - test: + name: 'snapshot' + requires: + - 'setup-environment-snapshot' + filters: + <<: *master-only + - deploy: + name: 'deploy snapshot' + requires: + - 'snapshot' + context: Sonatype + filters: + <<: *master-only + + release: + jobs: + - setup-build-environment: + name: 'setup-environment-release' + filters: + <<: *tags-only + - deploy: + name: 'release to maven central' + requires: + - 'setup-environment-release' + context: Sonatype + filters: + <<: *tags-only \ No newline at end of file diff --git a/.circleci/settings.xml b/.circleci/settings.xml new file mode 100644 index 0000000000..b7f976093f --- /dev/null +++ b/.circleci/settings.xml @@ -0,0 +1,38 @@ + + + + + ossrh + ${env.SONATYPE_USER} + ${env.SONATYPE_PASSWORD} + + + + + ossrh + + true + + + ${env.GPG_PASSPHRASE} + + + + \ No newline at end of file diff --git a/.circleci/toolchains.xml b/.circleci/toolchains.xml new file mode 100644 index 0000000000..d6ef9d38d3 --- /dev/null +++ b/.circleci/toolchains.xml @@ -0,0 +1,53 @@ + + + + jdk + + 1.8 + + + /home/circleci/.sdkman/candidates/java/8.0.382-tem + + + + jdk + + 11 + + + /home/circleci/.sdkman/candidates/java/11.0.22-tem + + + + jdk + + 17 + + + /home/circleci/.sdkman/candidates/java/17.0.10-tem + + + + jdk + + 21 + + + /home/circleci/.sdkman/candidates/java/21.0.2-tem + + + \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 77ea2f5a7b..0000000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,96 +0,0 @@ -# -# Copyright 2012-2020 The Feign Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except -# in compliance with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed under the License -# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions and limitations under -# the License. -# -name: Build - -on: - push: - branches: - - master - tags: - - '*' # Runs on all new tags - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - timeout-minutes: 30 - env: - # Customize the JVM maximum heap limit - MAVEN_OPTS: -Xmx3200m - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.ref }} - repository: ${{ github.event.pull_request.head.repo.full_name }} - - - name: Cache local Maven repository - uses: actions/cache@v3 - continue-on-error: true - with: - path: ~/.m2 - key: ${{ runner.os }}-maven-${{ matrix.language }} ${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-${{ matrix.language }} - ${{ runner.os }}-maven- - - - name: Cache SDKMAN JDKs - uses: actions/cache@v4 - with: - path: ~/.sdkman - key: sdkman-java-${{ runner.os }}-${{ hashFiles('~/.m2/toolchains.xml') }} - restore-keys: sdkman-java-${{ runner.os }}- - - - name: Install SDKMAN! - run: | - if [ ! -d "$HOME/.sdkman" ]; then - curl -s "https://get.sdkman.io" | bash - fi - source "$HOME/.sdkman/bin/sdkman-init.sh" - - - name: Install JDKs (8, 11, 17, 21) - run: | - source "$HOME/.sdkman/bin/sdkman-init.sh" - jdk_versions=("8.0.382-tem" "11.0.22-tem" "17.0.10-tem" "21.0.2-tem") - for jdk_version in "${jdk_versions[@]}"; do - if [ ! -d "$HOME/.sdkman/candidates/java/$jdk_version" ]; then - yes n | sdk install java "$jdk_version" - fi - done - sdk default java 21.0.2-tem - - - name: Configure Maven Toolchain - run: | - mkdir -p ~/.m2 - cp .github/files/toolchains.xml ~/.m2/toolchains.xml - - - name: Download dependencies only - run: ./mvnw -ntp -B org.apache.maven.plugins:maven-dependency-plugin:3.8.1:go-offline de.qaware.maven:go-offline-maven-plugin:1.2.8:resolve-dependencies -fn - - - name: Build - run: ./mvnw -ntp -B clean install - - - name: Verify formatting - run: scripts/no-git-changes.sh - - - name: Nexus deploy - if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/') - env: - GPG_KEY: ${{ secrets.GPG_KEY }} - SONATYPE_USER: ${{ secrets.SONATYPE_USER }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} - run: | - cp .github/files/settings.xml ~/.m2/settings.xml - echo -e "$GPG_KEY" | gpg --batch --no-tty --import --yes - ./mvnw -ntp -nsu -P release -pl -:feign-benchmark -DskipTests=true deploy -T1 From 690cb6557787bbb6c38febc29cade9f1907b70ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 08:54:09 +0000 Subject: [PATCH 168/615] Bump io.dropwizard.metrics:metrics-core from 4.2.32 to 4.2.33 Bumps [io.dropwizard.metrics:metrics-core](https://github.com/dropwizard/metrics) from 4.2.32 to 4.2.33. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.32...v4.2.33) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-version: 4.2.33 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- dropwizard-metrics4/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 9c479fa3ac..86442a5135 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -40,7 +40,7 @@ io.dropwizard.metrics metrics-core - 4.2.32 + 4.2.33 ${project.groupId} From ea4b7bb274b5a72a155fd6ed30c03db2c1b2aae1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 09:06:20 +0000 Subject: [PATCH 169/615] Bump reactor.version from 3.7.6 to 3.7.8 Bumps `reactor.version` from 3.7.6 to 3.7.8. Updates `io.projectreactor:reactor-core` from 3.7.6 to 3.7.8 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.6...v3.7.8) Updates `io.projectreactor:reactor-test` from 3.7.6 to 3.7.8 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.6...v3.7.8) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.7.8 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.7.8 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index f8e747762d..4c7e80488f 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.7.6 + 3.7.8 1.0.4 2.2.21 From 8b3eb9e37d13d7a1589f10f7e5cbcc31bd022cc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 09:16:09 +0000 Subject: [PATCH 170/615] Bump org.springframework:spring-context from 6.2.7 to 6.2.9 --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 6.2.9 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index facc2217a0..415b421f92 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - 6.2.7 + 6.2.9 test From c65be3d7cb744128bb17869e7871e83508b48832 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 09:29:13 +0000 Subject: [PATCH 171/615] Bump org.moditect:moditect-maven-plugin from 1.2.2.Final to 1.3.0.Final --- updated-dependencies: - dependency-name: org.moditect:moditect-maven-plugin dependency-version: 1.3.0.Final dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bc950b0b02..ed68975301 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 3.2.7 3.1.4 1.2.2 - 1.2.2.Final + 1.3.0.Final From 71cf9927dd6f9defdc87b58fce9d66d942d1dd72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 09:41:01 +0000 Subject: [PATCH 172/615] Bump netty.version from 4.2.1.Final to 4.2.3.Final Bumps `netty.version` from 4.2.1.Final to 4.2.3.Final. Updates `io.netty:netty-bom` from 4.2.1.Final to 4.2.3.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.1.Final...netty-4.2.3.Final) Updates `io.netty:netty-handler` from 4.2.1.Final to 4.2.3.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.1.Final...netty-4.2.3.Final) Updates `io.netty:netty-codec-http` from 4.2.1.Final to 4.2.3.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.1.Final...netty-4.2.3.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.3.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.3.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.3.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 4cbfb0720c..928754f30f 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.1.Final + 4.2.3.Final true From 982531a26ece780ac3017fd86ffdd9f97a23252e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 09:49:32 +0000 Subject: [PATCH 173/615] Bump kotlin.version from 2.1.21 to 2.2.0 Bumps `kotlin.version` from 2.1.21 to 2.2.0. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.1.21 to 2.2.0 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v2.2.0/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.21...v2.2.0) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.1.21 to 2.2.0 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v2.2.0/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.21...v2.2.0) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.1.21 to 2.2.0 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 72411af6f1..19ed595cbf 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.1.21 + 2.2.0 1.10.2 From 1427ae28255080f42360b927f4e8da297b27283b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 09:59:22 +0000 Subject: [PATCH 174/615] Bump micrometer.version from 1.15.0 to 1.15.2 Bumps `micrometer.version` from 1.15.0 to 1.15.2. Updates `io.micrometer:micrometer-core` from 1.15.0 to 1.15.2 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.15.0...v1.15.2) Updates `io.micrometer:micrometer-test` from 1.15.0 to 1.15.2 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.15.0...v1.15.2) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.15.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-version: 1.15.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index fe526488e9..c6fd73623f 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.15.0 + 1.15.2 From c96fbdb86f5fb6dba3b5fe12aa1e672938bc3bde Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:12:37 +0000 Subject: [PATCH 175/615] Bump com.gradle:develocity-maven-extension from 2.0 to 2.1 Bumps com.gradle:develocity-maven-extension from 2.0 to 2.1. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: '2.1' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 757e62f354..4b37029b1c 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.0 + 2.1 com.gradle From ef889c9a8b6800cc5e54a0b12d622be097682156 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:24:47 +0000 Subject: [PATCH 176/615] Bump org.apache.maven.plugins:maven-enforcer-plugin from 3.5.0 to 3.6.1 Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.5.0 to 3.6.1. - [Release notes](https://github.com/apache/maven-enforcer/releases) - [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.5.0...enforcer-3.6.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-enforcer-plugin dependency-version: 3.6.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ed68975301..b632900c4e 100644 --- a/pom.xml +++ b/pom.xml @@ -890,7 +890,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.5.0 + 3.6.1 enforce-no-repositories From 0aa300a46f0c78683f19327a983a4555a382ee39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:37:38 +0000 Subject: [PATCH 177/615] Bump jackson.version from 2.19.0 to 2.19.2 --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.19.2 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-version: 2.19.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-version: 2.19.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jr:jackson-jr-objects dependency-version: 2.19.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jr:jackson-jr-annotation-support dependency-version: 2.19.2 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-version: 2.19.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.19.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b632900c4e..aec0c88b2b 100644 --- a/pom.xml +++ b/pom.xml @@ -178,7 +178,7 @@ 3.3.5 5.12.2 - 2.19.0 + 2.19.2 3.27.3 5.18.0 2.0.57 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index b4f7496096..b1847eda3b 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -31,7 +31,7 @@ 11 - 2.19.0 + 2.19.2 From 176fccc5baff86f7cf4e3f23ab0ca562b9fc10fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:53:13 +0000 Subject: [PATCH 178/615] Bump org.openrewrite.maven:rewrite-maven-plugin from 6.10.0 to 6.13.0 Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.10.0 to 6.13.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.10.0...v6.13.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.13.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aec0c88b2b..c2bda1774d 100644 --- a/pom.xml +++ b/pom.xml @@ -1065,7 +1065,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.10.0 + 6.13.0 From 2f55f4d6e1720664f4ec0977f72d2e743bccfbb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 11:12:40 +0000 Subject: [PATCH 179/615] Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.10.0 to 3.13.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.10.0...v3.13.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.13.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c2bda1774d..a8c9568377 100644 --- a/pom.xml +++ b/pom.xml @@ -1071,7 +1071,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.10.0 + 3.13.0 org.openrewrite.recipe From d7b9b4526e5e17bbfaf0f5a122977d16416ce5af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:08:29 -0300 Subject: [PATCH 180/615] Bump org.openrewrite.recipe:rewrite-migrate-java from 3.11.0 to 3.13.0 (#2941) Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.11.0 to 3.13.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.11.0...v3.13.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.13.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a8c9568377..44dcf8fd2e 100644 --- a/pom.xml +++ b/pom.xml @@ -1076,7 +1076,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.11.0 + 3.13.0 From 231c6cbc843ded3a39d0c2bd997f2891d76bdc37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:08:42 -0300 Subject: [PATCH 181/615] Bump org.apache.maven.plugins:maven-gpg-plugin from 3.2.7 to 3.2.8 (#2932) Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.7 to 3.2.8. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.7...maven-gpg-plugin-3.2.8) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-version: 3.2.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 44dcf8fd2e..4cd30d4467 100644 --- a/pom.xml +++ b/pom.xml @@ -199,7 +199,7 @@ file://${project.basedir}/src/config/bom.xml 2.1.0 2.18.0 - 3.2.7 + 3.2.8 3.1.4 1.2.2 1.3.0.Final From e106a18ad877401b219b35741d4198dd0aada6dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:08:45 -0300 Subject: [PATCH 182/615] Bump vertx.version from 5.0.0.CR5 to 5.0.1 (#2926) * Bump vertx.version from 5.0.0.CR5 to 5.0.1 Bumps `vertx.version` from 5.0.0.CR5 to 5.0.1. Updates `io.vertx:vertx-core` from 5.0.0.CR5 to 5.0.1 - [Commits](https://github.com/eclipse/vert.x/commits/5.0.1) Updates `io.vertx:vertx-web-client` from 4.5.14 to 5.0.1 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.14...5.0.1) Updates `io.vertx:vertx-junit5` from 4.5.14 to 5.0.1 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.14...5.0.1) --- updated-dependencies: - dependency-name: io.vertx:vertx-core dependency-version: 5.0.1 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 5.0.1 dependency-type: direct:production update-type: version-update:semver-major - dependency-name: io.vertx:vertx-junit5 dependency-version: 5.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Update pom.xml --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin --- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index a9bf70de67..02367decda 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.0.0.CR5 + 5.0.1 diff --git a/vertx/pom.xml b/vertx/pom.xml index dd77117391..a3febc950a 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -34,7 +34,7 @@ - 5.0.0.CR5 + 5.0.1 2.0.16 3.0.1 From 170f44e9a54bfb8b58d7bf81ec44d88e42e1e967 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:08:47 -0300 Subject: [PATCH 183/615] Bump com.google.http-client:google-http-client from 1.47.0 to 1.47.1 (#2925) Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 1.47.0 to 1.47.1. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v1.47.0...v1.47.1) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-version: 1.47.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4cd30d4467..815703ae09 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 4.12.0 33.4.8-jre - 1.47.0 + 1.47.1 2.13.1 1.15.2 2.0.17 From 176a4011d9c5aba8c43517892c2f171ec62429db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:12:17 -0300 Subject: [PATCH 184/615] build(deps): Bump com.gradle:common-custom-user-data-maven-extension (#2913) Bumps [com.gradle:common-custom-user-data-maven-extension](https://github.com/gradle/common-custom-user-data-maven-extension) from 2.0.2 to 2.0.3. - [Release notes](https://github.com/gradle/common-custom-user-data-maven-extension/releases) - [Commits](https://github.com/gradle/common-custom-user-data-maven-extension/compare/v2.0.2...v2.0.3) --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-maven-extension dependency-version: 2.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 4b37029b1c..085ff38f35 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -24,7 +24,7 @@ com.gradle common-custom-user-data-maven-extension - 2.0.2 + 2.0.3 com.marvinformatics.jacoco From 66fe8be9a272090d7fe1bca980352bc7c62f63f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:12:45 -0300 Subject: [PATCH 185/615] build(deps): Bump org.springframework:spring-web in /spring (#2918) Bumps [org.springframework:spring-web](https://github.com/spring-projects/spring-framework) from 6.1.14 to 6.1.21. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.14...v6.1.21) --- updated-dependencies: - dependency-name: org.springframework:spring-web dependency-version: 6.1.21 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- spring/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring/pom.xml b/spring/pom.xml index 94247d58e8..e27e4e4d97 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -31,7 +31,7 @@ 17 - 6.1.14 + 6.1.21 From 3e5dec6a091b6fa38e69bf3b789328ccd7f9dc2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Jul 2025 05:08:13 +0000 Subject: [PATCH 186/615] build(deps): Bump commons-codec:commons-codec from 1.18.0 to 1.19.0 Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.18.0 to 1.19.0. - [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.18.0...rel/commons-codec-1.19.0) --- updated-dependencies: - dependency-name: commons-codec:commons-codec dependency-version: 1.19.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- httpclient/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 50d7583153..198b2872ee 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -38,7 +38,7 @@ --> commons-codec commons-codec - 1.18.0 + 1.19.0 From f48b95543758c32e640037b71dc1ac8591510d28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Jul 2025 05:18:18 +0000 Subject: [PATCH 187/615] build(deps): Bump org.junit:junit-bom from 5.12.2 to 5.13.4 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 5.12.2 to 5.13.4. - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r5.12.2...r5.13.4) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 5.13.4 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 815703ae09..c7c18fb98d 100644 --- a/pom.xml +++ b/pom.xml @@ -177,7 +177,7 @@ 20250517 3.3.5 - 5.12.2 + 5.13.4 2.19.2 3.27.3 5.18.0 From 67ac8fd4d06dc881b60170fcf8f5223724371c1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 05:39:28 +0000 Subject: [PATCH 188/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.14.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c7c18fb98d..02b644eecf 100644 --- a/pom.xml +++ b/pom.xml @@ -1076,7 +1076,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.13.0 + 3.14.1 From 322795ced7c710f806044344a0489e4f3ba341e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 05:51:23 +0000 Subject: [PATCH 189/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.14.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 02b644eecf..d295a07af9 100644 --- a/pom.xml +++ b/pom.xml @@ -1071,7 +1071,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.13.0 + 3.14.1 org.openrewrite.recipe From 417b5f50fc4afc3fc6e63aa12e64766435253890 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 06:03:57 +0000 Subject: [PATCH 190/615] build(deps): Bump org.openrewrite.maven:rewrite-maven-plugin --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.15.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d295a07af9..aa06fe207f 100644 --- a/pom.xml +++ b/pom.xml @@ -1065,7 +1065,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.13.0 + 6.15.0 From 5ef99efc64ed370e38f5c29ce39517a498bf9208 Mon Sep 17 00:00:00 2001 From: Marvin Date: Thu, 24 Jul 2025 08:35:09 -0300 Subject: [PATCH 191/615] Migrate from OSSRH to Central Publisher Portal (#2962) * Migrate from OSSRH to Central Publisher Portal - Replace nexus-staging-maven-plugin with central-publishing-maven-plugin - Update distributionManagement URLs to Central Publisher Portal endpoints - Configure auto-publishing with waitUntil=published for immediate release - Update GitHub Actions to use CENTRAL_TOKEN_* environment variables - Update Maven settings.xml server configuration for Central Portal This addresses the OSSRH sunset deadline of June 30th, 2025. Signed-off-by: Marvin Froeder * Build with one thread per core Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder --- .circleci/config.yml | 6 +- .circleci/settings.xml | 6 +- .github/files/settings.xml | 39 -------- .github/files/toolchains.xml | 53 ---------- .github/workflows/auto-merge-dependabot.yml | 28 ------ .github/workflows/codeql-analysis.yml | 105 -------------------- pom.xml | 23 +++-- 7 files changed, 18 insertions(+), 242 deletions(-) delete mode 100644 .github/files/settings.xml delete mode 100644 .github/files/toolchains.xml delete mode 100644 .github/workflows/auto-merge-dependabot.yml delete mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 8ee1d4300c..22ac02c0f7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -147,7 +147,7 @@ jobs: name: 'Test' command: | source "$HOME/.sdkman/bin/sdkman-init.sh" - ./mvnw -ntp -B verify + ./mvnw -ntp -B verify -T1C - verify-formatting deploy: @@ -191,7 +191,7 @@ workflows: name: 'deploy snapshot' requires: - 'snapshot' - context: Sonatype + context: central filters: <<: *master-only @@ -205,6 +205,6 @@ workflows: name: 'release to maven central' requires: - 'setup-environment-release' - context: Sonatype + context: central filters: <<: *tags-only \ No newline at end of file diff --git a/.circleci/settings.xml b/.circleci/settings.xml index b7f976093f..d3892ed423 100644 --- a/.circleci/settings.xml +++ b/.circleci/settings.xml @@ -19,9 +19,9 @@ http://maven.apache.org/xsd/settings-1.0.0.xsd"> - ossrh - ${env.SONATYPE_USER} - ${env.SONATYPE_PASSWORD} + central + ${env.CENTRAL_TOKEN_USERNAME} + ${env.CENTRAL_TOKEN_PASSWORD} diff --git a/.github/files/settings.xml b/.github/files/settings.xml deleted file mode 100644 index b3b4740ad1..0000000000 --- a/.github/files/settings.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - ossrh - ${env.SONATYPE_USER} - ${env.SONATYPE_PASSWORD} - - - - - ossrh - - true - - - ${env.GPG_PASSPHRASE} - - - - - diff --git a/.github/files/toolchains.xml b/.github/files/toolchains.xml deleted file mode 100644 index 7fb26e061e..0000000000 --- a/.github/files/toolchains.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - jdk - - 1.8 - - - /home/runner/.sdkman/candidates/java/8.0.382-tem - - - - jdk - - 11 - - - /home/runner/.sdkman/candidates/java/11.0.22-tem - - - - jdk - - 17 - - - /home/runner/.sdkman/candidates/java/17.0.10-tem - - - - jdk - - 21 - - - /home/runner/.sdkman/candidates/java/21.0.2-tem - - - \ No newline at end of file diff --git a/.github/workflows/auto-merge-dependabot.yml b/.github/workflows/auto-merge-dependabot.yml deleted file mode 100644 index c434f8c53d..0000000000 --- a/.github/workflows/auto-merge-dependabot.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Dependabot auto-merge -on: pull_request - -permissions: - contents: write - pull-requests: write - -jobs: - dependabot: - runs-on: ubuntu-latest - if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'OpenFeign/feign' - steps: - - name: Dependabot metadata - id: metadata - uses: dependabot/fetch-metadata@v2.2.0 - with: - github-token: "${{ secrets.GITHUB_TOKEN }}" - - - name: Auto-approve Dependabot PRs - uses: hmarr/auto-approve-action@v3 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Enable auto-merge for Dependabot PRs - run: gh pr merge --auto --merge "$PR_URL" - env: - PR_URL: ${{github.event.pull_request.html_url}} - GH_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 710211c27b..0000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,105 +0,0 @@ -# ---------------------------------------------------------------------------- -# Copyright 2012-2014 The Feign Authors -# -# The Netty Project licenses this file to you under the Apache License, -# version 2.0 (the "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at: -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -name: "CodeQL" - -on: - push: - branches: ["master"] - pull_request: - # The branches below must be a subset of the branches above - branches: ["master"] - schedule: - - cron: '0 13 * * 3' - -permissions: - contents: read - -jobs: - analyze: - permissions: - actions: read # for github/codeql-action/init to get workflow details - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/analyze to upload SARIF results - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - # Override automatic language detection by changing the below list - # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['java'] - # Learn more... - # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Cache .m2/repository - - name: Cache local Maven repository - uses: actions/cache@v3 - continue-on-error: true - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ matrix.language }} ${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven-${{ matrix.language }} - ${{ runner.os }}-maven- - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - # - name: Autobuild - # uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - name: Setup Java JDK - uses: actions/setup-java@v4.0.0 - with: - distribution: 'temurin' - java-version: '21' - - - name: Setup Develocity - uses: gradle/develocity-actions/setup-maven@v1.2 - with: - add-pr-comment: false - develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - - - name: Compile project - run: ./mvnw -B -ntp clean package -Pquickbuild -Dtoolchain.skip=true - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/pom.xml b/pom.xml index aa06fe207f..844e501256 100644 --- a/pom.xml +++ b/pom.xml @@ -143,12 +143,12 @@ - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + central + https://central.sonatype.com/api/v1/publisher - ossrh - https://oss.sonatype.org/content/repositories/snapshots + central + https://central.sonatype.com/api/v1/publisher @@ -194,6 +194,7 @@ 3.1.1 6.0.0 0.1.1 + 0.8.0 3.5.2 0.200.4 file://${project.basedir}/src/config/bom.xml @@ -876,15 +877,15 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - 1.7.0 + org.sonatype.central + central-publishing-maven-plugin + ${central-publishing-maven-plugin.version} true - ossrh - https://oss.sonatype.org/ - true - 15 + central + true + published + all From c6cefdd404d328c346bc54b7f8709023621e0835 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:16:59 -0300 Subject: [PATCH 192/615] build(deps-dev): Bump org.apache.commons:commons-text (#2971) Bumps [org.apache.commons:commons-text](https://github.com/apache/commons-text) from 1.13.1 to 1.14.0. - [Changelog](https://github.com/apache/commons-text/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-text/compare/rel/commons-text-1.13.1...rel/commons-text-1.14.0) --- updated-dependencies: - dependency-name: org.apache.commons:commons-text dependency-version: 1.14.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 2f7dd9d807..9c68486891 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -38,7 +38,7 @@ org.apache.commons commons-text - 1.13.1 + 1.14.0 org.projectlombok diff --git a/form/pom.xml b/form/pom.xml index 496a4bdcad..beb5b4894b 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -50,7 +50,7 @@ org.apache.commons commons-text - 1.13.1 + 1.14.0 test From 080badc5c5bc761b70afeba899c1454b573a4bb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 15:38:18 -0300 Subject: [PATCH 193/615] build(deps): Bump com.alibaba.fastjson2:fastjson2 from 2.0.57 to 2.0.58 (#2974) Bumps [com.alibaba.fastjson2:fastjson2](https://github.com/alibaba/fastjson2) from 2.0.57 to 2.0.58. - [Release notes](https://github.com/alibaba/fastjson2/releases) - [Commits](https://github.com/alibaba/fastjson2/compare/2.0.57...2.0.58) --- updated-dependencies: - dependency-name: com.alibaba.fastjson2:fastjson2 dependency-version: 2.0.58 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 844e501256..31d305891a 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ 2.19.2 3.27.3 5.18.0 - 2.0.57 + 2.0.58 1.5.3 5.3 From afb1f763fe8df9a6cf4c8ae5c63b24e362b840e6 Mon Sep 17 00:00:00 2001 From: Dennis Roppelt Date: Thu, 14 Aug 2025 20:37:13 +0200 Subject: [PATCH 194/615] bump commons-fileupload to fix CVE-2025-48976 (#2956) bump from commons-fileupload 1.5 to 1.6.0 caused moditect to fail, other modules ignore it too, doing it here as well ignores: [ERROR] Failed to execute goal org.moditect:moditect-maven-plugin:1.3.0.Final:add-module-info (add-module-infos) on project feign-form-spring: Execution add-module-infos of goal org.moditect:moditect-maven-plugin:1.3.0.Final:add-module-info failed: Module portlet.api not found, required by org.apache.commons.fileupload --- form-spring/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 9c68486891..9b54b60abb 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -32,6 +32,7 @@ 17 + true @@ -64,7 +65,7 @@ commons-fileupload commons-fileupload - 1.5 + 1.6.0 compile From 2931fcfb4d72b662c9231aa7e6e21cce159c3ba7 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Wed, 8 Oct 2025 06:58:18 -0300 Subject: [PATCH 195/615] Trigger CI Signed-off-by: Marvin Froeder From 17f64aea3aec90c4ac5606dc924eb6a0d9f7c06f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:16:08 -0300 Subject: [PATCH 196/615] build(deps): Bump io.sundr:sundr-maven-plugin from 0.200.4 to 0.230.0 (#3067) * build(deps): Bump io.sundr:sundr-maven-plugin from 0.200.4 to 0.230.0 Bumps [io.sundr:sundr-maven-plugin](https://github.com/sundrio/sundrio) from 0.200.4 to 0.230.0. - [Commits](https://github.com/sundrio/sundrio/commits/0.230.0) --- updated-dependencies: - dependency-name: io.sundr:sundr-maven-plugin dependency-version: 0.230.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * fix: Add User-Agent header to Wikipedia API requests Signed-off-by: Marvin Froeder * fix: Add User-Agent header to Wikipedia Spring Boot example Signed-off-by: Marvin Froeder --------- Signed-off-by: dependabot[bot] Signed-off-by: Marvin Froeder Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin Froeder --- .../example/wikipedia/WikipediaClientConfiguration.java | 8 ++++++++ .../src/main/java/example/wikipedia/WikipediaExample.java | 5 +++++ pom.xml | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/example-wikipedia-with-springboot/src/main/java/example/wikipedia/WikipediaClientConfiguration.java b/example-wikipedia-with-springboot/src/main/java/example/wikipedia/WikipediaClientConfiguration.java index 15ae58a687..7afdb3bc23 100644 --- a/example-wikipedia-with-springboot/src/main/java/example/wikipedia/WikipediaClientConfiguration.java +++ b/example-wikipedia-with-springboot/src/main/java/example/wikipedia/WikipediaClientConfiguration.java @@ -21,6 +21,7 @@ import com.google.gson.stream.JsonReader; import example.wikipedia.WikipediaClient.Page; import example.wikipedia.WikipediaClient.Response; +import feign.RequestInterceptor; import feign.codec.Decoder; import feign.gson.GsonDecoder; import java.io.IOException; @@ -62,4 +63,11 @@ public Decoder decoder() { return new GsonDecoder(gson); } + + @Bean + public RequestInterceptor userAgentInterceptor() { + return template -> + template.header( + "User-Agent", "Feign Wikipedia Example (https://github.com/openfeign/feign)"); + } } diff --git a/example-wikipedia/src/main/java/example/wikipedia/WikipediaExample.java b/example-wikipedia/src/main/java/example/wikipedia/WikipediaExample.java index f141756567..f2cb6ac1bc 100644 --- a/example-wikipedia/src/main/java/example/wikipedia/WikipediaExample.java +++ b/example-wikipedia/src/main/java/example/wikipedia/WikipediaExample.java @@ -65,6 +65,11 @@ public static void main(String... args) throws InterruptedException { .logger(new Logger.ErrorLogger()) .logLevel(Logger.Level.BASIC) .options(new Request.Options(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true)) + .requestInterceptor( + template -> + template.header( + "User-Agent", + "Feign Wikipedia Example (https://github.com/openfeign/feign)")) .target(Wikipedia.class, "https://en.wikipedia.org"); System.out.println("Let's search for PTAL!"); diff --git a/pom.xml b/pom.xml index 31d305891a..9ba115e0f0 100644 --- a/pom.xml +++ b/pom.xml @@ -196,7 +196,7 @@ 0.1.1 0.8.0 3.5.2 - 0.200.4 + 0.230.0 file://${project.basedir}/src/config/bom.xml 2.1.0 2.18.0 From f59a3a6c97ad5cdfbf10da8629d0d83f2ab8baa3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 10:20:33 +0000 Subject: [PATCH 197/615] Bump org.springframework.cloud:spring-cloud-starter-openfeign Bumps [org.springframework.cloud:spring-cloud-starter-openfeign](https://github.com/spring-cloud/spring-cloud-openfeign) from 4.1.4 to 4.3.0. - [Release notes](https://github.com/spring-cloud/spring-cloud-openfeign/releases) - [Commits](https://github.com/spring-cloud/spring-cloud-openfeign/compare/v4.1.4...v4.3.0) --- updated-dependencies: - dependency-name: org.springframework.cloud:spring-cloud-starter-openfeign dependency-version: 4.3.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- form-spring/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 9b54b60abb..d890046b38 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -78,7 +78,7 @@ org.springframework.cloud spring-cloud-starter-openfeign - 4.1.4 + 4.3.0 test From de353af738b9ee7bac171b3ba7bd2ba920787ca3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:33:59 -0300 Subject: [PATCH 198/615] build(deps): Bump org.springframework:spring-web in /form-spring (#3070) Bumps [org.springframework:spring-web](https://github.com/spring-projects/spring-framework) from 6.1.14 to 6.1.21. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.14...v6.1.21) --- updated-dependencies: - dependency-name: org.springframework:spring-web dependency-version: 6.1.21 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- form-spring/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 9b54b60abb..30cd273ed4 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -58,7 +58,7 @@ org.springframework spring-web - 6.1.14 + 6.1.21 compile From 9a16d013843a07f540b3774d27e7341e8777fb0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:37:46 -0300 Subject: [PATCH 199/615] build(deps): Bump io.netty:netty-codec-http in /benchmark (#3015) Bumps [io.netty:netty-codec-http](https://github.com/netty/netty) from 4.2.3.Final to 4.2.5.Final. - [Commits](https://github.com/netty/netty/compare/netty-4.2.3.Final...netty-4.2.5.Final) --- updated-dependencies: - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.5.Final dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 928754f30f..ed4ab17258 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.3.Final + 4.2.5.Final true From 87ebc9e0b5fba227bfa6efdbf65fa5be9fc07c57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:37:59 -0300 Subject: [PATCH 200/615] build(deps-dev): Bump io.undertow:undertow-core (#3021) Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.18.Final to 2.3.19.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/commits) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-version: 2.3.19.Final dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- form/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form/pom.xml b/form/pom.xml index beb5b4894b..be0119334f 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -69,7 +69,7 @@ io.undertow undertow-core - 2.3.18.Final + 2.3.19.Final test From 6f381d230ea7dad72a2ff70a18197325c58966be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:38:25 -0300 Subject: [PATCH 201/615] build(deps): Bump git-code-format-maven-plugin.version from 5.3 to 5.4 (#3063) * build(deps): Bump git-code-format-maven-plugin.version from 5.3 to 5.4 Bumps `git-code-format-maven-plugin.version` from 5.3 to 5.4. Updates `com.cosium.code:google-java-format` from 5.3 to 5.4 - [Commits](https://github.com/Cosium/git-code-format-maven-plugin/compare/5.3...5.4) Updates `com.cosium.code:git-code-format-maven-plugin` from 5.3 to 5.4 - [Commits](https://github.com/Cosium/git-code-format-maven-plugin/compare/5.3...5.4) --- updated-dependencies: - dependency-name: com.cosium.code:google-java-format dependency-version: '5.4' dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.cosium.code:git-code-format-maven-plugin dependency-version: '5.4' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Fix text blocks format Signed-off-by: Marvin Froeder --------- Signed-off-by: dependabot[bot] Signed-off-by: Marvin Froeder Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin Froeder --- gson/src/test/java/feign/gson/GsonCodecTest.java | 3 ++- .../src/test/java/feign/jaxb/JAXBCodecTest.java | 4 ++-- jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java | 4 ++-- moshi/src/test/java/feign/moshi/MoshiEncoderTest.java | 3 ++- pom.xml | 2 +- sax/src/test/java/feign/sax/SAXDecoderTest.java | 2 +- .../src/test/java/feign/soap/SOAPCodecTest.java | 10 +++++----- soap/src/test/java/feign/soap/SOAPCodecTest.java | 10 +++++----- 8 files changed, 20 insertions(+), 18 deletions(-) diff --git a/gson/src/test/java/feign/gson/GsonCodecTest.java b/gson/src/test/java/feign/gson/GsonCodecTest.java index 4c226fa767..1ec47b8918 100644 --- a/gson/src/test/java/feign/gson/GsonCodecTest.java +++ b/gson/src/test/java/feign/gson/GsonCodecTest.java @@ -49,7 +49,8 @@ void encodesMapObjectNumericalValuesAsInteger() { new GsonEncoder().encode(map, map.getClass(), template); assertThat(template) - .hasBody(""" + .hasBody( + """ { "foo": 1 }\ diff --git a/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java b/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java index fa3dfabb9b..77acd51a0d 100644 --- a/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java +++ b/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java @@ -148,7 +148,7 @@ void encodesXmlWithCustomJAXBNoNamespaceSchemaLocation() throws Exception { assertThat(template) .hasBody( - """ +""" \ @@ -420,7 +420,7 @@ public int hashCode() { private static Schema getMockIntObjSchema() throws Exception { String schema = - """ +""" \ \ diff --git a/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java b/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java index 2eccb41011..fa375e3114 100644 --- a/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java +++ b/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java @@ -148,7 +148,7 @@ void encodesXmlWithCustomJAXBNoNamespaceSchemaLocation() throws Exception { assertThat(template) .hasBody( - """ +""" \ @@ -421,7 +421,7 @@ public int hashCode() { private static Schema getMockIntObjSchema() throws Exception { String schema = - """ +""" \ \ diff --git a/moshi/src/test/java/feign/moshi/MoshiEncoderTest.java b/moshi/src/test/java/feign/moshi/MoshiEncoderTest.java index ba7654c98a..2a76d75973 100644 --- a/moshi/src/test/java/feign/moshi/MoshiEncoderTest.java +++ b/moshi/src/test/java/feign/moshi/MoshiEncoderTest.java @@ -39,7 +39,8 @@ void encodesMapObjectNumericalValuesAsInteger() { new MoshiEncoder().encode(map, Map.class, template); assertThat(template) - .hasBody(""" + .hasBody( + """ { "foo": 1 }\ diff --git a/pom.xml b/pom.xml index 9ba115e0f0..8a4b2d866d 100644 --- a/pom.xml +++ b/pom.xml @@ -184,7 +184,7 @@ 2.0.58 1.5.3 - 5.3 + 5.4 3.14.0 3.1.4 3.3.1 diff --git a/sax/src/test/java/feign/sax/SAXDecoderTest.java b/sax/src/test/java/feign/sax/SAXDecoderTest.java index 45900b2c28..16ece9f2c3 100644 --- a/sax/src/test/java/feign/sax/SAXDecoderTest.java +++ b/sax/src/test/java/feign/sax/SAXDecoderTest.java @@ -35,7 +35,7 @@ class SAXDecoderTest { static String statusFailed = - """ +""" diff --git a/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java b/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java index 5a43d1c7e7..0cbb94be42 100644 --- a/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java +++ b/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java @@ -149,7 +149,7 @@ void encodesSoapWithCustomJAXBSchemaLocation() { assertThat(template) .hasBody( - """ +""" \ \ \ @@ -180,7 +180,7 @@ void encodesSoapWithCustomJAXBNoSchemaLocation() { assertThat(template) .hasBody( - """ +""" \ \ \ @@ -238,7 +238,7 @@ void decodesSoap() throws Exception { mock.item.value = "Apples"; String mockSoapEnvelop = - """ +""" \ \ \ @@ -272,7 +272,7 @@ void decodesSoapWithSchemaOnEnvelope() throws Exception { mock.item.value = "Apples"; String mockSoapEnvelop = - """ +""" \ \ \ \ diff --git a/soap/src/test/java/feign/soap/SOAPCodecTest.java b/soap/src/test/java/feign/soap/SOAPCodecTest.java index b814c63a8c..002a0e33b6 100644 --- a/soap/src/test/java/feign/soap/SOAPCodecTest.java +++ b/soap/src/test/java/feign/soap/SOAPCodecTest.java @@ -149,7 +149,7 @@ void encodesSoapWithCustomJAXBSchemaLocation() { assertThat(template) .hasBody( - """ +""" \ \ \ @@ -180,7 +180,7 @@ void encodesSoapWithCustomJAXBNoSchemaLocation() { assertThat(template) .hasBody( - """ +""" \ \ \ @@ -238,7 +238,7 @@ void decodesSoap() throws Exception { mock.item.value = "Apples"; String mockSoapEnvelop = - """ +""" \ \ \ @@ -272,7 +272,7 @@ void decodesSoapWithSchemaOnEnvelope() throws Exception { mock.item.value = "Apples"; String mockSoapEnvelop = - """ +""" \ \ \ \ From e6e2b0bc763095fd63e2936cee36f4f17fc74ff3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:42:11 -0300 Subject: [PATCH 202/615] build(deps): Bump reactor.version from 3.7.8 to 3.7.11 (#3025) Bumps `reactor.version` from 3.7.8 to 3.7.11. Updates `io.projectreactor:reactor-core` from 3.7.8 to 3.7.11 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.8...v3.7.11) Updates `io.projectreactor:reactor-test` from 3.7.8 to 3.7.11 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.8...v3.7.11) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.7.11 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.7.11 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index 4c7e80488f..41644e1f37 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.7.8 + 3.7.11 1.0.4 2.2.21 From 4822becbaeffe6435b537f3e88fddc0917695e2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:42:42 -0300 Subject: [PATCH 203/615] build(deps): Bump jakarta.xml.bind:jakarta.xml.bind-api (#3037) Bumps [jakarta.xml.bind:jakarta.xml.bind-api](https://github.com/jakartaee/jaxb-api) from 4.0.2 to 4.0.4. - [Release notes](https://github.com/jakartaee/jaxb-api/releases) - [Commits](https://github.com/jakartaee/jaxb-api/compare/4.0.2...4.0.4) --- updated-dependencies: - dependency-name: jakarta.xml.bind:jakarta.xml.bind-api dependency-version: 4.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- jaxb-jakarta/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 44b40a63bf..3ed1ccba93 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -50,7 +50,7 @@ jakarta.xml.bind jakarta.xml.bind-api - 4.0.2 + 4.0.4 diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 6c2328fffa..6c6e344e21 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -68,7 +68,7 @@ jakarta.xml.bind jakarta.xml.bind-api - 4.0.2 + 4.0.4 com.sun.xml.messaging.saaj From 829a7c5585d368ed7467daffb0377adf75109a48 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:42:49 -0300 Subject: [PATCH 204/615] build(deps): Bump org.apache.maven.plugins:maven-javadoc-plugin (#3051) Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.11.2 to 3.12.0. - [Release notes](https://github.com/apache/maven-javadoc-plugin/releases) - [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.11.2...maven-javadoc-plugin-3.12.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-javadoc-plugin dependency-version: 3.12.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a4b2d866d..3a5e19095e 100644 --- a/pom.xml +++ b/pom.xml @@ -188,7 +188,7 @@ 3.14.0 3.1.4 3.3.1 - 3.11.2 + 3.12.0 5.0.0 3.4.2 3.1.1 From 48b2c13373c8e856467e2a4b55fe1df9e11e4c40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:43:03 -0300 Subject: [PATCH 205/615] build(deps): Bump kotlin.version from 2.2.0 to 2.2.20 (#3028) Bumps `kotlin.version` from 2.2.0 to 2.2.20. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.2.0 to 2.2.20 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.0...v2.2.20) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.2.0 to 2.2.20 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.0...v2.2.20) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.2.0 to 2.2.20 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-version: 2.2.20 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-version: 2.2.20 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-version: 2.2.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 19ed595cbf..646a49903d 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.2.0 + 2.2.20 1.10.2 From 58a38bf5b0ea6befab3b07412da01fdaf44428cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:43:08 -0300 Subject: [PATCH 206/615] build(deps): Bump micrometer.version from 1.15.2 to 1.15.4 (#3023) Bumps `micrometer.version` from 1.15.2 to 1.15.4. Updates `io.micrometer:micrometer-core` from 1.15.2 to 1.15.4 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.15.2...v1.15.4) Updates `io.micrometer:micrometer-test` from 1.15.2 to 1.15.4 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.15.2...v1.15.4) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.15.4 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-version: 1.15.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index c6fd73623f..b6a8f54089 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.15.2 + 1.15.4 From e4e38ec30214f741329cc53fe9c798621d0de74f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:43:20 -0300 Subject: [PATCH 207/615] build(deps-dev): Bump org.springframework:spring-context (#3032) Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 6.2.9 to 6.2.11. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.9...v6.2.11) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 6.2.11 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 415b421f92..5bc47b69f2 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - 6.2.9 + 6.2.11 test From b194ef4587c6740c1b701f5c392f6ccf89ccdd25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:43:26 -0300 Subject: [PATCH 208/615] build(deps): Bump org.apache.maven.plugins:maven-scm-plugin (#3060) Bumps [org.apache.maven.plugins:maven-scm-plugin](https://github.com/apache/maven-scm) from 2.1.0 to 2.2.1. - [Release notes](https://github.com/apache/maven-scm/releases) - [Commits](https://github.com/apache/maven-scm/compare/maven-scm-2.1.0...v2.2.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-scm-plugin dependency-version: 2.2.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3a5e19095e..77e1c7ddc3 100644 --- a/pom.xml +++ b/pom.xml @@ -198,7 +198,7 @@ 3.5.2 0.230.0 file://${project.basedir}/src/config/bom.xml - 2.1.0 + 2.2.1 2.18.0 3.2.8 3.1.4 From 7967cf0c4805cc7eca93726825c93265da68f6c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:43:34 -0300 Subject: [PATCH 209/615] build(deps): Bump org.apache.httpcomponents.client5:httpclient5 (#3062) Bumps [org.apache.httpcomponents.client5:httpclient5](https://github.com/apache/httpcomponents-client) from 5.5 to 5.5.1. - [Changelog](https://github.com/apache/httpcomponents-client/blob/rel/v5.5.1/RELEASE_NOTES.txt) - [Commits](https://github.com/apache/httpcomponents-client/compare/rel/v5.5...rel/v5.5.1) --- updated-dependencies: - dependency-name: org.apache.httpcomponents.client5:httpclient5 dependency-version: 5.5.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hc5/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hc5/pom.xml b/hc5/pom.xml index cca2e72999..0ade0edee6 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -38,7 +38,7 @@ org.apache.httpcomponents.client5 httpclient5 - 5.5 + 5.5.1 From 2bab5baaad7d1036ab7fe70a44fd305e07f6bf9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:43:43 -0300 Subject: [PATCH 210/615] build(deps): Bump org.assertj:assertj-core from 3.27.3 to 3.27.6 (#3053) Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.27.3 to 3.27.6. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.3...assertj-build-3.27.6) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-version: 3.27.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 77e1c7ddc3..da2270684f 100644 --- a/pom.xml +++ b/pom.xml @@ -179,7 +179,7 @@ 5.13.4 2.19.2 - 3.27.3 + 3.27.6 5.18.0 2.0.58 1.5.3 From 317c873705ab65a66e874f30f1838fcb458ec6c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:43:47 -0300 Subject: [PATCH 211/615] build(deps): Bump com.google.http-client:google-http-client (#3061) Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 1.47.1 to 2.0.1. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v1.47.1...v2.0.1) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-version: 2.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index da2270684f..4bf5b60fea 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 4.12.0 33.4.8-jre - 1.47.1 + 2.0.1 2.13.1 1.15.2 2.0.17 From 7ef66bbc524e3c6d4fd80a5474da5a2311d51975 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:43:55 -0300 Subject: [PATCH 212/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java (#3059) Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.14.1 to 3.18.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.14.1...v3.18.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4bf5b60fea..cd64746653 100644 --- a/pom.xml +++ b/pom.xml @@ -1077,7 +1077,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.14.1 + 3.18.0 From f0e7e70b7ed23019d181780139e8146e588aaef4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:44:02 -0300 Subject: [PATCH 213/615] build(deps): Bump org.junit:junit-bom from 5.13.4 to 6.0.0 (#3064) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 5.13.4 to 6.0.0. - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r5.13.4...r6.0.0) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cd64746653..175c385d23 100644 --- a/pom.xml +++ b/pom.xml @@ -177,7 +177,7 @@ 20250517 3.3.5 - 5.13.4 + 6.0.0 2.19.2 3.27.6 5.18.0 From 8804e93bed3a24055bb2ee1da1d2bcfade109566 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:44:09 -0300 Subject: [PATCH 214/615] build(deps): Bump maven-surefire-plugin.version from 3.5.2 to 3.5.4 (#3033) Bumps `maven-surefire-plugin.version` from 3.5.2 to 3.5.4. Updates `org.apache.maven.plugins:maven-surefire-plugin` from 3.5.2 to 3.5.4 - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.2...surefire-3.5.4) Updates `org.apache.maven.plugins:maven-failsafe-plugin` from 3.5.2 to 3.5.4 - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.2...surefire-3.5.4) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-version: 3.5.4 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-version: 3.5.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 175c385d23..5099e9dad6 100644 --- a/pom.xml +++ b/pom.xml @@ -195,7 +195,7 @@ 6.0.0 0.1.1 0.8.0 - 3.5.2 + 3.5.4 0.230.0 file://${project.basedir}/src/config/bom.xml 2.2.1 From 358478f58f3a8ce699d9fbe48120ee1cc9821831 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:44:15 -0300 Subject: [PATCH 215/615] build(deps): Bump com.gradle:common-custom-user-data-maven-extension (#3038) Bumps [com.gradle:common-custom-user-data-maven-extension](https://github.com/gradle/common-custom-user-data-maven-extension) from 2.0.3 to 2.0.6. - [Release notes](https://github.com/gradle/common-custom-user-data-maven-extension/releases) - [Commits](https://github.com/gradle/common-custom-user-data-maven-extension/compare/v2.0.3...v2.0.6) --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-maven-extension dependency-version: 2.0.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 085ff38f35..b5f3a9f6dd 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -24,7 +24,7 @@ com.gradle common-custom-user-data-maven-extension - 2.0.3 + 2.0.6 com.marvinformatics.jacoco From 737a4b19d266d9ee9f777474e4db19a2ecd6d8e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:44:21 -0300 Subject: [PATCH 216/615] build(deps): Bump io.dropwizard.metrics:metrics-core (#3036) Bumps [io.dropwizard.metrics:metrics-core](https://github.com/dropwizard/metrics) from 4.2.33 to 4.2.37. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.33...v4.2.37) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-version: 4.2.37 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dropwizard-metrics4/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 86442a5135..8c6716c89d 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -40,7 +40,7 @@ io.dropwizard.metrics metrics-core - 4.2.33 + 4.2.37 ${project.groupId} From ddcc3291e9f12369d15546ccdc3b21a24b0cccc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:44:29 -0300 Subject: [PATCH 217/615] build(deps): Bump com.gradle:develocity-maven-extension from 2.1 to 2.2 (#3041) Bumps com.gradle:develocity-maven-extension from 2.1 to 2.2. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: '2.2' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index b5f3a9f6dd..a9e021833d 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.1 + 2.2 com.gradle From e594ace2d91067fe5f1ef0fa8542df6edf780efd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:44:35 -0300 Subject: [PATCH 218/615] build(deps): Bump org.projectlombok:lombok from 1.18.38 to 1.18.42 (#3044) Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.38 to 1.18.42. - [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/projectlombok/lombok/compare/v1.18.38...v1.18.42) --- updated-dependencies: - dependency-name: org.projectlombok:lombok dependency-version: 1.18.42 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 30cd273ed4..74a6759a72 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -44,7 +44,7 @@ org.projectlombok lombok - 1.18.38 + 1.18.42 provided diff --git a/form/pom.xml b/form/pom.xml index be0119334f..222909042e 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -33,7 +33,7 @@ org.projectlombok lombok - 1.18.38 + 1.18.42 provided From 3f685afbd0df63acc40ab5ab1d9cf7c15599df37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:44:42 -0300 Subject: [PATCH 219/615] build(deps): Bump org.openrewrite.maven:rewrite-maven-plugin (#3057) Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.15.0 to 6.19.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.15.0...v6.19.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.19.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5099e9dad6..62457493e3 100644 --- a/pom.xml +++ b/pom.xml @@ -1066,7 +1066,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.15.0 + 6.19.0 From b6eb51e3e416c96c4d5ac3dbbe8a3468c4198324 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:44:49 -0300 Subject: [PATCH 220/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks (#3065) Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.14.1 to 3.18.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.14.1...v3.18.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 62457493e3..ea5ffe148e 100644 --- a/pom.xml +++ b/pom.xml @@ -1072,7 +1072,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.14.1 + 3.18.0 org.openrewrite.recipe From 4e1dd1c5788846683b9a39dd000bb9799bd13a71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:44:56 -0300 Subject: [PATCH 221/615] build(deps): Bump org.apache.maven.plugins:maven-shade-plugin (#3034) Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.6.0 to 3.6.1. - [Release notes](https://github.com/apache/maven-shade-plugin/releases) - [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.6.0...v3.6.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-shade-plugin dependency-version: 3.6.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index c3f2cf884d..022897636e 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -103,7 +103,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 + 3.6.1 diff --git a/benchmark/pom.xml b/benchmark/pom.xml index ed4ab17258..1204da1779 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -137,7 +137,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 + 3.6.1 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 6d8762e891..6089ec6083 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -56,7 +56,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 + 3.6.1 diff --git a/example-github/pom.xml b/example-github/pom.xml index bda16b4808..aae72fce9c 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -52,7 +52,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 + 3.6.1 diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 6e12e2fa90..102d8b2851 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -53,7 +53,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 + 3.6.1 From 698b1a664949889a0fe269b60c2099cdad4443d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:48:50 -0300 Subject: [PATCH 222/615] build(deps): Bump com.alibaba.fastjson2:fastjson2 from 2.0.58 to 2.0.59 (#3048) Bumps [com.alibaba.fastjson2:fastjson2](https://github.com/alibaba/fastjson2) from 2.0.58 to 2.0.59. - [Release notes](https://github.com/alibaba/fastjson2/releases) - [Commits](https://github.com/alibaba/fastjson2/compare/2.0.58...2.0.59) --- updated-dependencies: - dependency-name: com.alibaba.fastjson2:fastjson2 dependency-version: 2.0.59 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ea5ffe148e..3c6a7a5357 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ 2.19.2 3.27.6 5.18.0 - 2.0.58 + 2.0.59 1.5.3 5.4 From 81176e3883d01cfc691d432b5b54aecebf13742a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:49:17 -0300 Subject: [PATCH 223/615] build(deps): Bump org.apache.maven.plugins:maven-enforcer-plugin (#3066) Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.6.1 to 3.6.2. - [Release notes](https://github.com/apache/maven-enforcer/releases) - [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.6.1...enforcer-3.6.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-enforcer-plugin dependency-version: 3.6.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3c6a7a5357..cc4da3a2b4 100644 --- a/pom.xml +++ b/pom.xml @@ -891,7 +891,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.6.1 + 3.6.2 enforce-no-repositories From b0c038171b802a5164c758283762af6de4d95250 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:49:34 -0300 Subject: [PATCH 224/615] build(deps): Bump netty.version from 4.2.3.Final to 4.2.6.Final (#3022) Bumps `netty.version` from 4.2.3.Final to 4.2.6.Final. Updates `io.netty:netty-bom` from 4.2.3.Final to 4.2.6.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.3.Final...netty-4.2.6.Final) Updates `io.netty:netty-handler` from 4.2.3.Final to 4.2.6.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.3.Final...netty-4.2.6.Final) Updates `io.netty:netty-codec-http` from 4.2.3.Final to 4.2.6.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.3.Final...netty-4.2.6.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.6.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.6.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.6.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 1204da1779..2da672ad32 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.5.Final + 4.2.6.Final true From d96453929c9799cb10a4ccdf853fe9e3ef8ec0f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:52:54 -0300 Subject: [PATCH 225/615] build(deps): Bump org.apache.maven.plugins:maven-compiler-plugin (#3050) Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.14.0 to 3.14.1. - [Release notes](https://github.com/apache/maven-compiler-plugin/releases) - [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.14.0...maven-compiler-plugin-3.14.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-compiler-plugin dependency-version: 3.14.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cc4da3a2b4..3d669d1962 100644 --- a/pom.xml +++ b/pom.xml @@ -185,7 +185,7 @@ 1.5.3 5.4 - 3.14.0 + 3.14.1 3.1.4 3.3.1 3.12.0 From 4b4e3cfab0287a620696ce9ae3f4390034d6ed6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:55:39 -0300 Subject: [PATCH 226/615] build(deps): Bump org.sonatype.central:central-publishing-maven-plugin (#3054) Bumps [org.sonatype.central:central-publishing-maven-plugin](https://github.com/sonatype/central-publishing-maven-plugin) from 0.8.0 to 0.9.0. - [Commits](https://github.com/sonatype/central-publishing-maven-plugin/commits) --- updated-dependencies: - dependency-name: org.sonatype.central:central-publishing-maven-plugin dependency-version: 0.9.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3d669d1962..a5f5643597 100644 --- a/pom.xml +++ b/pom.xml @@ -194,7 +194,7 @@ 3.1.1 6.0.0 0.1.1 - 0.8.0 + 0.9.0 3.5.4 0.230.0 file://${project.basedir}/src/config/bom.xml From 23db76a2ca38b847dbd7d64766372bd5d17916d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:56:01 -0300 Subject: [PATCH 227/615] build(deps): Bump com.google.code.gson:gson from 2.13.1 to 2.13.2 (#3029) Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.13.1 to 2.13.2. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.13.1...gson-parent-2.13.2) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-version: 2.13.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a5f5643597..9d31ef9ce8 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 4.12.0 33.4.8-jre 2.0.1 - 2.13.1 + 2.13.2 1.15.2 2.0.17 20250517 From dacb45c5fc51f055ebf12bc9db01afc1cbbcb487 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:56:14 -0300 Subject: [PATCH 228/615] build(deps): Bump com.google.guava:guava from 33.4.8-jre to 33.5.0-jre (#3043) Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.4.8-jre to 33.5.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-version: 33.5.0-jre dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9d31ef9ce8..92ab0cdd42 100644 --- a/pom.xml +++ b/pom.xml @@ -169,7 +169,7 @@ ${main.java.version} 4.12.0 - 33.4.8-jre + 33.5.0-jre 2.0.1 2.13.2 1.15.2 From 6394c93ee6e16702bdc2e665e9f0b0c9dd9efc1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 07:56:19 -0300 Subject: [PATCH 229/615] build(deps): Bump org.codehaus.mojo:versions-maven-plugin (#3052) Bumps [org.codehaus.mojo:versions-maven-plugin](https://github.com/mojohaus/versions) from 2.18.0 to 2.19.1. - [Release notes](https://github.com/mojohaus/versions/releases) - [Changelog](https://github.com/mojohaus/versions/blob/master/ReleaseNotes.md) - [Commits](https://github.com/mojohaus/versions/compare/2.18.0...2.19.1) --- updated-dependencies: - dependency-name: org.codehaus.mojo:versions-maven-plugin dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 92ab0cdd42..2143b22698 100644 --- a/pom.xml +++ b/pom.xml @@ -199,7 +199,7 @@ 0.230.0 file://${project.basedir}/src/config/bom.xml 2.2.1 - 2.18.0 + 2.19.1 3.2.8 3.1.4 1.2.2 From 0194233a1cbca0b56ecb78fcfd0cab4522a5b6fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:00:19 -0300 Subject: [PATCH 230/615] build(deps): Bump mockito.version from 5.18.0 to 5.20.0 (#3049) Bumps `mockito.version` from 5.18.0 to 5.20.0. Updates `org.mockito:mockito-core` from 5.18.0 to 5.20.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.18.0...v5.20.0) Updates `org.mockito:mockito-junit-jupiter` from 5.18.0 to 5.20.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.18.0...v5.20.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.20.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-junit-jupiter dependency-version: 5.20.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- form-spring/pom.xml | 4 ++-- form/pom.xml | 4 ++-- pom.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 74a6759a72..098baf5173 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -125,13 +125,13 @@ org.mockito mockito-core - 5.18.0 + 5.20.0 test org.mockito mockito-junit-jupiter - 5.18.0 + 5.20.0 test diff --git a/form/pom.xml b/form/pom.xml index 222909042e..9eaa146cb4 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -99,13 +99,13 @@ org.mockito mockito-core - 5.18.0 + 5.20.0 test org.mockito mockito-junit-jupiter - 5.18.0 + 5.20.0 test diff --git a/pom.xml b/pom.xml index 2143b22698..530ac4b9fa 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ 6.0.0 2.19.2 3.27.6 - 5.18.0 + 5.20.0 2.0.59 1.5.3 From da62f4f805850dfb01f5779f5c73f7941bef0472 Mon Sep 17 00:00:00 2001 From: Marvin Date: Wed, 8 Oct 2025 08:05:11 -0300 Subject: [PATCH 231/615] Upgrade Spring versions to latest stable releases (#3071) Signed-off-by: Marvin Froeder --- form-spring/pom.xml | 4 ++-- pom.xml | 2 +- spring/pom.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 098baf5173..aaa7a42051 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -58,7 +58,7 @@ org.springframework spring-web - 6.1.21 + 6.2.11 compile @@ -78,7 +78,7 @@ org.springframework.cloud spring-cloud-starter-openfeign - 4.1.4 + 4.3.0 test diff --git a/pom.xml b/pom.xml index 530ac4b9fa..4e11a86db3 100644 --- a/pom.xml +++ b/pom.xml @@ -175,7 +175,7 @@ 1.15.2 2.0.17 20250517 - 3.3.5 + 3.5.6 6.0.0 2.19.2 diff --git a/spring/pom.xml b/spring/pom.xml index e27e4e4d97..dedbc8aa82 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -31,7 +31,7 @@ 17 - 6.1.21 + 6.2.11 From d9fb1d272281f7a7e822508cd8ba48124a97cb40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:17:09 -0300 Subject: [PATCH 232/615] build(deps): Bump springboot.version from 3.3.5 to 3.5.6 (#3045) Bumps `springboot.version` from 3.3.5 to 3.5.6. Updates `org.springframework.boot:spring-boot-starter-web` from 3.3.5 to 3.5.6 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.5...v3.5.6) Updates `org.springframework.boot:spring-boot-starter-test` from 3.3.5 to 3.5.6 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.5...v3.5.6) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-web dependency-version: 3.5.6 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.springframework.boot:spring-boot-starter-test dependency-version: 3.5.6 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin From 9c2792e1bf452dbaf1513ce6fd7cd675d66e9840 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:24:20 -0300 Subject: [PATCH 233/615] build(deps): Bump com.squareup.okhttp3:okhttp-bom from 4.12.0 to 5.2.0 (#3069) * build(deps): Bump com.squareup.okhttp3:okhttp-bom from 4.12.0 to 5.2.0 Bumps [com.squareup.okhttp3:okhttp-bom](https://github.com/square/okhttp) from 4.12.0 to 5.2.0. - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.12.0...parent-5.2.0) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp-bom dependency-version: 5.2.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Use okhttp-jvm artifact for OkHttp 5.x Maven compatibility Signed-off-by: Marvin Froeder --------- Signed-off-by: dependabot[bot] Signed-off-by: Marvin Froeder Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin Froeder --- okhttp/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/okhttp/pom.xml b/okhttp/pom.xml index db203eac55..a20bc44b17 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -42,7 +42,7 @@ com.squareup.okhttp3 - okhttp + okhttp-jvm diff --git a/pom.xml b/pom.xml index 4e11a86db3..20132861df 100644 --- a/pom.xml +++ b/pom.xml @@ -168,7 +168,7 @@ ${main.java.version} ${main.java.version} - 4.12.0 + 5.2.0 33.5.0-jre 2.0.1 2.13.2 From 17a446ed43945793cf56670656d5028e134bf928 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:28:05 -0300 Subject: [PATCH 234/615] build(deps-dev): Bump com.google.testing.compile:compile-testing from 0.21.0 to 0.23.0 (#3030) * build(deps-dev): Bump com.google.testing.compile:compile-testing Bumps [com.google.testing.compile:compile-testing](https://github.com/google/compile-testing) from 0.21.0 to 0.23.0. - [Release notes](https://github.com/google/compile-testing/releases) - [Commits](https://github.com/google/compile-testing/compare/v0.21.0...v0.23.0) --- updated-dependencies: - dependency-name: com.google.testing.compile:compile-testing dependency-version: 0.23.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Add JDK module exports for compile-testing 0.23.0 compatibility Signed-off-by: Marvin Froeder --------- Signed-off-by: dependabot[bot] Signed-off-by: Marvin Froeder Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin Froeder --- apt-test-generator/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index 022897636e..b3c7ed52bb 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -50,7 +50,7 @@ com.google.testing.compile compile-testing - 0.21.0 + 0.23.0 test @@ -188,7 +188,7 @@ org.apache.maven.plugins maven-surefire-plugin - --add-opens jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED + --add-opens jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED From abf90d20e63b07f93a223af3c3a1b86f1a8500ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:56:04 -0300 Subject: [PATCH 235/615] build(deps): Bump vertx.version from 5.0.1 to 5.0.4 (#3013) * build(deps): Bump vertx.version from 5.0.1 to 5.0.4 Bumps `vertx.version` from 5.0.1 to 5.0.4. Updates `io.vertx:vertx-core` from 5.0.1 to 5.0.4 - [Commits](https://github.com/eclipse/vert.x/compare/5.0.1...5.0.4) Updates `io.vertx:vertx-web-client` from 4.5.14 to 5.0.4 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.14...5.0.4) Updates `io.vertx:vertx-junit5` from 4.5.14 to 5.0.4 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.14...5.0.4) --- updated-dependencies: - dependency-name: io.vertx:vertx-core dependency-version: 5.0.4 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 5.0.4 dependency-type: direct:production update-type: version-update:semver-major - dependency-name: io.vertx:vertx-junit5 dependency-version: 5.0.4 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Revert vertx4-test module to Vertx 4.x version The feign-vertx4-test module is specifically for testing compatibility with Vertx 4.x. Dependabot incorrectly upgraded it from 4.5.14 to 5.0.4, causing API incompatibilities. This reverts the vertx4-test module back to 4.5.14 while keeping vertx5-test at 5.0.4. Signed-off-by: Marvin Froeder --------- Signed-off-by: dependabot[bot] Signed-off-by: Marvin Froeder Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin Froeder --- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 02367decda..d330c3ad9e 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.0.1 + 5.0.4 diff --git a/vertx/pom.xml b/vertx/pom.xml index a3febc950a..f8f8bedaef 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -34,7 +34,7 @@ - 5.0.1 + 5.0.4 2.0.16 3.0.1 From a84adfb23032b443caeb9d69629b91c9b8ac683d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:07:39 -0300 Subject: [PATCH 236/615] build(deps): Bump jackson.version from 2.19.2 to 2.20 (#3007) * build(deps): Bump jackson.version from 2.19.2 to 2.20 Bumps `jackson.version` from 2.19.2 to 2.20. Updates `com.fasterxml.jackson.core:jackson-databind` from 2.19.2 to 2.20 Updates `com.fasterxml.jackson.core:jackson-core` from 2.19.2 to 2.20 Updates `com.fasterxml.jackson.core:jackson-annotations` from 2.19.2 to 2.20 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.jr:jackson-jr-objects` from 2.19.2 to 2.20 Updates `com.fasterxml.jackson.jr:jackson-jr-annotation-support` from 2.19.2 to 2.20 Updates `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider` from 2.19.2 to 2.20 Updates `com.fasterxml.jackson:jackson-bom` from 2.19.2 to 2.20 --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: '2.20' dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-version: '2.20' dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-version: '2.20' dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.jr:jackson-jr-objects dependency-version: '2.20' dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.jr:jackson-jr-annotation-support dependency-version: '2.20' dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-version: '2.20' dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: '2.20' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Fix Jackson 2.20 upgrade and Spring Boot test port conflicts Changes: - Split Jackson version properties: jackson.version (2.20.0) for core/databind, jackson.annotations.version (2.20) for annotations - Fix form-spring tests to use same port (8080) to allow Spring context sharing - Add DirtiesContext annotations to properly clean up Spring test contexts - Configure surefire to run tests alphabetically for consistent ordering This resolves build failures caused by: 1. Jackson 2.20 versioning change where annotations no longer uses patch version 2. Spring Boot 3.5.6 context cleanup issues between tests using different ports Signed-off-by: Marvin Froeder --------- Signed-off-by: dependabot[bot] Signed-off-by: Marvin Froeder Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin Froeder --- form-spring/pom.xml | 7 +++++++ .../test/java/feign/form/feign/spring/DownloadClient.java | 2 +- .../feign/form/feign/spring/SpringFormEncoderTest.java | 3 +++ .../form/feign/spring/SpringMultipartDecoderTest.java | 5 ++++- pom.xml | 5 +++-- vertx/feign-vertx/pom.xml | 2 +- 6 files changed, 19 insertions(+), 5 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index aaa7a42051..ad77c69a34 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -147,6 +147,13 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + alphabetical + + diff --git a/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java b/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java index b1b3a61949..aa4e42bc13 100644 --- a/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java +++ b/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java @@ -33,7 +33,7 @@ @FeignClient( name = "multipart-download-support-service", - url = "http://localhost:8081", + url = "http://localhost:8080", configuration = DownloadClient.ClientConfiguration.class) interface DownloadClient { diff --git a/form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java b/form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java index f87e18660c..5bf9fa3499 100644 --- a/form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java +++ b/form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java @@ -28,6 +28,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.web.multipart.MultipartFile; @SpringBootTest( @@ -38,6 +40,7 @@ "feign.hystrix.enabled=false", "logging.level.feign.form.feign.spring.Client=DEBUG" }) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) class SpringFormEncoderTest { @Autowired private Client client; diff --git a/form-spring/src/test/java/feign/form/feign/spring/SpringMultipartDecoderTest.java b/form-spring/src/test/java/feign/form/feign/spring/SpringMultipartDecoderTest.java index 129d62230c..2412b552d1 100644 --- a/form-spring/src/test/java/feign/form/feign/spring/SpringMultipartDecoderTest.java +++ b/form-spring/src/test/java/feign/form/feign/spring/SpringMultipartDecoderTest.java @@ -23,12 +23,15 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.web.multipart.MultipartFile; @SpringBootTest( webEnvironment = DEFINED_PORT, classes = Server.class, - properties = {"server.port=8081", "feign.hystrix.enabled=false"}) + properties = {"server.port=8080", "feign.hystrix.enabled=false"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) class SpringMultipartDecoderTest { @Autowired private DownloadClient downloadClient; diff --git a/pom.xml b/pom.xml index 20132861df..6e85e3ec44 100644 --- a/pom.xml +++ b/pom.xml @@ -178,7 +178,8 @@ 3.5.6 6.0.0 - 2.19.2 + 2.20.0 + 2.20 3.27.6 5.20.0 2.0.59 @@ -445,7 +446,7 @@ com.fasterxml.jackson.core jackson-annotations - ${jackson.version} + ${jackson.annotations.version} diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index b1847eda3b..6cd46521fb 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -31,7 +31,7 @@ 11 - 2.19.2 + 2.20.0 From b3a8957d7b08a70bc6660508907de1943214eeb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:31:34 -0300 Subject: [PATCH 237/615] build(deps-dev): Bump org.springframework:spring-context (#3087) Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 6.2.11 to 6.2.12. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.11...v6.2.12) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 6.2.12 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 5bc47b69f2..691c7c884c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - 6.2.11 + 6.2.12 test From eaa6f00be1a15b8fda06d267caaa7fe9d8e24c80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:31:43 -0300 Subject: [PATCH 238/615] build(deps): Bump netty.version from 4.2.6.Final to 4.2.7.Final (#3086) Bumps `netty.version` from 4.2.6.Final to 4.2.7.Final. Updates `io.netty:netty-bom` from 4.2.6.Final to 4.2.7.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.6.Final...netty-4.2.7.Final) Updates `io.netty:netty-handler` from 4.2.6.Final to 4.2.7.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.6.Final...netty-4.2.7.Final) Updates `io.netty:netty-codec-http` from 4.2.6.Final to 4.2.7.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.6.Final...netty-4.2.7.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.7.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.7.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.7.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 2da672ad32..150e7695be 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.6.Final + 4.2.7.Final true From 44888a746a9434a4dc729d1cb2e234f9644edac6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:31:51 -0300 Subject: [PATCH 239/615] build(deps): Bump reactor.version from 3.7.11 to 3.7.12 (#3085) Bumps `reactor.version` from 3.7.11 to 3.7.12. Updates `io.projectreactor:reactor-core` from 3.7.11 to 3.7.12 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.11...v3.7.12) Updates `io.projectreactor:reactor-test` from 3.7.11 to 3.7.12 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.11...v3.7.12) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.7.12 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.7.12 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index 41644e1f37..24efa55e4a 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.7.11 + 3.7.12 1.0.4 2.2.21 From f4c8829e63fa790c41fdc031cb1e4b51e49150de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:31:59 -0300 Subject: [PATCH 240/615] build(deps): Bump com.google.http-client:google-http-client (#3083) Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 2.0.1 to 2.0.2. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v2.0.1...v2.0.2) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-version: 2.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6e85e3ec44..0855012d4d 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 5.2.0 33.5.0-jre - 2.0.1 + 2.0.2 2.13.2 1.15.2 2.0.17 From fe54265b57bbe8a7b846e32645381d443d8bf618 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:32:08 -0300 Subject: [PATCH 241/615] build(deps): Bump micrometer.version from 1.15.4 to 1.15.5 (#3082) Bumps `micrometer.version` from 1.15.4 to 1.15.5. Updates `io.micrometer:micrometer-core` from 1.15.4 to 1.15.5 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.15.4...v1.15.5) Updates `io.micrometer:micrometer-test` from 1.15.4 to 1.15.5 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.15.4...v1.15.5) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.15.5 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-version: 1.15.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index b6a8f54089..c9a5b2514f 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.15.4 + 1.15.5 From 6c70f9453e5ad74b980d1391a8a0db5c7433dbdd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:32:16 -0300 Subject: [PATCH 242/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks (#3081) Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.18.0 to 3.19.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.18.0...v3.19.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.19.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0855012d4d..b1b2c21ece 100644 --- a/pom.xml +++ b/pom.xml @@ -1073,7 +1073,7 @@ org.openrewrite.recipe rewrite-testing-frameworks - 3.18.0 + 3.19.0 org.openrewrite.recipe From 71641bd9c3a4a231606856960db7197d3a408a20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:32:23 -0300 Subject: [PATCH 243/615] build(deps-dev): Bump io.undertow:undertow-core (#3079) Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.19.Final to 2.3.20.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.19.Final...2.3.20.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-version: 2.3.20.Final dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- form/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/form/pom.xml b/form/pom.xml index 9eaa146cb4..f68207ba71 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -69,7 +69,7 @@ io.undertow undertow-core - 2.3.19.Final + 2.3.20.Final test From 4940ea67e5eadace5926d7d7fbfa7dd2e454cc3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:32:32 -0300 Subject: [PATCH 244/615] build(deps): Bump org.jacoco:jacoco-maven-plugin from 0.8.13 to 0.8.14 (#3078) Bumps [org.jacoco:jacoco-maven-plugin](https://github.com/jacoco/jacoco) from 0.8.13 to 0.8.14. - [Release notes](https://github.com/jacoco/jacoco/releases) - [Commits](https://github.com/jacoco/jacoco/compare/v0.8.13...v0.8.14) --- updated-dependencies: - dependency-name: org.jacoco:jacoco-maven-plugin dependency-version: 0.8.14 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b1b2c21ece..e8311f846d 100644 --- a/pom.xml +++ b/pom.xml @@ -913,7 +913,7 @@ org.jacoco jacoco-maven-plugin - 0.8.13 + 0.8.14 feign/** From 5df789c002ab66f663f61a907a8ebabcb4ce4b37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:32:40 -0300 Subject: [PATCH 245/615] build(deps): Bump org.openrewrite.maven:rewrite-maven-plugin (#3077) Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.19.0 to 6.21.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.19.0...v6.21.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.21.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e8311f846d..246dbda3ec 100644 --- a/pom.xml +++ b/pom.xml @@ -1067,7 +1067,7 @@ org.openrewrite.maven rewrite-maven-plugin - 6.19.0 + 6.21.1 From ac6e594b91c454edfd99c4631d4004a970649dee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:32:48 -0300 Subject: [PATCH 246/615] build(deps): Bump io.sundr:sundr-maven-plugin from 0.230.0 to 0.230.1 (#3073) Bumps [io.sundr:sundr-maven-plugin](https://github.com/sundrio/sundrio) from 0.230.0 to 0.230.1. - [Commits](https://github.com/sundrio/sundrio/compare/0.230.0...0.230.1) --- updated-dependencies: - dependency-name: io.sundr:sundr-maven-plugin dependency-version: 0.230.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 246dbda3ec..ce138beb3a 100644 --- a/pom.xml +++ b/pom.xml @@ -197,7 +197,7 @@ 0.1.1 0.9.0 3.5.4 - 0.230.0 + 0.230.1 file://${project.basedir}/src/config/bom.xml 2.2.1 2.19.1 From 75ff8a20d891fa032d98910329fb02e1209e3807 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 09:20:48 -0300 Subject: [PATCH 247/615] build(deps): Bump com.squareup.okhttp3:okhttp-bom from 5.2.0 to 5.2.1 (#3075) Bumps [com.squareup.okhttp3:okhttp-bom](https://github.com/square/okhttp) from 5.2.0 to 5.2.1. - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-5.2.0...parent-5.2.1) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp-bom dependency-version: 5.2.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ce138beb3a..5d4ba7f815 100644 --- a/pom.xml +++ b/pom.xml @@ -168,7 +168,7 @@ ${main.java.version} ${main.java.version} - 5.2.0 + 5.2.1 33.5.0-jre 2.0.2 2.13.2 From 77dbb2e098ab0a3a01786867a6513eff725c0466 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:19:01 -0300 Subject: [PATCH 248/615] build(deps): Bump io.dropwizard.metrics5:metrics-core from 5.0.0-rc21 to 5.0.5 (#3039) * build(deps): Bump io.dropwizard.metrics5:metrics-core Bumps [io.dropwizard.metrics5:metrics-core](https://github.com/dropwizard/metrics) from 5.0.0-rc21 to 5.0.5. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v5.0.0-rc21...v5.0.5) --- updated-dependencies: - dependency-name: io.dropwizard.metrics5:metrics-core dependency-version: 5.0.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * fix: dropwizard-metrics5 requires Java 17 Signed-off-by: Marvin Froeder --------- Signed-off-by: dependabot[bot] Signed-off-by: Marvin Froeder Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin Froeder --- dropwizard-metrics5/pom.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index e825314f8a..8353ecfe4f 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -27,6 +27,10 @@ Feign Dropwizard Metrics5 Feign Dropwizard Metrics 5 + + 17 + + ${project.groupId} @@ -40,7 +44,7 @@ io.dropwizard.metrics5 metrics-core - 5.0.0-rc21 + 5.0.5 ${project.groupId} From 5e6163df17c233c9e6ceac387ce638d294278248 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 19:56:42 -0300 Subject: [PATCH 249/615] build(deps): Bump com.github.jknack:handlebars from 4.3.1 to 4.5.0 (#2978) * build(deps): Bump com.github.jknack:handlebars from 4.3.1 to 4.5.0 Bumps [com.github.jknack:handlebars](https://github.com/jknack/handlebars.java) from 4.3.1 to 4.5.0. - [Release notes](https://github.com/jknack/handlebars.java/releases) - [Commits](https://github.com/jknack/handlebars.java/compare/v4.3.1...v4.5.0) --- updated-dependencies: - dependency-name: com.github.jknack:handlebars dependency-version: 4.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * fix: apt-test-generator requires Java 17 for handlebars 4.5.0 Signed-off-by: Marvin Froeder --------- Signed-off-by: dependabot[bot] Signed-off-by: Marvin Froeder Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marvin Froeder --- apt-test-generator/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index b3c7ed52bb..3d286bb827 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -31,6 +31,7 @@ Feign code generation tool for mocked clients + 17 true @@ -38,7 +39,7 @@ com.github.jknack handlebars - 4.3.1 + 4.5.0 From ec30480fff99bacba8983c5f809847af04a52df5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 20:01:39 -0300 Subject: [PATCH 250/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java (#3080) Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.18.0 to 3.19.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.18.0...v3.19.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.19.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5d4ba7f815..7c1388b5dc 100644 --- a/pom.xml +++ b/pom.xml @@ -1078,7 +1078,7 @@ org.openrewrite.recipe rewrite-migrate-java - 3.18.0 + 3.19.0 From 92a93289d7c4a9e50ce32d40480472acb20db2a6 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 20 Oct 2025 20:02:25 -0300 Subject: [PATCH 251/615] docs: add guidance for updating Java version in modules Signed-off-by: Marvin Froeder --- CLAUDE.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8eab9bf87e..4002f616a4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -78,4 +78,29 @@ Feign is a declarative HTTP client library with a modular design: ### Java Version Support - Source/target: Java 8 (for `src/main`) - Tests: Java 21 (for `src/test`) -- Maintains backwards compatibility with Java 8 in main codebase \ No newline at end of file +- Maintains backwards compatibility with Java 8 in main codebase + +### Updating Java Version for a Module +When a module's dependencies require a newer Java version (e.g., due to dependency upgrades), you need to override the Java version in that module's `pom.xml`: + +1. Add a `` section to the module's `pom.xml` (or update existing one) +2. Set `` to the required version (11, 17, 21, etc.) + +Example: +```xml + + 17 + +``` + +**Common scenarios requiring Java version updates:** +- Dropwizard Metrics 5.x requires Java 17 +- Handlebars 4.5.0+ requires Java 17 +- Jakarta EE modules typically require Java 11+ + +**Examples of modules with custom Java versions:** +- `spring/` - Java 17 (for Spring 6.x) +- `jaxrs4/` - Java 17 (for Jakarta EE 9+) +- `dropwizard-metrics5/` - Java 17 (for Metrics 5.x) +- `apt-test-generator/` - Java 17 (for Handlebars 4.5.0+) +- `soap-jakarta/`, `jaxb-jakarta/` - Java 11 (for Jakarta namespace) From 0d358c0b946caa3ead87f60edac7d55aeb538fae Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 20 Oct 2025 20:04:23 -0300 Subject: [PATCH 252/615] ci: add Dependabot auto-merge workflow Signed-off-by: Marvin Froeder --- .github/workflows/auto-merge-dependabot.yml | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/auto-merge-dependabot.yml diff --git a/.github/workflows/auto-merge-dependabot.yml b/.github/workflows/auto-merge-dependabot.yml new file mode 100644 index 0000000000..cc3a140b96 --- /dev/null +++ b/.github/workflows/auto-merge-dependabot.yml @@ -0,0 +1,31 @@ +name: Dependabot auto-merge +on: + pull_request: + branches: + - master + +permissions: + contents: write + pull-requests: write + +jobs: + dependabot: + runs-on: ubuntu-latest + if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'OpenFeign/feign' + steps: + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v2.2.0 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Auto-approve Dependabot PRs + uses: hmarr/auto-approve-action@v3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Enable auto-merge for Dependabot PRs + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GH_TOKEN: ${{secrets.GITHUB_TOKEN}} From 7ebca9f3572405af0244b2c86de45f2dbd95ca3a Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 20 Oct 2025 21:33:01 -0300 Subject: [PATCH 253/615] build: migrate to Central Portal API for Maven releases Signed-off-by: Marvin Froeder --- pom.xml | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/pom.xml b/pom.xml index 7c1388b5dc..d572ca1a42 100644 --- a/pom.xml +++ b/pom.xml @@ -141,17 +141,6 @@ https://github.com/openfeign/feign/issues - - - central - https://central.sonatype.com/api/v1/publisher - - - central - https://central.sonatype.com/api/v1/publisher - - - UTF-8 UTF-8 @@ -877,18 +866,6 @@ ${project.version} - - org.sonatype.central - central-publishing-maven-plugin - ${central-publishing-maven-plugin.version} - true - - central - true - published - all - - org.apache.maven.plugins maven-enforcer-plugin @@ -1035,6 +1012,25 @@ + + org.sonatype.central + central-publishing-maven-plugin + ${central-publishing-maven-plugin.version} + true + + central + true + published + required + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + From d291ead2afb231244fd13da2d262667f44296e47 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 20 Oct 2025 21:55:15 -0300 Subject: [PATCH 254/615] fix: decode base64-encoded GPG key before importing in CircleCI Signed-off-by: Marvin Froeder --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 22ac02c0f7..dd72406d1b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -92,7 +92,7 @@ commands: - run: name: 'Configure GPG keys' command: | - echo -e "$GPG_KEY" | gpg --batch --no-tty --import --yes + echo -e "$GPG_KEY" | base64 -d | gpg --batch --yes --import nexus-deploy: steps: - run: From ab644ee6a4e733f5acbc78ac5d2fd4bc4e49d936 Mon Sep 17 00:00:00 2001 From: Marvin Date: Tue, 21 Oct 2025 09:30:00 -0300 Subject: [PATCH 255/615] refactor: extract all hardcoded versions to parent POM properties (#3088) * refactor: extract all hardcoded versions to properties Signed-off-by: Marvin Froeder * refactor: extract all dependency and plugin versions to parent POM properties Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder --- apt-test-generator/pom.xml | 10 ++-- benchmark/pom.xml | 4 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 6 +- example-github/pom.xml | 6 +- example-wikipedia-with-springboot/pom.xml | 6 +- example-wikipedia/pom.xml | 6 +- form-spring/pom.xml | 14 ++--- form/pom.xml | 12 ++-- hc5/pom.xml | 2 +- httpclient/pom.xml | 4 +- hystrix/pom.xml | 4 +- jackson-jaxb/pom.xml | 8 +-- jaxb-jakarta/pom.xml | 4 +- jaxb/pom.xml | 4 +- jaxrs/pom.xml | 4 +- jaxrs2/pom.xml | 4 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- pom.xml | 69 +++++++++++++++++++---- soap-jakarta/pom.xml | 10 ++-- soap/pom.xml | 8 +-- 24 files changed, 122 insertions(+), 73 deletions(-) diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index 3d286bb827..d3eb3165d0 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -39,7 +39,7 @@ com.github.jknack handlebars - 4.5.0 + ${handlebars.version} @@ -51,7 +51,7 @@ com.google.testing.compile compile-testing - 0.23.0 + ${compile-testing.version} test @@ -75,7 +75,7 @@ com.google.auto.service auto-service-annotations - 1.1.1 + ${auto-service-annotations.version} provided @@ -104,7 +104,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.1 + ${maven-shade-plugin.version} @@ -125,7 +125,7 @@ org.skife.maven really-executable-jar-maven-plugin - 2.1.1 + ${really-executable-jar-maven-plugin.version} github diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 150e7695be..d2f63dfea4 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -137,7 +137,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.1 + ${maven-shade-plugin.version} @@ -158,7 +158,7 @@ org.skife.maven really-executable-jar-maven-plugin - 2.1.1 + ${really-executable-jar-maven-plugin.version} benchmark diff --git a/core/pom.xml b/core/pom.xml index 691c7c884c..02f493ff3b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - 6.2.12 + ${spring-context.version} test diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 8c6716c89d..d137ae0b4c 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -40,7 +40,7 @@ io.dropwizard.metrics metrics-core - 4.2.37 + ${metrics-core-4.version} ${project.groupId} diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 8353ecfe4f..620a5976dc 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -44,7 +44,7 @@ io.dropwizard.metrics5 metrics-core - 5.0.5 + ${metrics-core-5.version} ${project.groupId} diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 6089ec6083..6e885acae1 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -45,7 +45,7 @@ org.apache.commons commons-exec - 1.5.0 + ${commons-exec.version} test @@ -56,7 +56,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.1 + ${maven-shade-plugin.version} @@ -77,7 +77,7 @@ org.skife.maven really-executable-jar-maven-plugin - 2.1.1 + ${really-executable-jar-maven-plugin.version} github diff --git a/example-github/pom.xml b/example-github/pom.xml index aae72fce9c..ae9539a053 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -41,7 +41,7 @@ org.apache.commons commons-exec - 1.5.0 + ${commons-exec.version} test @@ -52,7 +52,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.1 + ${maven-shade-plugin.version} @@ -73,7 +73,7 @@ org.skife.maven really-executable-jar-maven-plugin - 2.1.1 + ${really-executable-jar-maven-plugin.version} github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 514e986546..8253cdf48a 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -39,7 +39,7 @@ org.springframework.cloud spring-cloud-dependencies - 2025.0.0 + ${spring-cloud-dependencies.version} pom import @@ -66,7 +66,7 @@ org.apache.commons commons-exec - 1.5.0 + ${commons-exec.version} test @@ -100,7 +100,7 @@ org.skife.maven really-executable-jar-maven-plugin - 2.1.1 + ${really-executable-jar-maven-plugin.version} wikipedia diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 102d8b2851..4493615581 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -42,7 +42,7 @@ org.apache.commons commons-exec - 1.5.0 + ${commons-exec.version} test @@ -53,7 +53,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.1 + ${maven-shade-plugin.version} @@ -74,7 +74,7 @@ org.skife.maven really-executable-jar-maven-plugin - 2.1.1 + ${really-executable-jar-maven-plugin.version} wikipedia diff --git a/form-spring/pom.xml b/form-spring/pom.xml index ad77c69a34..498e170242 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -39,12 +39,12 @@ org.apache.commons commons-text - 1.14.0 + ${commons-text.version} org.projectlombok lombok - 1.18.42 + ${lombok.version} provided @@ -58,14 +58,14 @@ org.springframework spring-web - 6.2.11 + ${spring-web.version} compile commons-fileupload commons-fileupload - 1.6.0 + ${commons-fileupload.version} compile @@ -78,7 +78,7 @@ org.springframework.cloud spring-cloud-starter-openfeign - 4.3.0 + ${spring-cloud-starter-openfeign.version} test @@ -125,13 +125,13 @@ org.mockito mockito-core - 5.20.0 + ${mockito.version} test org.mockito mockito-junit-jupiter - 5.20.0 + ${mockito.version} test diff --git a/form/pom.xml b/form/pom.xml index f68207ba71..21f22c415f 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -33,7 +33,7 @@ org.projectlombok lombok - 1.18.42 + ${lombok.version} provided @@ -50,7 +50,7 @@ org.apache.commons commons-text - 1.14.0 + ${commons-text.version} test @@ -69,13 +69,13 @@ io.undertow undertow-core - 2.3.20.Final + ${undertow-core.version} test io.appulse utils-java - 1.18.0 + ${utils-java.version} test @@ -99,13 +99,13 @@ org.mockito mockito-core - 5.20.0 + ${mockito.version} test org.mockito mockito-junit-jupiter - 5.20.0 + ${mockito.version} test diff --git a/hc5/pom.xml b/hc5/pom.xml index 0ade0edee6..3090cf5332 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -38,7 +38,7 @@ org.apache.httpcomponents.client5 httpclient5 - 5.5.1 + ${httpclient5.version} diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 198b2872ee..ef83da18aa 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -38,7 +38,7 @@ --> commons-codec commons-codec - 1.19.0 + ${commons-codec.version} @@ -52,7 +52,7 @@ org.apache.httpcomponents httpclient - 4.5.14 + ${httpclient4.version} diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 34eeaefaaa..1800dae670 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -48,14 +48,14 @@ com.netflix.archaius archaius-core - 0.7.12 + ${archaius-core.version} test com.netflix.hystrix hystrix-core - 1.5.18 + ${hystrix-core.version} diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 2e79ad6bef..5cf4a6ee5b 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -47,13 +47,13 @@ javax.ws.rs jsr311-api - 1.1.1 + ${jsr311-api.version} javax.ws.rs javax.ws.rs-api - 2.1.1 + ${javax.ws.rs-api.version} test @@ -67,7 +67,7 @@ com.sun.jersey jersey-client - 1.19.4 + ${jersey-client.version} test @@ -81,7 +81,7 @@ com.sun.xml.bind jaxb-impl - 2.3.9 + ${jaxb-impl-2.version} test diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 3ed1ccba93..7d773f0ec0 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -50,14 +50,14 @@ jakarta.xml.bind jakarta.xml.bind-api - 4.0.4 + ${jakarta.xml.bind-api.version} com.sun.xml.bind jaxb-impl - 4.0.3 + ${jaxb-impl-4.version} test diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 99ab6003db..38fc67c75f 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -44,14 +44,14 @@ javax.xml.bind jaxb-api - 2.3.1 + ${jaxb-api.version} com.sun.xml.bind jaxb-impl - 2.3.9 + ${jaxb-impl-2.version} test diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 1584af5975..62d6b3a80a 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -38,7 +38,7 @@ javax.ws.rs jsr311-api - 1.1.1 + ${jsr311-api.version} @@ -71,7 +71,7 @@ org.eclipse.transformer org.eclipse.transformer.maven - 0.2.0 + ${org.eclipse.transformer.maven.version} jakarta-ee diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 2ddaf0f7f2..767f956549 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -43,7 +43,7 @@ javax.ws.rs javax.ws.rs-api - 2.1.1 + ${javax.ws.rs-api.version} @@ -118,7 +118,7 @@ org.eclipse.transformer org.eclipse.transformer.maven - 0.2.0 + ${org.eclipse.transformer.maven.version} jakarta-ee diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 762cacd2aa..9af476c2d3 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -49,7 +49,7 @@ jakarta.ws.rs jakarta.ws.rs-api - 3.1.0 + ${jakarta.ws.rs-api-3.version} diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index fde82d6bdb..1c86480192 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -43,7 +43,7 @@ jakarta.ws.rs jakarta.ws.rs-api - 4.0.0 + ${jakarta.ws.rs-api-4.version} diff --git a/pom.xml b/pom.xml index d572ca1a42..4ab1ce314b 100644 --- a/pom.xml +++ b/pom.xml @@ -194,6 +194,55 @@ 3.1.4 1.2.2 1.3.0.Final + 3.6.2 + 3.2.0 + 1.2.8 + 4.0.0 + 0.8.14 + 0.1.4 + 6.21.1 + 3.19.0 + 3.19.0 + 1.0 + + + 0.7.12 + 1.1.1 + 1.19.0 + 1.5.0 + 1.6.0 + 1.14.0 + 0.23.0 + 4.5.0 + 4.5.14 + 5.5.1 + 1.5.18 + 3.1.0 + 4.0.0 + 4.0.4 + 3.0.2 + 4.0.2 + 2.1.1 + 2.3.1 + 2.3.9 + 4.0.3 + 2.3.1 + 1.19.4 + 1.1.1 + 1.18.42 + 3.6.1 + 4.2.37 + 5.0.5 + 0.2.0 + 2.1.1 + 1.5.3 + 3.0.2 + 2025.0.0 + 4.3.0 + 6.2.12 + 6.2.11 + 2.3.20.Final + 1.18.0 @@ -773,7 +822,7 @@ de.qaware.maven go-offline-maven-plugin - 1.2.8 + ${go-offline-maven-plugin.version} @@ -785,7 +834,7 @@ org.codehaus.mojo.signature java18 - 1.0 + ${java18-signature.version} signature MAIN @@ -795,7 +844,7 @@ com.github.ekryd.sortpom sortpom-maven-plugin - 4.0.0 + ${sortpom-maven-plugin.version} true \n @@ -869,7 +918,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.6.2 + ${maven-enforcer-plugin.version} enforce-no-repositories @@ -890,7 +939,7 @@ org.jacoco jacoco-maven-plugin - 0.8.14 + ${jacoco-maven-plugin.version} feign/** @@ -900,7 +949,7 @@ com.marvinformatics.jacoco easy-jacoco-maven-plugin - 0.1.4 + ${easy-jacoco-maven-plugin.version} @@ -1063,18 +1112,18 @@ org.openrewrite.maven rewrite-maven-plugin - 6.21.1 + ${rewrite-maven-plugin.version} org.openrewrite.recipe rewrite-testing-frameworks - 3.19.0 + ${rewrite-testing-frameworks.version} org.openrewrite.recipe rewrite-migrate-java - 3.19.0 + ${rewrite-migrate-java.version} @@ -1132,7 +1181,7 @@ org.apache.maven.plugins maven-toolchains-plugin - 3.2.0 + ${maven-toolchains-plugin.version} diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 6c6e344e21..5f7dec40ce 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -58,27 +58,27 @@ jakarta.xml.ws jakarta.xml.ws-api - 4.0.2 + ${jakarta.xml.ws-api.version} jakarta.xml.soap jakarta.xml.soap-api - 3.0.2 + ${jakarta.xml.soap-api.version} jakarta.xml.bind jakarta.xml.bind-api - 4.0.4 + ${jakarta.xml.bind-api.version} com.sun.xml.messaging.saaj saaj-impl - 3.0.2 + ${saaj-impl-3.version} com.sun.xml.bind jaxb-impl - 4.0.3 + ${jaxb-impl-4.version} runtime diff --git a/soap/pom.xml b/soap/pom.xml index f9057e4405..09e03f3869 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -54,22 +54,22 @@ javax.xml.ws jaxws-api - 2.3.1 + ${jaxws-api.version} javax.xml.bind jaxb-api - 2.3.1 + ${jaxb-api.version} com.sun.xml.messaging.saaj saaj-impl - 1.5.3 + ${saaj-impl-1.version} com.sun.xml.bind jaxb-impl - 2.3.9 + ${jaxb-impl-2.version} test From dfcefc25955bb2cd971801b4af5b59388adedf0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Oct 2025 05:03:05 +0000 Subject: [PATCH 256/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.19.0 to 3.20.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.19.0...v3.20.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.20.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4ab1ce314b..f20723a9d5 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 0.8.14 0.1.4 6.21.1 - 3.19.0 + 3.20.0 3.19.0 1.0 From 35e325725e0e872afb493b85b8dac19d727a8c88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Oct 2025 05:13:58 +0000 Subject: [PATCH 257/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.19.0 to 3.20.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.19.0...v3.20.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.20.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f20723a9d5..353830de56 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 0.1.4 6.21.1 3.20.0 - 3.19.0 + 3.20.0 1.0 From 0d773463e61d2e08b32d6ad1a6975e04f3aae4e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Oct 2025 05:13:58 +0000 Subject: [PATCH 258/615] build(deps): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.21.1 to 6.22.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.21.1...v6.22.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.22.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f20723a9d5..3d6e8f1c95 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 4.0.0 0.8.14 0.1.4 - 6.21.1 + 6.22.1 3.20.0 3.19.0 1.0 From 57d36ce50cf4b5d7f3c10e3f5e6bbdffa5757fb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 05:10:24 +0000 Subject: [PATCH 259/615] build(deps): Bump kotlin.version from 2.2.20 to 2.2.21 Bumps `kotlin.version` from 2.2.20 to 2.2.21. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.2.20 to 2.2.21 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v2.2.21/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.20...v2.2.21) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.2.20 to 2.2.21 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v2.2.21/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.20...v2.2.21) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.2.20 to 2.2.21 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-version: 2.2.21 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-version: 2.2.21 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-version: 2.2.21 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 646a49903d..b90357b8f0 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.2.20 + 2.2.21 1.10.2 From 372ad30f80f9670381232417903134f49d1431b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 05:20:08 +0000 Subject: [PATCH 260/615] build(deps): Bump com.alibaba.fastjson2:fastjson2 from 2.0.59 to 2.0.60 Bumps [com.alibaba.fastjson2:fastjson2](https://github.com/alibaba/fastjson2) from 2.0.59 to 2.0.60. - [Release notes](https://github.com/alibaba/fastjson2/releases) - [Commits](https://github.com/alibaba/fastjson2/compare/2.0.59...2.0.60) --- updated-dependencies: - dependency-name: com.alibaba.fastjson2:fastjson2 dependency-version: 2.0.60 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a32bfe9a90..6c79cbb090 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 2.20 3.27.6 5.20.0 - 2.0.59 + 2.0.60 1.5.3 5.4 From f020990a84c7d70a088a70e3f9bd5fdcb19aef72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Oct 2025 05:02:35 +0000 Subject: [PATCH 261/615] build(deps): Bump io.sundr:sundr-maven-plugin from 0.230.1 to 0.230.2 Bumps [io.sundr:sundr-maven-plugin](https://github.com/sundrio/sundrio) from 0.230.1 to 0.230.2. - [Commits](https://github.com/sundrio/sundrio/compare/0.230.1...0.230.2) --- updated-dependencies: - dependency-name: io.sundr:sundr-maven-plugin dependency-version: 0.230.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6c79cbb090..0cc7fca16c 100644 --- a/pom.xml +++ b/pom.xml @@ -186,7 +186,7 @@ 0.1.1 0.9.0 3.5.4 - 0.230.1 + 0.230.2 file://${project.basedir}/src/config/bom.xml 2.2.1 2.19.1 From 64cc15a27e4dd31e2c32c8620c60cf1e5d0ebbc2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 05:02:47 +0000 Subject: [PATCH 262/615] build(deps): Bump jackson.version from 2.20.0 to 2.20.1 Bumps `jackson.version` from 2.20.0 to 2.20.1. Updates `com.fasterxml.jackson.core:jackson-databind` from 2.20.0 to 2.20.1 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.core:jackson-core` from 2.20.0 to 2.20.1 - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.20.0...jackson-core-2.20.1) Updates `com.fasterxml.jackson.jr:jackson-jr-objects` from 2.20.0 to 2.20.1 - [Commits](https://github.com/FasterXML/jackson-jr/compare/jackson-jr-parent-2.20.0...jackson-jr-parent-2.20.1) Updates `com.fasterxml.jackson.jr:jackson-jr-annotation-support` from 2.20.0 to 2.20.1 - [Commits](https://github.com/FasterXML/jackson-jr/compare/jackson-jr-parent-2.20.0...jackson-jr-parent-2.20.1) Updates `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider` from 2.20.0 to 2.20.1 Updates `com.fasterxml.jackson:jackson-bom` from 2.20.0 to 2.20.1 - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.20.0...jackson-bom-2.20.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.20.1 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-version: 2.20.1 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jr:jackson-jr-objects dependency-version: 2.20.1 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jr:jackson-jr-annotation-support dependency-version: 2.20.1 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-version: 2.20.1 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.20.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0cc7fca16c..75cd4ae2c9 100644 --- a/pom.xml +++ b/pom.xml @@ -167,7 +167,7 @@ 3.5.6 6.0.0 - 2.20.0 + 2.20.1 2.20 3.27.6 5.20.0 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 6cd46521fb..d263ec575f 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -31,7 +31,7 @@ 11 - 2.20.0 + 2.20.1 From f71ce5a1436e5e08f2a7dcf4ed389e283a307cb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 05:04:14 +0000 Subject: [PATCH 263/615] build(deps): Bump com.squareup.okhttp3:okhttp-bom from 5.2.1 to 5.3.0 Bumps [com.squareup.okhttp3:okhttp-bom](https://github.com/square/okhttp) from 5.2.1 to 5.3.0. - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-5.2.1...parent-5.3.0) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp-bom dependency-version: 5.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0cc7fca16c..14e65c2a45 100644 --- a/pom.xml +++ b/pom.xml @@ -157,7 +157,7 @@ ${main.java.version} ${main.java.version} - 5.2.1 + 5.3.0 33.5.0-jre 2.0.2 2.13.2 From ff9dff8ad42b1b09e15c626e0aaee096ef98a5d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 05:03:52 +0000 Subject: [PATCH 264/615] build(deps): Bump org.junit:junit-bom from 6.0.0 to 6.0.1 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r6.0.0...r6.0.1) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b53a957940..ae1592eb17 100644 --- a/pom.xml +++ b/pom.xml @@ -166,7 +166,7 @@ 20250517 3.5.6 - 6.0.0 + 6.0.1 2.20.1 2.20 3.27.6 From 9e8716018085df1c9aecf2b867c21471631ebd89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 05:03:56 +0000 Subject: [PATCH 265/615] build(deps): Bump com.gradle:develocity-maven-extension Bumps com.gradle:develocity-maven-extension from 2.2 to 2.2.1. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: 2.2.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index a9e021833d..90c85f8bbf 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.2 + 2.2.1 com.gradle From 2d663d2f26804174520ec475295dec7555bb18ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 05:04:02 +0000 Subject: [PATCH 266/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.20.0 to 3.21.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.20.0...v3.21.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.21.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ae1592eb17..3fffa8ad1a 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 0.8.14 0.1.4 6.22.1 - 3.20.0 + 3.21.0 3.20.0 1.0 From 026e190262125264543965d6105b051597b940eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 05:14:32 +0000 Subject: [PATCH 267/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.20.0 to 3.21.1. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.20.0...v3.21.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.21.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3fffa8ad1a..6920346df0 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 0.1.4 6.22.1 3.21.0 - 3.20.0 + 3.21.1 1.0 From ad519462cee5d7c7a5c13e01ea97e462bb795857 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 05:14:50 +0000 Subject: [PATCH 268/615] build(deps): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.22.1 to 6.23.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.22.1...v6.23.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.23.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3fffa8ad1a..61cbf6fb39 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 4.0.0 0.8.14 0.1.4 - 6.22.1 + 6.23.0 3.21.0 3.20.0 1.0 From e71f7cc76fb75566890ea5f3f10d8de18da3a244 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 05:02:12 +0000 Subject: [PATCH 269/615] build(deps): Bump commons-codec:commons-codec from 1.19.0 to 1.20.0 Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.19.0 to 1.20.0. - [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.19.0...rel/commons-codec-1.20.0) --- updated-dependencies: - dependency-name: commons-codec:commons-codec dependency-version: 1.20.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0fd1063cc6..83ad694a68 100644 --- a/pom.xml +++ b/pom.xml @@ -208,7 +208,7 @@ 0.7.12 1.1.1 - 1.19.0 + 1.20.0 1.5.0 1.6.0 1.14.0 From 1a1025452c712a2e29afdf4fa20d7cd03a8baa40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 05:02:54 +0000 Subject: [PATCH 270/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.21.0 to 3.21.2. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.21.0...v3.21.2) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.21.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0fd1063cc6..3e465d56ca 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 0.8.14 0.1.4 6.23.0 - 3.21.0 + 3.21.2 3.21.1 1.0 From a90308f0239f8fea3d4ffa20249b0bcbee8008c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Nov 2025 05:03:58 +0000 Subject: [PATCH 271/615] build(deps): Bump micrometer.version from 1.15.5 to 1.16.0 Bumps `micrometer.version` from 1.15.5 to 1.16.0. Updates `io.micrometer:micrometer-core` from 1.15.5 to 1.16.0 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.15.5...v1.16.0) Updates `io.micrometer:micrometer-test` from 1.15.5 to 1.16.0 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.15.5...v1.16.0) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.16.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.micrometer:micrometer-test dependency-version: 1.16.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index c9a5b2514f..5215b05958 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.15.5 + 1.16.0 From ec3813b09ff58614ac70e313f7f2229967734c66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 05:04:13 +0000 Subject: [PATCH 272/615] build(deps): Bump reactor.version from 3.7.12 to 3.8.0 Bumps `reactor.version` from 3.7.12 to 3.8.0. Updates `io.projectreactor:reactor-core` from 3.7.12 to 3.8.0 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.12...v3.8.0) Updates `io.projectreactor:reactor-test` from 3.7.12 to 3.8.0 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.7.12...v3.8.0) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.8.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.projectreactor:reactor-test dependency-version: 3.8.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index 24efa55e4a..71903288cd 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.7.12 + 3.8.0 1.0.4 2.2.21 From 9c6f5f5fe6bef3c5d801a1355126765cc6fc0c9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 05:02:39 +0000 Subject: [PATCH 273/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.21.2 to 3.21.3. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.21.2...v3.21.3) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.21.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8709547a26..29b64287c9 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 0.8.14 0.1.4 6.23.0 - 3.21.2 + 3.21.3 3.21.1 1.0 From 8b1ff5f8f55752d9efed9400820a2adf50714350 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 05:13:38 +0000 Subject: [PATCH 274/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.21.1 to 3.21.2. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.21.1...v3.21.2) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.21.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 29b64287c9..ab8dad50b9 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 0.1.4 6.23.0 3.21.3 - 3.21.1 + 3.21.2 1.0 From 8a426412c275507874a0429ca93ea472ffe6816e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Nov 2025 05:02:44 +0000 Subject: [PATCH 275/615] build(deps-dev): Bump org.springframework:spring-context Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 6.2.12 to 7.0.0. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.12...v7.0.0) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 7.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ab8dad50b9..707ed34593 100644 --- a/pom.xml +++ b/pom.xml @@ -239,7 +239,7 @@ 3.0.2 2025.0.0 4.3.0 - 6.2.12 + 7.0.0 6.2.11 2.3.20.Final 1.18.0 From ec857306a3ecd05e216fd1fcd167e02ae682924c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 05:05:29 +0000 Subject: [PATCH 276/615] build(deps): Bump org.apache.maven.plugins:maven-jar-plugin Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.4.2 to 3.5.0. - [Release notes](https://github.com/apache/maven-jar-plugin/releases) - [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.4.2...maven-jar-plugin-3.5.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-jar-plugin dependency-version: 3.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 707ed34593..b0e0e7f383 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ 3.3.1 3.12.0 5.0.0 - 3.4.2 + 3.5.0 3.1.1 6.0.0 0.1.1 From 4c6c197c970024132f94fafb38ef556cc39d001f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 05:05:53 +0000 Subject: [PATCH 277/615] build(deps): Bump com.gradle:common-custom-user-data-maven-extension Bumps [com.gradle:common-custom-user-data-maven-extension](https://github.com/gradle/common-custom-user-data-maven-extension) from 2.0.6 to 2.1.0. - [Release notes](https://github.com/gradle/common-custom-user-data-maven-extension/releases) - [Commits](https://github.com/gradle/common-custom-user-data-maven-extension/compare/v2.0.6...v2.1.0) --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-maven-extension dependency-version: 2.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 90c85f8bbf..36c29faaba 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -24,7 +24,7 @@ com.gradle common-custom-user-data-maven-extension - 2.0.6 + 2.1.0 com.marvinformatics.jacoco From e6d481ab5774653a241eade160c219077f4724b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 05:05:58 +0000 Subject: [PATCH 278/615] build(deps): Bump com.squareup.okhttp3:okhttp-bom from 5.3.0 to 5.3.1 Bumps [com.squareup.okhttp3:okhttp-bom](https://github.com/square/okhttp) from 5.3.0 to 5.3.1. - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-5.3.0...parent-5.3.1) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp-bom dependency-version: 5.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 707ed34593..d2756c3f94 100644 --- a/pom.xml +++ b/pom.xml @@ -157,7 +157,7 @@ ${main.java.version} ${main.java.version} - 5.3.0 + 5.3.1 33.5.0-jre 2.0.2 2.13.2 From e341e22a894a3473aa29399b006f2d3650e6e18e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 05:17:11 +0000 Subject: [PATCH 279/615] build(deps): Bump org.apache.maven.plugins:maven-release-plugin Bumps [org.apache.maven.plugins:maven-release-plugin](https://github.com/apache/maven-release) from 3.1.1 to 3.2.0. - [Release notes](https://github.com/apache/maven-release/releases) - [Commits](https://github.com/apache/maven-release/compare/maven-release-3.1.1...maven-release-3.2.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-release-plugin dependency-version: 3.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 45adb975ff..c2ec7427bb 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ 3.12.0 5.0.0 3.5.0 - 3.1.1 + 3.2.0 6.0.0 0.1.1 0.9.0 From 7b8952fe2d99305bbe5280d9fcd892ff24de77d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 05:02:49 +0000 Subject: [PATCH 280/615] build(deps): Bump com.squareup.okhttp3:okhttp-bom from 5.3.1 to 5.3.2 Bumps [com.squareup.okhttp3:okhttp-bom](https://github.com/square/okhttp) from 5.3.1 to 5.3.2. - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-5.3.1...parent-5.3.2) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp-bom dependency-version: 5.3.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c2ec7427bb..d6ae07f640 100644 --- a/pom.xml +++ b/pom.xml @@ -157,7 +157,7 @@ ${main.java.version} ${main.java.version} - 5.3.1 + 5.3.2 33.5.0-jre 2.0.2 2.13.2 From be3a94f54c07ecb84e657648439cf0490ff1297d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 05:12:41 +0000 Subject: [PATCH 281/615] build(deps-dev): Bump org.glassfish.jersey.core:jersey-client in /jaxrs3 Bumps org.glassfish.jersey.core:jersey-client from 3.1.8 to 3.1.10. --- updated-dependencies: - dependency-name: org.glassfish.jersey.core:jersey-client dependency-version: 3.1.10 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- jaxrs3/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 9af476c2d3..f9c9df26b1 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -31,7 +31,7 @@ 11 - 3.1.8 + 3.1.10 From 831447d82867a185b9b1da852c5c18fbbaadfc1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=EC=A4=80?= <80584060+qkrtkdwns3410@users.noreply.github.com> Date: Wed, 19 Nov 2025 19:04:53 +0900 Subject: [PATCH 282/615] refactor: replace Charset.forName() with StandardCharsets constants for improved readability (#3122) --- core/src/main/java/feign/Util.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/feign/Util.java b/core/src/main/java/feign/Util.java index 99b56683df..91cb7e5a1a 100644 --- a/core/src/main/java/feign/Util.java +++ b/core/src/main/java/feign/Util.java @@ -34,6 +34,7 @@ import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -74,11 +75,11 @@ public class Util { public static final String ENCODING_DEFLATE = "deflate"; /** UTF-8: eight-bit UCS Transformation Format. */ - public static final Charset UTF_8 = Charset.forName("UTF-8"); + public static final Charset UTF_8 = StandardCharsets.UTF_8; // com.google.common.base.Charsets /** ISO-8859-1: ISO Latin Alphabet Number 1 (ISO-LATIN-1). */ - public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); + public static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1; private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes) From 1209beb9043764e82bb5f8e46216ade34d14d74f Mon Sep 17 00:00:00 2001 From: Vasiliy Date: Wed, 19 Nov 2025 15:05:42 +0500 Subject: [PATCH 283/615] docs(feign): add detailed javadoc for RequestLine annotation parameters (#3110) * docs(feign): add detailed javadoc for RequestLine annotation parameters * docs(feign): fixup formatting after CI/CD fail --- core/src/main/java/feign/RequestLine.java | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/core/src/main/java/feign/RequestLine.java b/core/src/main/java/feign/RequestLine.java index b9e8ceffd0..626c618757 100644 --- a/core/src/main/java/feign/RequestLine.java +++ b/core/src/main/java/feign/RequestLine.java @@ -30,9 +30,65 @@ @Retention(RUNTIME) public @interface RequestLine { + /** + * The HTTP request line, including the method and an optional URI template. + * + *

The string must begin with a valid {@linkplain feign.Request.HttpMethod HTTP method name} + * (e.g. {@linkplain feign.Request.HttpMethod#GET GET}, {@linkplain feign.Request.HttpMethod#POST + * POST}, {@linkplain feign.Request.HttpMethod#PUT PUT}), followed by a space and a URI template. + * If only the HTTP method is specified (e.g. {@code "DELETE"}), the request will use the base URL + * defined for the client. + * + *

Example: + * + *

{@code @RequestLine("GET /repos/{owner}/{repo}")
+   * Repo getRepo(@Param("owner") String owner, @Param("repo") String repo);
+   * }
+ * + * @return the HTTP method and optional URI template for the request. + * @see feign.template.UriTemplate + */ String value(); + /** + * Controls whether percent-encoded forward slashes ({@code %2F}) in expanded path variables are + * decoded back to {@code '/'} before sending the request. + * + *

When {@code true} (the default), any {@code %2F} sequences produced during URI template + * expansion will be replaced with literal slashes, meaning that path variables containing slashes + * will be interpreted as multiple path segments. + * + *

When {@code false}, percent-encoded slashes ({@code %2F}) are preserved in the final URL. + * This is useful when a path variable intentionally includes a slash as part of its value (for + * example, an encoded identifier such as {@code "foo%2Fbar"}). + * + *

Example: + * + *

{@code @RequestLine(value = "GET /projects/{id}", decodeSlash = false)
+   * Project getProject(@Param("id") String encodedId);
+   * }
+ * + * @return {@code true} if encoded slashes should be decoded (default behavior); {@code false} to + * preserve {@code %2F} sequences in the URL. + */ boolean decodeSlash() default true; + /** + * Specifies how collections (e.g. {@link java.util.List List} or arrays) are serialized when + * expanded into the URI template. + * + *

Determines whether values are represented as exploded parameters (repeated keys) or as a + * single comma-separated value, depending on the chosen {@link feign.CollectionFormat}. + * + *

Example: + * + *

    + *
  • {@linkplain CollectionFormat#EXPLODED EXPLODED}: {@code /items?id=1&id=2&id=3} + *
  • {@linkplain CollectionFormat#CSV CSV}: {@code /items?id=1,2,3} + *
+ * + * @return the collection serialization format to use when expanding templates. + * @see CollectionFormat + */ CollectionFormat collectionFormat() default CollectionFormat.EXPLODED; } From cc519ac5a57fad37898abf03885154619453cab2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 15:33:19 +0000 Subject: [PATCH 284/615] build(deps-dev): Bump org.glassfish.jersey.core:jersey-client in /jaxrs2 Bumps org.glassfish.jersey.core:jersey-client from 2.45 to 2.46. --- updated-dependencies: - dependency-name: org.glassfish.jersey.core:jersey-client dependency-version: '2.46' dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- jaxrs2/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 767f956549..ad4022f34c 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -31,7 +31,7 @@ true - 2.45 + 2.46 From f2707fa0b23ad996e500da7f9c709e97e03d370b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 05:02:32 +0000 Subject: [PATCH 285/615] build(deps-dev): Bump org.springframework:spring-context Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.0...v7.0.1) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 7.0.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d6ae07f640..d538d22604 100644 --- a/pom.xml +++ b/pom.xml @@ -239,7 +239,7 @@ 3.0.2 2025.0.0 4.3.0 - 7.0.0 + 7.0.1 6.2.11 2.3.20.Final 1.18.0 From 2e3e55ada8fbbce9a00502835cc6ac0611239d5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 05:02:56 +0000 Subject: [PATCH 286/615] build(deps): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.23.0 to 6.24.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.23.0...v6.24.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.24.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d6ae07f640..80d53936a6 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 4.0.0 0.8.14 0.1.4 - 6.23.0 + 6.24.0 3.21.3 3.21.2 1.0 From 20af2bc7be98bf95782e0a97c7b397d7e0128afa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 05:04:19 +0000 Subject: [PATCH 287/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.21.2 to 3.22.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.21.2...v3.22.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.22.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d6ae07f640..ad493fd769 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 0.1.4 6.23.0 3.21.3 - 3.21.2 + 3.22.0 1.0 From 30ff8a9ba1e8490d2668cb0f893e7f3df571de08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 05:14:47 +0000 Subject: [PATCH 288/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.21.3 to 3.22.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.21.3...v3.22.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.22.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6dcd6d47ab..79ee483300 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 0.8.14 0.1.4 6.24.0 - 3.21.3 + 3.22.0 3.22.0 1.0 From c1e914bccec32af754fadb69664c07b183e3732d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 05:02:48 +0000 Subject: [PATCH 289/615] build(deps): Bump org.codehaus.mojo:versions-maven-plugin Bumps [org.codehaus.mojo:versions-maven-plugin](https://github.com/mojohaus/versions) from 2.19.1 to 2.20.0. - [Release notes](https://github.com/mojohaus/versions/releases) - [Changelog](https://github.com/mojohaus/versions/blob/master/ReleaseNotes.md) - [Commits](https://github.com/mojohaus/versions/compare/2.19.1...2.20.0) --- updated-dependencies: - dependency-name: org.codehaus.mojo:versions-maven-plugin dependency-version: 2.20.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 79ee483300..f6794d441c 100644 --- a/pom.xml +++ b/pom.xml @@ -189,7 +189,7 @@ 0.230.2 file://${project.basedir}/src/config/bom.xml 2.2.1 - 2.19.1 + 2.20.0 3.2.8 3.1.4 1.2.2 From 3fe35ce552d475f50ce099f317f748406a6a24ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 05:02:53 +0000 Subject: [PATCH 290/615] build(deps): Bump org.codehaus.mojo:versions-maven-plugin Bumps [org.codehaus.mojo:versions-maven-plugin](https://github.com/mojohaus/versions) from 2.20.0 to 2.20.1. - [Release notes](https://github.com/mojohaus/versions/releases) - [Changelog](https://github.com/mojohaus/versions/blob/master/ReleaseNotes.md) - [Commits](https://github.com/mojohaus/versions/compare/2.20.0...2.20.1) --- updated-dependencies: - dependency-name: org.codehaus.mojo:versions-maven-plugin dependency-version: 2.20.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f6794d441c..82cd16e182 100644 --- a/pom.xml +++ b/pom.xml @@ -189,7 +189,7 @@ 0.230.2 file://${project.basedir}/src/config/bom.xml 2.2.1 - 2.20.0 + 2.20.1 3.2.8 3.1.4 1.2.2 From 7969d0dd16894527ad2419a3ea1afed4c7cd1550 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 05:04:09 +0000 Subject: [PATCH 291/615] build(deps): Bump org.apache.commons:commons-exec from 1.5.0 to 1.6.0 Bumps [org.apache.commons:commons-exec](https://github.com/apache/commons-exec) from 1.5.0 to 1.6.0. - [Changelog](https://github.com/apache/commons-exec/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-exec/compare/rel/commons-exec-1.5.0...rel/commons-exec-1.6.0) --- updated-dependencies: - dependency-name: org.apache.commons:commons-exec dependency-version: 1.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 82cd16e182..f5eedb7f5d 100644 --- a/pom.xml +++ b/pom.xml @@ -209,7 +209,7 @@ 0.7.12 1.1.1 1.20.0 - 1.5.0 + 1.6.0 1.6.0 1.14.0 0.23.0 From 08703ac86887042a6488352fc15ab9f59603f60f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 05:02:59 +0000 Subject: [PATCH 292/615] build(deps): Bump org.apache.maven.plugins:maven-release-plugin Bumps [org.apache.maven.plugins:maven-release-plugin](https://github.com/apache/maven-release) from 3.2.0 to 3.3.0. - [Release notes](https://github.com/apache/maven-release/releases) - [Commits](https://github.com/apache/maven-release/compare/maven-release-3.2.0...maven-release-3.3.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-release-plugin dependency-version: 3.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f5eedb7f5d..750cf350d0 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ 3.12.0 5.0.0 3.5.0 - 3.2.0 + 3.3.0 6.0.0 0.1.1 0.9.0 From 847145533e3a3db57051f6ec61f309568755ed21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 05:03:00 +0000 Subject: [PATCH 293/615] build(deps-dev): Bump org.apache.commons:commons-text Bumps [org.apache.commons:commons-text](https://github.com/apache/commons-text) from 1.14.0 to 1.15.0. - [Changelog](https://github.com/apache/commons-text/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-text/compare/rel/commons-text-1.14.0...rel/commons-text-1.15.0) --- updated-dependencies: - dependency-name: org.apache.commons:commons-text dependency-version: 1.15.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 750cf350d0..c0f9802f92 100644 --- a/pom.xml +++ b/pom.xml @@ -211,7 +211,7 @@ 1.20.0 1.6.0 1.6.0 - 1.14.0 + 1.15.0 0.23.0 4.5.0 4.5.14 From 683f47c92375229958653bcd448e055a3a200174 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 05:03:09 +0000 Subject: [PATCH 294/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.22.0 to 3.23.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.22.0...v3.23.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.23.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 750cf350d0..93e2f559dc 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 0.8.14 0.1.4 6.24.0 - 3.22.0 + 3.23.0 3.22.0 1.0 From 9c513f5b1d70a2001eab7b9e8e125f894d9f8252 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 05:13:54 +0000 Subject: [PATCH 295/615] build(deps): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.24.0 to 6.25.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.24.0...v6.25.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.25.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 686d34805e..7717d7151e 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 4.0.0 0.8.14 0.1.4 - 6.24.0 + 6.25.0 3.23.0 3.22.0 1.0 From 25e708581ba9baf379728ab92481dd5bbba73714 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 05:14:17 +0000 Subject: [PATCH 296/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.22.0 to 3.23.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.22.0...v3.23.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.23.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 686d34805e..bfbcb1be44 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 0.1.4 6.24.0 3.23.0 - 3.22.0 + 3.23.0 1.0 From c9aaf65cf0e9ea15273f991d3b52ffacf7224401 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 05:03:53 +0000 Subject: [PATCH 297/615] build(deps): Bump micrometer.version from 1.16.0 to 1.16.1 Bumps `micrometer.version` from 1.16.0 to 1.16.1. Updates `io.micrometer:micrometer-core` from 1.16.0 to 1.16.1 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.0...v1.16.1) Updates `io.micrometer:micrometer-test` from 1.16.0 to 1.16.1 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.0...v1.16.1) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.16.1 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-version: 1.16.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 5215b05958..44107908c5 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.16.0 + 1.16.1 From 1e66970661a1a1b49da1dca2fe404d3d7a954743 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 05:02:45 +0000 Subject: [PATCH 298/615] build(deps): Bump reactor.version from 3.8.0 to 3.8.1 Bumps `reactor.version` from 3.8.0 to 3.8.1. Updates `io.projectreactor:reactor-core` from 3.8.0 to 3.8.1 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.0...v3.8.1) Updates `io.projectreactor:reactor-test` from 3.8.0 to 3.8.1 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.0...v3.8.1) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.8.1 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.8.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index 71903288cd..1cd8fd8d6a 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.8.0 + 3.8.1 1.0.4 2.2.21 From a7e4d055e84669db9d4d96b3cc8866000d39daba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 05:03:15 +0000 Subject: [PATCH 299/615] build(deps): Bump mockito.version from 5.20.0 to 5.21.0 Bumps `mockito.version` from 5.20.0 to 5.21.0. Updates `org.mockito:mockito-core` from 5.20.0 to 5.21.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.20.0...v5.21.0) Updates `org.mockito:mockito-junit-jupiter` from 5.20.0 to 5.21.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.20.0...v5.21.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.21.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-junit-jupiter dependency-version: 5.21.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ba24977e02..31dcc2663a 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 2.20.1 2.20 3.27.6 - 5.20.0 + 5.21.0 2.0.60 1.5.3 From c28295dd9fcc2b307d67420a9f9d8981fe140a05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 05:02:46 +0000 Subject: [PATCH 300/615] build(deps): Bump com.gradle:develocity-maven-extension Bumps com.gradle:develocity-maven-extension from 2.2.1 to 2.3. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: '2.3' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 36c29faaba..593b403738 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.2.1 + 2.3 com.gradle From 8142217acac31f22a01ac55899b5159443767528 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 05:02:59 +0000 Subject: [PATCH 301/615] build(deps): Bump netty.version from 4.2.7.Final to 4.2.8.Final Bumps `netty.version` from 4.2.7.Final to 4.2.8.Final. Updates `io.netty:netty-bom` from 4.2.7.Final to 4.2.8.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.7.Final...netty-4.2.8.Final) Updates `io.netty:netty-handler` from 4.2.7.Final to 4.2.8.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.7.Final...netty-4.2.8.Final) Updates `io.netty:netty-codec-http` from 4.2.7.Final to 4.2.8.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.7.Final...netty-4.2.8.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.8.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.8.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.8.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index d2f63dfea4..25edb993bb 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.7.Final + 4.2.8.Final true From e642d5995ec832f4e11aa91247e1bddb588aff18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 05:02:54 +0000 Subject: [PATCH 302/615] build(deps): Bump org.apache.maven.plugins:maven-release-plugin Bumps [org.apache.maven.plugins:maven-release-plugin](https://github.com/apache/maven-release) from 3.3.0 to 3.3.1. - [Release notes](https://github.com/apache/maven-release/releases) - [Commits](https://github.com/apache/maven-release/compare/maven-release-3.3.0...maven-release-3.3.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-release-plugin dependency-version: 3.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 31dcc2663a..59090d015c 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ 3.12.0 5.0.0 3.5.0 - 3.3.0 + 3.3.1 6.0.0 0.1.1 0.9.0 From 8c55d1c9bb07c48e33131edc15913dc1b390e821 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 05:03:19 +0000 Subject: [PATCH 303/615] build(deps): Bump netty.version from 4.2.8.Final to 4.2.9.Final Bumps `netty.version` from 4.2.8.Final to 4.2.9.Final. Updates `io.netty:netty-bom` from 4.2.8.Final to 4.2.9.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.8.Final...netty-4.2.9.Final) Updates `io.netty:netty-handler` from 4.2.8.Final to 4.2.9.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.8.Final...netty-4.2.9.Final) Updates `io.netty:netty-codec-http` from 4.2.8.Final to 4.2.9.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.8.Final...netty-4.2.9.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.9.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.9.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.9.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 25edb993bb..30a8494d8e 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.8.Final + 4.2.9.Final true From a5255b1196825398201817189d52afd3f21ddcdb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 05:01:58 +0000 Subject: [PATCH 304/615] build(deps): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.25.0 to 6.26.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.25.0...v6.26.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.26.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 59090d015c..f921c2845d 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 4.0.0 0.8.14 0.1.4 - 6.25.0 + 6.26.0 3.23.0 3.23.0 1.0 From e414024ee2a92996abba2df9a9ed7f5bd459eed6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 05:08:45 +0000 Subject: [PATCH 305/615] build(deps): Bump kotlin.version from 2.2.21 to 2.3.0 Bumps `kotlin.version` from 2.2.21 to 2.3.0. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.2.21 to 2.3.0 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.21...v2.3.0) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.2.21 to 2.3.0 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.21...v2.3.0) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.2.21 to 2.3.0 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-version: 2.3.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-version: 2.3.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-version: 2.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index b90357b8f0..73704564df 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.2.21 + 2.3.0 1.10.2 From 5011883894c235d58d326094a54a1e6d3d6b8adc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 05:09:36 +0000 Subject: [PATCH 306/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.23.0 to 3.24.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.23.0...v3.24.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.24.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 59090d015c..ca53dbf357 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 0.1.4 6.25.0 3.23.0 - 3.23.0 + 3.24.0 1.0 From 79d9c67102917e806d6a83254669584be9569d83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 05:20:26 +0000 Subject: [PATCH 307/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.23.0 to 3.24.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.23.0...v3.24.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.24.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ac169bab6e..14687c6a2b 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 0.8.14 0.1.4 6.26.0 - 3.23.0 + 3.24.0 3.24.0 1.0 From ca0677bc3268f6702b3a810f191c9f8b833a9acd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Dec 2025 05:03:23 +0000 Subject: [PATCH 308/615] build(deps): Bump com.google.http-client:google-http-client Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 2.0.2 to 2.0.3. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v2.0.2...v2.0.3) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-version: 2.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 14687c6a2b..46a1e18c26 100644 --- a/pom.xml +++ b/pom.xml @@ -159,7 +159,7 @@ 5.3.2 33.5.0-jre - 2.0.2 + 2.0.3 2.13.2 1.15.2 2.0.17 From d27e5363e605b29d8f18921fadc6bc94532e51b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 05:03:56 +0000 Subject: [PATCH 309/615] build(deps): Bump com.alibaba.fastjson2:fastjson2 Bumps [com.alibaba.fastjson2:fastjson2](https://github.com/alibaba/fastjson2) from 2.0.60 to 2.0.60.android8. - [Release notes](https://github.com/alibaba/fastjson2/releases) - [Commits](https://github.com/alibaba/fastjson2/compare/2.0.60...2.0.60.android8) --- updated-dependencies: - dependency-name: com.alibaba.fastjson2:fastjson2 dependency-version: 2.0.60.android8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 46a1e18c26..35adc07e8f 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 2.20 3.27.6 5.21.0 - 2.0.60 + 2.0.60.android8 1.5.3 5.4 From bef367c6b4afeae626665ba6d03a0920b9057dc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 05:03:37 +0000 Subject: [PATCH 310/615] build(deps): Bump org.junit:junit-bom from 6.0.1 to 6.0.2 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r6.0.1...r6.0.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 6.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 35adc07e8f..b39cf5ef48 100644 --- a/pom.xml +++ b/pom.xml @@ -166,7 +166,7 @@ 20250517 3.5.6 - 6.0.1 + 6.0.2 2.20.1 2.20 3.27.6 From 7ebb3f503f11d4c05f4e2ca7759ba1f234f843c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:37:41 +0000 Subject: [PATCH 311/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.24.0 to 3.25.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.24.0...v3.25.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.25.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b39cf5ef48..e5813a8725 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 0.1.4 6.26.0 3.24.0 - 3.24.0 + 3.25.0 1.0 From 776ce3b7a63af80813a5a95607df974caf980b4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:37:48 +0000 Subject: [PATCH 312/615] build(deps): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.26.0 to 6.27.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.26.0...v6.27.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.27.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b39cf5ef48..0aa9e31cda 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 4.0.0 0.8.14 0.1.4 - 6.26.0 + 6.27.0 3.24.0 3.24.0 1.0 From 89e9b59b91dd48d77edef25f6d2d78d12c7a8c65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:48:55 +0000 Subject: [PATCH 313/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.24.0 to 3.25.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.24.0...v3.25.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.25.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 569cd6e8c4..5c85349079 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 0.8.14 0.1.4 6.27.0 - 3.24.0 + 3.25.0 3.25.0 1.0 From fc1c3a2d730137b80f080bc416312657fc2133ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 05:35:11 +0000 Subject: [PATCH 314/615] build(deps): Bump org.sonatype.central:central-publishing-maven-plugin Bumps [org.sonatype.central:central-publishing-maven-plugin](https://github.com/sonatype/central-publishing-maven-plugin) from 0.9.0 to 0.10.0. - [Commits](https://github.com/sonatype/central-publishing-maven-plugin/commits) --- updated-dependencies: - dependency-name: org.sonatype.central:central-publishing-maven-plugin dependency-version: 0.10.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5c85349079..1fe5755406 100644 --- a/pom.xml +++ b/pom.xml @@ -184,7 +184,7 @@ 3.3.1 6.0.0 0.1.1 - 0.9.0 + 0.10.0 3.5.4 0.230.2 file://${project.basedir}/src/config/bom.xml From ecb2a807ac687dfb153ee7286175dcc3b4cac5da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 05:32:05 +0000 Subject: [PATCH 315/615] build(deps): Bump reactor.version from 3.8.1 to 3.8.2 Bumps `reactor.version` from 3.8.1 to 3.8.2. Updates `io.projectreactor:reactor-core` from 3.8.1 to 3.8.2 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.1...v3.8.2) Updates `io.projectreactor:reactor-test` from 3.8.1 to 3.8.2 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.1...v3.8.2) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.8.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.8.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index 1cd8fd8d6a..ca2dfc50f5 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.8.1 + 3.8.2 1.0.4 2.2.21 From 257327287c037148fbf2c5cad1bbf4f0792f0a16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 05:30:51 +0000 Subject: [PATCH 316/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.27.0 to 6.27.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.27.0...v6.27.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.27.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1fe5755406..4c1c0dba6a 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 4.0.0 0.8.14 0.1.4 - 6.27.0 + 6.27.1 3.25.0 3.25.0 1.0 From 84b1cee51a63a88b64ffa33d74e35314f7dcf084 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 05:27:51 +0000 Subject: [PATCH 317/615] build(deps-dev): Bump com.gradle:develocity-maven-extension Bumps com.gradle:develocity-maven-extension from 2.3 to 2.3.1. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: 2.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 593b403738..73ea72ebca 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.3 + 2.3.1 com.gradle From 54ebfa3c8cd8be2204e8f5bdae554594ef486be2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 05:28:26 +0000 Subject: [PATCH 318/615] build(deps-dev): Bump org.springframework:spring-context Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 7.0.1 to 7.0.3. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.1...v7.0.3) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 7.0.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4c1c0dba6a..8ba3163239 100644 --- a/pom.xml +++ b/pom.xml @@ -239,7 +239,7 @@ 3.0.2 2025.0.0 4.3.0 - 7.0.1 + 7.0.3 6.2.11 2.3.20.Final 1.18.0 From f220b351bf157ab8235854960f036eaac6660303 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 05:28:48 +0000 Subject: [PATCH 319/615] build(deps-dev): Bump io.undertow:undertow-core Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.20.Final to 2.3.22.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.20.Final...2.3.22.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-version: 2.3.22.Final dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4c1c0dba6a..84015c8888 100644 --- a/pom.xml +++ b/pom.xml @@ -241,7 +241,7 @@ 4.3.0 7.0.1 6.2.11 - 2.3.20.Final + 2.3.22.Final 1.18.0 From c18fd1ac7f5624bebc7893550dce88b1313954bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 05:52:43 +0000 Subject: [PATCH 320/615] build(deps-dev): Bump org.codehaus.mojo:versions-maven-plugin Bumps [org.codehaus.mojo:versions-maven-plugin](https://github.com/mojohaus/versions) from 2.20.1 to 2.21.0. - [Release notes](https://github.com/mojohaus/versions/releases) - [Changelog](https://github.com/mojohaus/versions/blob/master/ReleaseNotes.md) - [Commits](https://github.com/mojohaus/versions/compare/2.20.1...2.21.0) --- updated-dependencies: - dependency-name: org.codehaus.mojo:versions-maven-plugin dependency-version: 2.21.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5af4c9727f..0c24fa11e8 100644 --- a/pom.xml +++ b/pom.xml @@ -189,7 +189,7 @@ 0.230.2 file://${project.basedir}/src/config/bom.xml 2.2.1 - 2.20.1 + 2.21.0 3.2.8 3.1.4 1.2.2 From 365dfa7bbf6566df60ea342e53a7e8de614c3e2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 05:54:03 +0000 Subject: [PATCH 321/615] build(deps): Bump com.fasterxml.jackson.core:jackson-annotations Bumps [com.fasterxml.jackson.core:jackson-annotations](https://github.com/FasterXML/jackson) from 2.20 to 2.21. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-version: '2.21' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5af4c9727f..b2fe516832 100644 --- a/pom.xml +++ b/pom.xml @@ -168,7 +168,7 @@ 6.0.2 2.20.1 - 2.20 + 2.21 3.27.6 5.21.0 2.0.60.android8 From be21a214e37df9158a9e412f93eabfae53985664 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 06:04:45 +0000 Subject: [PATCH 322/615] build(deps): Bump jackson.version from 2.20.1 to 2.21.0 Bumps `jackson.version` from 2.20.1 to 2.21.0. Updates `com.fasterxml.jackson.core:jackson-databind` from 2.20.1 to 2.21.0 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.core:jackson-core` from 2.20.1 to 2.21.0 - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.20.1...jackson-core-2.21.0) Updates `com.fasterxml.jackson.jr:jackson-jr-objects` from 2.20.1 to 2.21.0 - [Commits](https://github.com/FasterXML/jackson-jr/compare/jackson-jr-parent-2.20.1...jackson-jr-parent-2.21.0) Updates `com.fasterxml.jackson.jr:jackson-jr-annotation-support` from 2.20.1 to 2.21.0 - [Commits](https://github.com/FasterXML/jackson-jr/compare/jackson-jr-parent-2.20.1...jackson-jr-parent-2.21.0) Updates `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider` from 2.20.1 to 2.21.0 Updates `com.fasterxml.jackson:jackson-bom` from 2.20.1 to 2.21.0 - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.20.1...jackson-bom-2.21.0) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.21.0 dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-version: 2.21.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.jr:jackson-jr-objects dependency-version: 2.21.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.jr:jackson-jr-annotation-support dependency-version: 2.21.0 dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-version: 2.21.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.21.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 79d358bebf..ea35383341 100644 --- a/pom.xml +++ b/pom.xml @@ -167,7 +167,7 @@ 3.5.6 6.0.2 - 2.20.1 + 2.21.0 2.21 3.27.6 5.21.0 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index d263ec575f..fec0f6a413 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -31,7 +31,7 @@ 11 - 2.20.1 + 2.21.0 From d6781fb5ebde4dd8708c40445f54a99b13b56967 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 05:30:02 +0000 Subject: [PATCH 323/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.25.0 to 3.26.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.25.0...v3.26.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.26.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ea35383341..c5b70f8565 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 0.1.4 6.27.1 3.25.0 - 3.25.0 + 3.26.0 1.0 From afc8ba04fc4c604cf869f76ee529ac39d6e1b4f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 05:30:19 +0000 Subject: [PATCH 324/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.27.1 to 6.28.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.27.1...v6.28.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.28.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ea35383341..ad952026b2 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 4.0.0 0.8.14 0.1.4 - 6.27.1 + 6.28.0 3.25.0 3.25.0 1.0 From 124ff45c4633f69a49a58246187e03860f26a75a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 05:40:15 +0000 Subject: [PATCH 325/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.25.0 to 3.26.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.25.0...v3.26.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.26.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cbaac60961..2f6e28cbfe 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 0.8.14 0.1.4 6.28.0 - 3.25.0 + 3.26.0 3.26.0 1.0 From 66ee45ea0e3cab4d697a699e8ad93c71cc6e2db3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 05:29:23 +0000 Subject: [PATCH 326/615] build(deps): Bump com.google.http-client:google-http-client Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 2.0.3 to 2.1.0. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v2.0.3...v2.1.0) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-version: 2.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2f6e28cbfe..bfe340ea8d 100644 --- a/pom.xml +++ b/pom.xml @@ -159,7 +159,7 @@ 5.3.2 33.5.0-jre - 2.0.3 + 2.1.0 2.13.2 1.15.2 2.0.17 From 12f045132f49e5e9023c9ce4f6ef72bf6f8774ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 05:34:37 +0000 Subject: [PATCH 327/615] build(deps): Bump org.assertj:assertj-core from 3.27.6 to 3.27.7 Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.27.6 to 3.27.7. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.6...assertj-build-3.27.7) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-version: 3.27.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bfe340ea8d..9ba2be6ebc 100644 --- a/pom.xml +++ b/pom.xml @@ -169,7 +169,7 @@ 6.0.2 2.21.0 2.21 - 3.27.6 + 3.27.7 5.21.0 2.0.60.android8 1.5.3 From 1639bc2822b65826cf21dd682b199edc9757b04b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 05:34:59 +0000 Subject: [PATCH 328/615] build(deps): Bump io.dropwizard.metrics5:metrics-core Bumps [io.dropwizard.metrics5:metrics-core](https://github.com/dropwizard/metrics) from 5.0.5 to 5.0.6. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v5.0.5...v5.0.6) --- updated-dependencies: - dependency-name: io.dropwizard.metrics5:metrics-core dependency-version: 5.0.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bfe340ea8d..5e0e8ffb38 100644 --- a/pom.xml +++ b/pom.xml @@ -232,7 +232,7 @@ 1.18.42 3.6.1 4.2.37 - 5.0.5 + 5.0.6 0.2.0 2.1.1 1.5.3 From 6dee44328cb9234d1782e1177abe8e3d0c19da0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 05:35:12 +0000 Subject: [PATCH 329/615] build(deps-dev): Bump com.gradle:develocity-maven-extension Bumps com.gradle:develocity-maven-extension from 2.3.1 to 2.3.2. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: 2.3.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 73ea72ebca..dd6265892c 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.3.1 + 2.3.2 com.gradle From b930d7a164d2bbe5fd59673e3e3e49cd1f2490d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 05:45:12 +0000 Subject: [PATCH 330/615] build(deps): Bump io.dropwizard.metrics:metrics-core Bumps [io.dropwizard.metrics:metrics-core](https://github.com/dropwizard/metrics) from 4.2.37 to 4.2.38. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.37...v4.2.38) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-version: 4.2.38 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 237eb968b4..125219914e 100644 --- a/pom.xml +++ b/pom.xml @@ -231,7 +231,7 @@ 1.1.1 1.18.42 3.6.1 - 4.2.37 + 4.2.38 5.0.6 0.2.0 2.1.1 From 18c9d142a5520111c6efcfe0a78015ce5c6f6528 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Jan 2026 05:26:46 +0000 Subject: [PATCH 331/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.28.0 to 6.28.1. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.28.0...v6.28.1) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.28.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 125219914e..a48c6e1dff 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 4.0.0 0.8.14 0.1.4 - 6.28.0 + 6.28.1 3.26.0 3.26.0 1.0 From ad0d1e24e2f93a87ce18b2901e61dcdc1eeb91da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 05:26:44 +0000 Subject: [PATCH 332/615] build(deps-dev): Bump com.gradle:develocity-maven-extension Bumps com.gradle:develocity-maven-extension from 2.3.2 to 2.3.3. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: 2.3.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index dd6265892c..94c59b51ea 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.3.2 + 2.3.3 com.gradle From d7ebd3164f0706311857f5a925e380b458a70cfc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 05:26:21 +0000 Subject: [PATCH 333/615] build(deps): Bump commons-codec:commons-codec from 1.20.0 to 1.21.0 Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.20.0 to 1.21.0. - [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.20.0...rel/commons-codec-1.21.0) --- updated-dependencies: - dependency-name: commons-codec:commons-codec dependency-version: 1.21.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a48c6e1dff..bcfdbe4d00 100644 --- a/pom.xml +++ b/pom.xml @@ -208,7 +208,7 @@ 0.7.12 1.1.1 - 1.20.0 + 1.21.0 1.6.0 1.6.0 1.15.0 From 7e10ab52e72baefcca1c75791880d3540b3142e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 05:26:29 +0000 Subject: [PATCH 334/615] build(deps): Bump org.springframework.cloud:spring-cloud-dependencies Bumps [org.springframework.cloud:spring-cloud-dependencies](https://github.com/spring-cloud/spring-cloud-release) from 2025.0.0 to 2025.1.1. - [Release notes](https://github.com/spring-cloud/spring-cloud-release/releases) - [Commits](https://github.com/spring-cloud/spring-cloud-release/compare/v2025.0.0...v2025.1.1) --- updated-dependencies: - dependency-name: org.springframework.cloud:spring-cloud-dependencies dependency-version: 2025.1.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a48c6e1dff..d9d28e0efc 100644 --- a/pom.xml +++ b/pom.xml @@ -237,7 +237,7 @@ 2.1.1 1.5.3 3.0.2 - 2025.0.0 + 2025.1.1 4.3.0 7.0.3 6.2.11 From 1e05afa812cddbb93422b4984851261203a22436 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Feb 2026 05:34:38 +0000 Subject: [PATCH 335/615] build(deps): Bump org.apache.maven.plugins:maven-compiler-plugin Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.14.1 to 3.15.0. - [Release notes](https://github.com/apache/maven-compiler-plugin/releases) - [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.14.1...maven-compiler-plugin-3.15.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-compiler-plugin dependency-version: 3.15.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d2bfb0ef80..d0c8e2a1a6 100644 --- a/pom.xml +++ b/pom.xml @@ -175,7 +175,7 @@ 1.5.3 5.4 - 3.14.1 + 3.15.0 3.1.4 3.3.1 3.12.0 From 459b6ab45624a8f85eeb5e9a2e9afc1c20082921 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 05:27:07 +0000 Subject: [PATCH 336/615] build(deps): Bump netty.version from 4.2.9.Final to 4.2.10.Final Bumps `netty.version` from 4.2.9.Final to 4.2.10.Final. Updates `io.netty:netty-bom` from 4.2.9.Final to 4.2.10.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.9.Final...netty-4.2.10.Final) Updates `io.netty:netty-handler` from 4.2.9.Final to 4.2.10.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.9.Final...netty-4.2.10.Final) Updates `io.netty:netty-codec-http` from 4.2.9.Final to 4.2.10.Final - [Commits](https://github.com/netty/netty/compare/netty-4.2.9.Final...netty-4.2.10.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.10.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.10.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.10.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 30a8494d8e..bffc654e47 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.9.Final + 4.2.10.Final true From 7ad0c5aee5f8947b84a4a8896b40be4142c4ebe5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 05:34:57 +0000 Subject: [PATCH 337/615] build(deps): Bump kotlin.version from 2.3.0 to 2.3.10 Bumps `kotlin.version` from 2.3.0 to 2.3.10. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.3.0 to 2.3.10 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.3.0...v2.3.10) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.3.0 to 2.3.10 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.3.0...v2.3.10) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.3.0 to 2.3.10 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-version: 2.3.10 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-version: 2.3.10 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-version: 2.3.10 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 73704564df..fb4caedf30 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.3.0 + 2.3.10 1.10.2 From bda012004016d695d4047293cf47a91070d63222 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 05:36:00 +0000 Subject: [PATCH 338/615] build(deps-dev): Bump io.undertow:undertow-core Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.22.Final to 2.3.23.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.22.Final...2.3.23.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-version: 2.3.23.Final dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d0c8e2a1a6..b85b9f4032 100644 --- a/pom.xml +++ b/pom.xml @@ -241,7 +241,7 @@ 4.3.0 7.0.3 6.2.11 - 2.3.22.Final + 2.3.23.Final 1.18.0 From 38a6e82b874440a26009523e499d83e9ad279c56 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 6 Feb 2026 08:53:02 -0300 Subject: [PATCH 339/615] Ignore major version bumps for dependencies locked across modules Signed-off-by: Marvin Froeder --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8bccb05c25..940e432644 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,3 +10,15 @@ updates: schedule: interval: "daily" open-pull-requests-limit: 100 + ignore: + # Jersey exists at different majors: 2.x (jaxrs2), 3.x (jaxrs3), 4.x (jaxrs4) + - dependency-name: "org.glassfish.jersey.core:jersey-client" + update-types: ["version-update:semver-major"] + - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" + update-types: ["version-update:semver-major"] + # JAXB impl at 2.x (jaxb, soap) and 4.x (jaxb-jakarta, soap-jakarta) + - dependency-name: "com.sun.xml.bind:jaxb-impl" + update-types: ["version-update:semver-major"] + # SAAJ impl at 1.x (soap) and 3.x (soap-jakarta) + - dependency-name: "com.sun.xml.messaging.saaj:saaj-impl" + update-types: ["version-update:semver-major"] From 017669ba7235a24a1280aa9e60012be065d01f29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 11:55:23 +0000 Subject: [PATCH 340/615] build(deps): Bump jakarta.xml.bind:jakarta.xml.bind-api Bumps [jakarta.xml.bind:jakarta.xml.bind-api](https://github.com/jakartaee/jaxb-api) from 4.0.4 to 4.0.5. - [Release notes](https://github.com/jakartaee/jaxb-api/releases) - [Commits](https://github.com/jakartaee/jaxb-api/compare/4.0.4...4.0.5) --- updated-dependencies: - dependency-name: jakarta.xml.bind:jakarta.xml.bind-api dependency-version: 4.0.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b85b9f4032..9df6ff2076 100644 --- a/pom.xml +++ b/pom.xml @@ -219,7 +219,7 @@ 1.5.18 3.1.0 4.0.0 - 4.0.4 + 4.0.5 3.0.2 4.0.2 2.1.1 From 98434e342eb1447f7e377a6a1f2123712559322b Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 6 Feb 2026 09:04:47 -0300 Subject: [PATCH 341/615] Split jersey dependabot updates into per-module entries Signed-off-by: Marvin Froeder --- .github/dependabot.yml | 47 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 940e432644..27c258983f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,14 +11,55 @@ updates: interval: "daily" open-pull-requests-limit: 100 ignore: - # Jersey exists at different majors: 2.x (jaxrs2), 3.x (jaxrs3), 4.x (jaxrs4) + # Jersey uses the same property name (jersey.version) in jaxrs2/3/4 at different majors. + # Per-module entries below handle jersey updates independently. - dependency-name: "org.glassfish.jersey.core:jersey-client" - update-types: ["version-update:semver-major"] - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" - update-types: ["version-update:semver-major"] # JAXB impl at 2.x (jaxb, soap) and 4.x (jaxb-jakarta, soap-jakarta) - dependency-name: "com.sun.xml.bind:jaxb-impl" update-types: ["version-update:semver-major"] # SAAJ impl at 1.x (soap) and 3.x (soap-jakarta) - dependency-name: "com.sun.xml.messaging.saaj:saaj-impl" update-types: ["version-update:semver-major"] + + # Jersey 2.x for jaxrs2 + - package-ecosystem: "maven" + directory: "/jaxrs2" + schedule: + interval: "daily" + allow: + - dependency-name: "org.glassfish.jersey.core:jersey-client" + - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" + ignore: + - dependency-name: "org.glassfish.jersey.core:jersey-client" + update-types: ["version-update:semver-major"] + - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" + update-types: ["version-update:semver-major"] + + # Jersey 3.x for jaxrs3 + - package-ecosystem: "maven" + directory: "/jaxrs3" + schedule: + interval: "daily" + allow: + - dependency-name: "org.glassfish.jersey.core:jersey-client" + - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" + ignore: + - dependency-name: "org.glassfish.jersey.core:jersey-client" + update-types: ["version-update:semver-major"] + - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" + update-types: ["version-update:semver-major"] + + # Jersey 4.x for jaxrs4 + - package-ecosystem: "maven" + directory: "/jaxrs4" + schedule: + interval: "daily" + allow: + - dependency-name: "org.glassfish.jersey.core:jersey-client" + - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" + ignore: + - dependency-name: "org.glassfish.jersey.core:jersey-client" + update-types: ["version-update:semver-major"] + - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" + update-types: ["version-update:semver-major"] From 5a1fe21ed06723defad76cf2713561a5884e5a67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:05:52 +0000 Subject: [PATCH 342/615] build(deps-dev): Bump jersey.version from 3.1.10 to 3.1.11 in /jaxrs3 Bumps `jersey.version` from 3.1.10 to 3.1.11. Updates `org.glassfish.jersey.core:jersey-client` from 3.1.10 to 3.1.11 Updates `org.glassfish.jersey.inject:jersey-hk2` from 3.1.10 to 3.1.11 --- updated-dependencies: - dependency-name: org.glassfish.jersey.core:jersey-client dependency-version: 3.1.11 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: org.glassfish.jersey.inject:jersey-hk2 dependency-version: 3.1.11 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- jaxrs3/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index f9c9df26b1..57638ee98b 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -31,7 +31,7 @@ 11 - 3.1.10 + 3.1.11 From ffdfed9900a4370984723ab27fcbdfe51fc8ad60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:05:52 +0000 Subject: [PATCH 343/615] build(deps-dev): Bump jersey.version from 4.0.0-M1 to 4.0.2 in /jaxrs4 Bumps `jersey.version` from 4.0.0-M1 to 4.0.2. Updates `org.glassfish.jersey.core:jersey-client` from 4.0.0-M1 to 4.0.2 Updates `org.glassfish.jersey.inject:jersey-hk2` from 4.0.0-M1 to 4.0.2 --- updated-dependencies: - dependency-name: org.glassfish.jersey.core:jersey-client dependency-version: 4.0.2 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: org.glassfish.jersey.inject:jersey-hk2 dependency-version: 4.0.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- jaxrs4/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 1c86480192..a21e93e356 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -31,7 +31,7 @@ 17 - 4.0.0-M1 + 4.0.2 From 5a023da7d2c122a9b4eb1c10a85e62bfec65e4c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:05:54 +0000 Subject: [PATCH 344/615] build(deps-dev): Bump jersey.version from 2.46 to 2.47 in /jaxrs2 Bumps `jersey.version` from 2.46 to 2.47. Updates `org.glassfish.jersey.core:jersey-client` from 2.46 to 2.47 Updates `org.glassfish.jersey.inject:jersey-hk2` from 2.46 to 2.47 --- updated-dependencies: - dependency-name: org.glassfish.jersey.core:jersey-client dependency-version: '2.47' dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: org.glassfish.jersey.inject:jersey-hk2 dependency-version: '2.47' dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- jaxrs2/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index ad4022f34c..835071b883 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -31,7 +31,7 @@ true - 2.46 + 2.47 From bc3d2f91046bf7fa8a72be0a7594c16fc1b9791a Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 6 Feb 2026 09:11:23 -0300 Subject: [PATCH 345/615] Add per-module dependabot entries for vertx and document the approach Signed-off-by: Marvin Froeder --- .github/dependabot.yml | 36 ++++++++++++++++++++++++++++++++++++ CLAUDE.md | 18 ++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 27c258983f..fa14f951f4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,6 +15,9 @@ updates: # Per-module entries below handle jersey updates independently. - dependency-name: "org.glassfish.jersey.core:jersey-client" - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" + # Vertx uses the same property name (vertx.version) at 4.x and 5.x. + # Per-module entries below handle vertx updates independently. + - dependency-name: "io.vertx:*" # JAXB impl at 2.x (jaxb, soap) and 4.x (jaxb-jakarta, soap-jakarta) - dependency-name: "com.sun.xml.bind:jaxb-impl" update-types: ["version-update:semver-major"] @@ -63,3 +66,36 @@ updates: update-types: ["version-update:semver-major"] - dependency-name: "org.glassfish.jersey.inject:jersey-hk2" update-types: ["version-update:semver-major"] + + # Vertx 5.x for feign-vertx (main library) + - package-ecosystem: "maven" + directory: "/vertx/feign-vertx" + schedule: + interval: "daily" + allow: + - dependency-name: "io.vertx:*" + ignore: + - dependency-name: "io.vertx:*" + update-types: ["version-update:semver-major"] + + # Vertx 4.x for feign-vertx4-test + - package-ecosystem: "maven" + directory: "/vertx/feign-vertx4-test" + schedule: + interval: "daily" + allow: + - dependency-name: "io.vertx:*" + ignore: + - dependency-name: "io.vertx:*" + update-types: ["version-update:semver-major"] + + # Vertx 5.x for feign-vertx5-test + - package-ecosystem: "maven" + directory: "/vertx/feign-vertx5-test" + schedule: + interval: "daily" + allow: + - dependency-name: "io.vertx:*" + ignore: + - dependency-name: "io.vertx:*" + update-types: ["version-update:semver-major"] diff --git a/CLAUDE.md b/CLAUDE.md index 4002f616a4..33b037e165 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -104,3 +104,21 @@ Example: - `dropwizard-metrics5/` - Java 17 (for Metrics 5.x) - `apt-test-generator/` - Java 17 (for Handlebars 4.5.0+) - `soap-jakarta/`, `jaxb-jakarta/` - Java 11 (for Jakarta namespace) + +### Dependabot Configuration + +Some modules define the same Maven property name (e.g., `jersey.version`, `vertx.version`) at different major versions. Dependabot treats these as a single property across the reactor and tries to set them all to the same value, which breaks modules locked to a specific major. + +**Current split-property modules:** +- `jersey.version`: 2.x (jaxrs2), 3.x (jaxrs3), 4.x (jaxrs4) +- `vertx.version`: 4.x (feign-vertx4-test), 5.x (feign-vertx, feign-vertx5-test) + +**How it works in `.github/dependabot.yml`:** +1. The root `/` entry **ignores** the conflicting dependencies entirely (jersey, vertx) +2. Each module gets its own entry with `allow` (only the conflicting dependency) and `ignore` (block major version bumps) +3. Other dependencies that use **different property names** per major (e.g., `jaxb-impl-2.version` vs `jaxb-impl-4.version`) only need `update-types: ["version-update:semver-major"]` on the root entry + +**When adding a new module that reuses a version property at a different major:** +1. Add the dependency to the root entry's `ignore` list (fully ignored, not just major) +2. Add a per-directory entry for the new module with `allow` for the specific dependency and `ignore` for `version-update:semver-major` +3. Verify existing modules with the same property also have their own per-directory entries From 5ce830493b0c81892d7b512dc047a6a10c63776f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:12:18 +0000 Subject: [PATCH 346/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx4-test Bumps `vertx.version` from 4.5.14 to 4.5.24. Updates `io.vertx:vertx-junit5` from 4.5.14 to 4.5.24 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.14...4.5.24) Updates `io.vertx:vertx-web-client` from 4.5.14 to 4.5.24 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.14...4.5.24) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 4.5.24 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 4.5.24 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx4-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 5254468fb4..a759b785c3 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 4.x. - 4.5.14 + 4.5.24 From df3dfebc8b9f38824c04a6bb7d95f7308f142e06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 12:12:27 +0000 Subject: [PATCH 347/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx5-test Bumps `vertx.version` from 5.0.4 to 5.0.7. Updates `io.vertx:vertx-junit5` from 5.0.4 to 5.0.7 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/5.0.4...5.0.7) Updates `io.vertx:vertx-web-client` from 5.0.4 to 5.0.7 - [Commits](https://github.com/vert-x3/vertx-web/compare/5.0.4...5.0.7) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 5.0.7 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 5.0.7 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx5-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index d330c3ad9e..8b4387b051 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.0.4 + 5.0.7 From 5e1345e85b6ea21e2fd40c9e5971a73622a7af88 Mon Sep 17 00:00:00 2001 From: fbus Date: Fri, 6 Feb 2026 13:40:00 +0100 Subject: [PATCH 348/615] feat(codec): Add Jackson 3 support module (feign-jackson3) (#3162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(codec): Add Jackson 3 support module (feign-jackson3) This commit introduces a new module `feign-jackson3` that provides support for Jackson 3.x, alongside the existing `feign-jackson` module which continues to support Jackson 2.x. ## Changes ### Module Creation - Created new `jackson3` module based on `feign-jackson` - Added module to parent POM ### Jackson 3 Migration - **Dependency**: Upgraded to Jackson 3.0.2 (`tools.jackson.core:jackson-databind`) - **Package changes**: Migrated from `com.fasterxml.jackson.*` to `tools.jackson.*` - Exception: `com.fasterxml.jackson.annotation` remains unchanged (as per Jackson 3 spec) - **Maven coordinates**: Updated groupId from `com.fasterxml.jackson.core` to `tools.jackson.core` ### API Changes - **Immutable ObjectMapper**: Replaced direct `ObjectMapper` instantiation with `JsonMapper.builder()` - All configuration now done via builder pattern - **Exception handling**: - Jackson 3 uses `JacksonException` (unchecked) instead of `IOException` (checked) - Updated catch blocks to handle `JacksonException` and extract `IOException` from cause when needed - **Module type**: Changed from `Module` to `JacksonModule` ### Configuration - **Default settings**: Respects Jackson 3 defaults (improved security) - `FAIL_ON_TRAILING_TOKENS` enabled by default (new in Jackson 3) - Explicitly disabled for `Jackson3IteratorDecoder` only (required for streaming array elements) - **Java version**: Minimum Java 17 required (Jackson 3 baseline) ### Classes - `Jackson3Decoder`: Standard JSON decoder for Jackson 3 - `Jackson3Encoder`: Standard JSON encoder for Jackson 3 - `Jackson3IteratorDecoder`: Streaming iterator decoder for large JSON arrays ### Tests - Migrated all tests from `feign-jackson` - Updated to use Jackson 3 APIs (`tools.jackson.*` packages) - Updated method names for Jackson 3 API changes (e.g., `getCurrentName()` → `currentName()`) - All tests passing ✅ ## Migration Notes Users can migrate from `feign-jackson` to `feign-jackson3` by: 1. Updating dependency to `feign-jackson3` 2. Changing imports from `feign.jackson.*` to `feign.jackson3.*` 3. Ensuring Java 17+ is available Both modules can coexist in the same project if needed. ## References - [Jackson 3 Migration Guide](https://github.com/FasterXML/jackson/blob/main/jackson3/MIGRATING_TO_JACKSON_3.md) - [Jackson 3.0 Release Notes](https://github.com/FasterXML/jackson/wiki/Jackson-Release-3.0) * Use Jackson BOMs for dependency management in jackson and jackson3 modules Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder Co-authored-by: Fabien BUSSIRON Co-authored-by: Marvin Froeder --- jackson3/README.md | 39 ++ jackson3/pom.xml | 66 +++ .../java/feign/jackson3/Jackson3Decoder.java | 74 ++++ .../java/feign/jackson3/Jackson3Encoder.java | 62 +++ .../jackson3/Jackson3IteratorDecoder.java | 199 +++++++++ .../feign/jackson3/Jackson3CodecTest.java | 388 ++++++++++++++++++ .../jackson3/examples/GitHubExample.java | 59 +++ .../examples/GitHubIteratorExample.java | 67 +++ pom.xml | 33 +- 9 files changed, 960 insertions(+), 27 deletions(-) create mode 100644 jackson3/README.md create mode 100644 jackson3/pom.xml create mode 100644 jackson3/src/main/java/feign/jackson3/Jackson3Decoder.java create mode 100644 jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java create mode 100644 jackson3/src/main/java/feign/jackson3/Jackson3IteratorDecoder.java create mode 100644 jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java create mode 100644 jackson3/src/test/java/feign/jackson3/examples/GitHubExample.java create mode 100644 jackson3/src/test/java/feign/jackson3/examples/GitHubIteratorExample.java diff --git a/jackson3/README.md b/jackson3/README.md new file mode 100644 index 0000000000..0a1107020b --- /dev/null +++ b/jackson3/README.md @@ -0,0 +1,39 @@ +Jackson 3 Codec +=================== + +This module adds support for encoding and decoding JSON via Jackson 3. + +**Note:** Jackson 3 requires Java 17 or higher. + +Add `Jackson3Encoder` and/or `Jackson3Decoder` to your `Feign.Builder` like so: + +```java +GitHub github = Feign.builder() + .encoder(new Jackson3Encoder()) + .decoder(new Jackson3Decoder()) + .target(GitHub.class, "https://api.github.com"); +``` + +If you want to customize the `JsonMapper` that is used, provide it to the `Jackson3Encoder` and `Jackson3Decoder`: + +```java +JsonMapper mapper = JsonMapper.builder() + .changeDefaultPropertyInclusion(incl -> incl.withValueInclusion(JsonInclude.Include.NON_NULL)) + .enable(SerializationFeature.INDENT_OUTPUT) + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .build(); + +GitHub github = Feign.builder() + .encoder(new Jackson3Encoder(mapper)) + .decoder(new Jackson3Decoder(mapper)) + .target(GitHub.class, "https://api.github.com"); +``` + +## Migration from Jackson 2 to Jackson 3 + +The main differences are: + +- Package changes: `com.fasterxml.jackson` → `tools.jackson` (except for `com.fasterxml.jackson.annotation`) +- GroupId changes: `com.fasterxml.jackson.core` → `tools.jackson.core` +- `ObjectMapper` is immutable and must be configured via `JsonMapper.builder()` +- Java 17 minimum requirement diff --git a/jackson3/pom.xml b/jackson3/pom.xml new file mode 100644 index 0000000000..de7e9225cd --- /dev/null +++ b/jackson3/pom.xml @@ -0,0 +1,66 @@ + + + + 4.0.0 + + + io.github.openfeign + feign-parent + 13.7-SNAPSHOT + + + feign-jackson3 + Feign Jackson 3 + Feign Jackson 3 + + + 17 + + + + + + tools.jackson + jackson-bom + ${jackson3.version} + pom + import + + + + + + + ${project.groupId} + feign-core + + + + tools.jackson.core + jackson-databind + + + + ${project.groupId} + feign-core + test-jar + test + + + diff --git a/jackson3/src/main/java/feign/jackson3/Jackson3Decoder.java b/jackson3/src/main/java/feign/jackson3/Jackson3Decoder.java new file mode 100644 index 0000000000..723f0b146f --- /dev/null +++ b/jackson3/src/main/java/feign/jackson3/Jackson3Decoder.java @@ -0,0 +1,74 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.jackson3; + +import feign.Response; +import feign.Util; +import feign.codec.Decoder; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.lang.reflect.Type; +import java.util.Collections; +import tools.jackson.core.JacksonException; +import tools.jackson.databind.DeserializationFeature; +import tools.jackson.databind.JacksonModule; +import tools.jackson.databind.json.JsonMapper; + +public class Jackson3Decoder implements Decoder { + + private final JsonMapper mapper; + + public Jackson3Decoder() { + this(Collections.emptyList()); + } + + public Jackson3Decoder(Iterable modules) { + this( + JsonMapper.builder() + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .addModules(modules) + .build()); + } + + public Jackson3Decoder(JsonMapper mapper) { + this.mapper = mapper; + } + + @Override + public Object decode(Response response, Type type) throws IOException { + if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type); + if (response.body() == null) return null; + Reader reader = response.body().asReader(response.charset()); + if (!reader.markSupported()) { + reader = new BufferedReader(reader, 1); + } + try { + // Read the first byte to see if we have any data + reader.mark(1); + if (reader.read() == -1) { + return null; // Eagerly returning null avoids "No content to map due to end-of-input" + } + reader.reset(); + return mapper.readValue(reader, mapper.constructType(type)); + } catch (JacksonException e) { + if (e.getCause() != null && e.getCause() instanceof IOException) { + throw IOException.class.cast(e.getCause()); + } + throw e; + } + } +} diff --git a/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java b/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java new file mode 100644 index 0000000000..d6455000a0 --- /dev/null +++ b/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java @@ -0,0 +1,62 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.jackson3; + +import com.fasterxml.jackson.annotation.JsonInclude; +import feign.RequestTemplate; +import feign.Util; +import feign.codec.EncodeException; +import feign.codec.Encoder; +import java.lang.reflect.Type; +import java.util.Collections; +import tools.jackson.core.JacksonException; +import tools.jackson.databind.JacksonModule; +import tools.jackson.databind.JavaType; +import tools.jackson.databind.SerializationFeature; +import tools.jackson.databind.json.JsonMapper; + +public class Jackson3Encoder implements Encoder { + + private final JsonMapper mapper; + + public Jackson3Encoder() { + this(Collections.emptyList()); + } + + public Jackson3Encoder(Iterable modules) { + this( + JsonMapper.builder() + .changeDefaultPropertyInclusion( + incl -> incl.withValueInclusion(JsonInclude.Include.NON_NULL)) + .enable(SerializationFeature.INDENT_OUTPUT) + .addModules(modules) + .build()); + } + + public Jackson3Encoder(JsonMapper mapper) { + this.mapper = mapper; + } + + @Override + public void encode(Object object, Type bodyType, RequestTemplate template) { + try { + JavaType javaType = mapper.getTypeFactory().constructType(bodyType); + template.body(mapper.writerFor(javaType).writeValueAsBytes(object), Util.UTF_8); + } catch (JacksonException e) { + throw new EncodeException(e.getMessage(), e); + } + } +} diff --git a/jackson3/src/main/java/feign/jackson3/Jackson3IteratorDecoder.java b/jackson3/src/main/java/feign/jackson3/Jackson3IteratorDecoder.java new file mode 100644 index 0000000000..9ba52fa593 --- /dev/null +++ b/jackson3/src/main/java/feign/jackson3/Jackson3IteratorDecoder.java @@ -0,0 +1,199 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.jackson3; + +import static feign.Util.UTF_8; +import static feign.Util.ensureClosed; + +import feign.Response; +import feign.Util; +import feign.codec.DecodeException; +import feign.codec.Decoder; +import java.io.BufferedReader; +import java.io.Closeable; +import java.io.IOException; +import java.io.Reader; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.Iterator; +import java.util.NoSuchElementException; +import tools.jackson.core.JacksonException; +import tools.jackson.core.JsonParser; +import tools.jackson.core.JsonToken; +import tools.jackson.databind.DeserializationFeature; +import tools.jackson.databind.JacksonModule; +import tools.jackson.databind.ObjectReader; +import tools.jackson.databind.json.JsonMapper; + +/** + * Jackson 3 decoder which return a closeable iterator. Returned iterator auto-close the {@code + * Response} when it reached json array end or failed to parse stream. If this iterator is not + * fetched till the end, it has to be casted to {@code Closeable} and explicity {@code + * Closeable#close} by the consumer. + * + *

+ * + *

+ * + *

Example:
+ * + *

+ * 
+ * Feign.builder()
+ *   .decoder(Jackson3IteratorDecoder.create())
+ *   .doNotCloseAfterDecode() // Required to fetch the iterator after the response is processed, need to be close
+ *   .target(GitHub.class, "https://api.github.com");
+ * interface GitHub {
+ *  {@literal @}RequestLine("GET /repos/{owner}/{repo}/contributors")
+ *   Iterator contributors(@Param("owner") String owner, @Param("repo") String repo);
+ * }
+ * 
+ */ +public final class Jackson3IteratorDecoder implements Decoder { + + private final JsonMapper mapper; + + Jackson3IteratorDecoder(JsonMapper mapper) { + this.mapper = mapper; + } + + @Override + public Object decode(Response response, Type type) throws IOException { + if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type); + if (response.body() == null) return null; + Reader reader = response.body().asReader(UTF_8); + if (!reader.markSupported()) { + reader = new BufferedReader(reader, 1); + } + try { + // Read the first byte to see if we have any data + reader.mark(1); + if (reader.read() == -1) { + return null; // Eagerly returning null avoids "No content to map due to end-of-input" + } + reader.reset(); + return new Jackson3Iterator( + actualIteratorTypeArgument(type), mapper, response, reader); + } catch (JacksonException e) { + if (e.getCause() != null && e.getCause() instanceof IOException) { + throw IOException.class.cast(e.getCause()); + } + throw e; + } + } + + private static Type actualIteratorTypeArgument(Type type) { + if (!(type instanceof ParameterizedType)) { + throw new IllegalArgumentException("Not supported type " + type.toString()); + } + ParameterizedType parameterizedType = (ParameterizedType) type; + if (!Iterator.class.equals(parameterizedType.getRawType())) { + throw new IllegalArgumentException( + "Not an iterator type " + parameterizedType.getRawType().toString()); + } + return ((ParameterizedType) type).getActualTypeArguments()[0]; + } + + public static Jackson3IteratorDecoder create() { + return create(Collections.emptyList()); + } + + public static Jackson3IteratorDecoder create(Iterable modules) { + return new Jackson3IteratorDecoder( + JsonMapper.builder() + .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + // Disable FAIL_ON_TRAILING_TOKENS for iterator: we read a JSON array element by + // element, so there are always "trailing tokens" (the remaining array elements) + .disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS) + .addModules(modules) + .build()); + } + + public static Jackson3IteratorDecoder create(JsonMapper jsonMapper) { + return new Jackson3IteratorDecoder(jsonMapper); + } + + static final class Jackson3Iterator implements Iterator, Closeable { + private final Response response; + private final JsonParser parser; + private final ObjectReader objectReader; + + private T current; + + Jackson3Iterator(Type type, JsonMapper mapper, Response response, Reader reader) + throws IOException { + this.response = response; + this.parser = mapper.createParser(reader); + this.objectReader = mapper.reader().forType(mapper.constructType(type)); + } + + @Override + public boolean hasNext() { + if (current == null) { + current = readNext(); + } + return current != null; + } + + private T readNext() { + try { + JsonToken jsonToken = parser.nextToken(); + if (jsonToken == null) { + return null; + } + + if (jsonToken == JsonToken.START_ARRAY) { + jsonToken = parser.nextToken(); + } + + if (jsonToken == JsonToken.END_ARRAY) { + ensureClosed(this); + return null; + } + + return objectReader.readValue(parser); + } catch (JacksonException e) { + // Input Stream closed automatically by parser + throw new DecodeException(response.status(), e.getMessage(), response.request(), e); + } + } + + @Override + public T next() { + if (current != null) { + T tmp = current; + current = null; + return tmp; + } + T next = readNext(); + if (next == null) { + throw new NoSuchElementException(); + } + return next; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + @Override + public void close() throws IOException { + ensureClosed(this.response); + } + } +} diff --git a/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java b/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java new file mode 100644 index 0000000000..d91683033c --- /dev/null +++ b/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java @@ -0,0 +1,388 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.jackson3; + +import static feign.Util.UTF_8; +import static feign.assertj.FeignAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; + +import feign.Request; +import feign.Request.HttpMethod; +import feign.RequestTemplate; +import feign.Response; +import feign.Util; +import java.io.Closeable; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; +import tools.jackson.core.JacksonException; +import tools.jackson.core.JsonGenerator; +import tools.jackson.core.JsonParser; +import tools.jackson.core.JsonToken; +import tools.jackson.core.type.TypeReference; +import tools.jackson.databind.DeserializationContext; +import tools.jackson.databind.SerializationContext; +import tools.jackson.databind.deser.std.StdDeserializer; +import tools.jackson.databind.module.SimpleModule; +import tools.jackson.databind.ser.std.StdSerializer; + +@SuppressWarnings("deprecation") +class Jackson3CodecTest { + + private String zonesJson = + "" // + + "[" + + System.lineSeparator() // + + " {" + + System.lineSeparator() // + + " \"name\": \"denominator.io.\"" + + System.lineSeparator() // + + " }," + + System.lineSeparator() // + + " {" + + System.lineSeparator() // + + " \"name\": \"denominator.io.\"," + + System.lineSeparator() // + + " \"id\": \"ABCD\"" + + System.lineSeparator() // + + " }" + + System.lineSeparator() // + + "]" + + System.lineSeparator(); + + @Test + void encodesMapObjectNumericalValuesAsInteger() { + Map map = new LinkedHashMap<>(); + map.put("foo", 1); + + RequestTemplate template = new RequestTemplate(); + new Jackson3Encoder().encode(map, map.getClass(), template); + + assertThat(template) + .hasBody( + "" // + + "{" + + System.lineSeparator() // + + " \"foo\" : 1" + + System.lineSeparator() // + + "}"); + } + + @Test + void encodesFormParams() { + Map form = new LinkedHashMap<>(); + form.put("foo", 1); + form.put("bar", Arrays.asList(2, 3)); + + RequestTemplate template = new RequestTemplate(); + new Jackson3Encoder().encode(form, new TypeReference>() {}.getType(), template); + + assertThat(template) + .hasBody( + "" // + + "{" + + System.lineSeparator() // + + " \"foo\" : 1," + + System.lineSeparator() // + + " \"bar\" : [ 2, 3 ]" + + System.lineSeparator() // + + "}"); + } + + @Test + void decodes() throws Exception { + List zones = new LinkedList<>(); + zones.add(new Zone("denominator.io.")); + zones.add(new Zone("denominator.io.", "ABCD")); + + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.emptyMap()) + .body(zonesJson, UTF_8) + .build(); + assertThat(new Jackson3Decoder().decode(response, new TypeReference>() {}.getType())) + .isEqualTo(zones); + } + + @Test + void nullBodyDecodesToNull() throws Exception { + Response response = + Response.builder() + .status(204) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.emptyMap()) + .build(); + assertThat(new Jackson3Decoder().decode(response, String.class)).isNull(); + } + + @Test + void emptyBodyDecodesToNull() throws Exception { + Response response = + Response.builder() + .status(204) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.emptyMap()) + .body(new byte[0]) + .build(); + assertThat(new Jackson3Decoder().decode(response, String.class)).isNull(); + } + + @Test + void customDecoder() throws Exception { + Jackson3Decoder decoder = + new Jackson3Decoder( + Arrays.asList(new SimpleModule().addDeserializer(Zone.class, new ZoneDeserializer()))); + + List zones = new LinkedList<>(); + zones.add(new Zone("DENOMINATOR.IO.")); + zones.add(new Zone("DENOMINATOR.IO.", "ABCD")); + + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.emptyMap()) + .body(zonesJson, UTF_8) + .build(); + assertThat(decoder.decode(response, new TypeReference>() {}.getType())) + .isEqualTo(zones); + } + + @Test + void customEncoder() { + Jackson3Encoder encoder = + new Jackson3Encoder( + Arrays.asList(new SimpleModule().addSerializer(Zone.class, new ZoneSerializer()))); + + List zones = new LinkedList<>(); + zones.add(new Zone("denominator.io.")); + zones.add(new Zone("denominator.io.", "abcd")); + + RequestTemplate template = new RequestTemplate(); + encoder.encode(zones, new TypeReference>() {}.getType(), template); + + assertThat(template) + .hasBody( + "" // + + "[ {" + + System.lineSeparator() + + " \"name\" : \"DENOMINATOR.IO.\"" + + System.lineSeparator() + + "}, {" + + System.lineSeparator() + + " \"name\" : \"DENOMINATOR.IO.\"," + + System.lineSeparator() + + " \"id\" : \"ABCD\"" + + System.lineSeparator() + + "} ]"); + } + + @Test + void decoderCharset() throws IOException { + Zone zone = new Zone("denominator.io.", "ÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÑ"); + + Map> headers = new HashMap<>(); + headers.put("Content-Type", Arrays.asList("application/json;charset=ISO-8859-1")); + + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(headers) + .body( + new String( + "" // + + "{" + + System.lineSeparator() + + " \"name\" : \"DENOMINATOR.IO.\"," + + System.lineSeparator() + + " \"id\" : \"ÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÑ\"" + + System.lineSeparator() + + "}") + .getBytes(StandardCharsets.ISO_8859_1)) + .build(); + assertThat( + ((Zone) new Jackson3Decoder().decode(response, new TypeReference() {}.getType()))) + .containsEntry("id", zone.get("id")); + } + + @Test + void decodesIterator() throws Exception { + List zones = new LinkedList<>(); + zones.add(new Zone("denominator.io.")); + zones.add(new Zone("denominator.io.", "ABCD")); + + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.emptyMap()) + .body(zonesJson, UTF_8) + .build(); + Object decoded = + Jackson3IteratorDecoder.create() + .decode(response, new TypeReference>() {}.getType()); + assertThat(Iterator.class.isAssignableFrom(decoded.getClass())).isTrue(); + assertThat(Closeable.class.isAssignableFrom(decoded.getClass())).isTrue(); + assertThat(asList((Iterator) decoded)).isEqualTo(zones); + } + + private List asList(Iterator iter) { + final List copy = new ArrayList<>(); + while (iter.hasNext()) { + copy.add(iter.next()); + } + return copy; + } + + @Test + void nullBodyDecodesToEmptyIterator() throws Exception { + Response response = + Response.builder() + .status(204) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.emptyMap()) + .build(); + assertThat((byte[]) Jackson3IteratorDecoder.create().decode(response, byte[].class)).isEmpty(); + } + + @Test + void emptyBodyDecodesToEmptyIterator() throws Exception { + Response response = + Response.builder() + .status(204) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.emptyMap()) + .body(new byte[0]) + .build(); + assertThat((byte[]) Jackson3IteratorDecoder.create().decode(response, byte[].class)).isEmpty(); + } + + static class Zone extends LinkedHashMap { + + private static final long serialVersionUID = 1L; + + Zone() { + // for reflective instantiation. + } + + Zone(String name) { + this(name, null); + } + + Zone(String name, String id) { + put("name", name); + if (id != null) { + put("id", id); + } + } + } + + static class ZoneDeserializer extends StdDeserializer { + + public ZoneDeserializer() { + super(Zone.class); + } + + @Override + public Zone deserialize(JsonParser jp, DeserializationContext ctxt) { + Zone zone = new Zone(); + jp.nextToken(); + while (jp.nextToken() != JsonToken.END_OBJECT) { + String name = jp.currentName(); + String value = jp.getValueAsString(); + if (value != null) { + zone.put(name, value.toUpperCase()); + } + } + return zone; + } + } + + static class ZoneSerializer extends StdSerializer { + + public ZoneSerializer() { + super(Zone.class); + } + + @Override + public void serialize(Zone value, JsonGenerator jgen, SerializationContext provider) + throws JacksonException { + jgen.writeStartObject(); + for (Map.Entry entry : value.entrySet()) { + jgen.writeName(entry.getKey()); + jgen.writeString(entry.getValue().toString().toUpperCase()); + } + jgen.writeEndObject(); + } + } + + /** Enabled via {@link feign.Feign.Builder#dismiss404()} */ + @Test + void notFoundDecodesToEmpty() throws Exception { + Response response = + Response.builder() + .status(404) + .reason("NOT FOUND") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.emptyMap()) + .build(); + assertThat((byte[]) new Jackson3Decoder().decode(response, byte[].class)).isEmpty(); + } + + /** Enabled via {@link feign.Feign.Builder#dismiss404()} */ + @Test + void notFoundDecodesToEmptyIterator() throws Exception { + Response response = + Response.builder() + .status(404) + .reason("NOT FOUND") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.emptyMap()) + .build(); + assertThat((byte[]) Jackson3IteratorDecoder.create().decode(response, byte[].class)).isEmpty(); + } +} diff --git a/jackson3/src/test/java/feign/jackson3/examples/GitHubExample.java b/jackson3/src/test/java/feign/jackson3/examples/GitHubExample.java new file mode 100644 index 0000000000..4bced86a97 --- /dev/null +++ b/jackson3/src/test/java/feign/jackson3/examples/GitHubExample.java @@ -0,0 +1,59 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.jackson3.examples; + +import feign.Feign; +import feign.Param; +import feign.RequestLine; +import feign.jackson3.Jackson3Decoder; +import java.util.List; + +/** adapted from {@code com.example.retrofit.GitHubClient} */ +public class GitHubExample { + + public static void main(String... args) { + GitHub github = + Feign.builder() + .decoder(new Jackson3Decoder()) + .target(GitHub.class, "https://api.github.com"); + + System.out.println("Let's fetch and print a list of the contributors to this library."); + List contributors = github.contributors("netflix", "feign"); + for (Contributor contributor : contributors) { + System.out.println(contributor.login + " (" + contributor.contributions + ")"); + } + } + + interface GitHub { + + @RequestLine("GET /repos/{owner}/{repo}/contributors") + List contributors(@Param("owner") String owner, @Param("repo") String repo); + } + + static class Contributor { + + private String login; + private int contributions; + + void setLogin(String login) { + this.login = login; + } + + void setContributions(int contributions) { + this.contributions = contributions; + } + } +} diff --git a/jackson3/src/test/java/feign/jackson3/examples/GitHubIteratorExample.java b/jackson3/src/test/java/feign/jackson3/examples/GitHubIteratorExample.java new file mode 100644 index 0000000000..9bca014240 --- /dev/null +++ b/jackson3/src/test/java/feign/jackson3/examples/GitHubIteratorExample.java @@ -0,0 +1,67 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.jackson3.examples; + +import feign.Feign; +import feign.Param; +import feign.RequestLine; +import feign.jackson3.Jackson3IteratorDecoder; +import java.io.Closeable; +import java.io.IOException; +import java.util.Iterator; + +/** adapted from {@code com.example.retrofit.GitHubClient} */ +public class GitHubIteratorExample { + + public static void main(String... args) throws IOException { + GitHub github = + Feign.builder() + .decoder(Jackson3IteratorDecoder.create()) + .doNotCloseAfterDecode() + .target(GitHub.class, "https://api.github.com"); + + System.out.println("Let's fetch and print a list of the contributors to this library."); + Iterator contributors = github.contributors("OpenFeign", "feign"); + try { + while (contributors.hasNext()) { + Contributor contributor = contributors.next(); + System.out.println(contributor.login + " (" + contributor.contributions + ")"); + } + } finally { + ((Closeable) contributors).close(); + } + } + + interface GitHub { + + @RequestLine("GET /repos/{owner}/{repo}/contributors") + Iterator contributors(@Param("owner") String owner, @Param("repo") String repo); + } + + static class Contributor { + + private String login; + private int contributions; + + void setLogin(String login) { + this.login = login; + } + + void setContributions(int contributions) { + this.contributions = contributions; + } + } +} diff --git a/pom.xml b/pom.xml index 9df6ff2076..1e392888f3 100644 --- a/pom.xml +++ b/pom.xml @@ -89,6 +89,7 @@ hc5 hystrix jackson + jackson3 jackson-jaxb jackson-jr jaxb @@ -168,7 +169,7 @@ 6.0.2 2.21.0 - 2.21 + 3.0.2 3.27.7 5.21.0 2.0.60.android8 @@ -470,33 +471,11 @@ - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.annotations.version} - - - - com.fasterxml.jackson.jr - jackson-jr-objects - ${jackson.version} - - - - com.fasterxml.jackson.jr - jackson-jr-annotation-support + com.fasterxml.jackson + jackson-bom ${jackson.version} + pom + import From 08b9c7cef6a3c801ccf77b18214b4b610ed8f871 Mon Sep 17 00:00:00 2001 From: Marvin Date: Fri, 6 Feb 2026 12:39:42 -0300 Subject: [PATCH 349/615] Upgrade test compilation and execution to Java 25 (#3210) * Upgrade test compilation and execution to Java 25 Signed-off-by: Marvin Froeder * Apply OpenRewrite UpgradeToJava25 on test sources and fix Lombok val compatibility Signed-off-by: Marvin Froeder * Update TrustingSSLSocketFactory to use TLS and ECDHE cipher suite for Java 25 compatibility Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder --- .circleci/config.yml | 8 ++--- .circleci/toolchains.xml | 9 +++++ ...nnotationErrorDecoderNoAnnotationTest.java | 2 +- .../feign/AlwaysEncodeBodyContractTest.java | 2 +- core/src/test/java/feign/AsyncFeignTest.java | 28 ++++++++-------- core/src/test/java/feign/BaseApiTest.java | 6 ++-- core/src/test/java/feign/BaseBuilderTest.java | 9 ++--- .../src/test/java/feign/FeignBuilderTest.java | 12 +++---- core/src/test/java/feign/FeignTest.java | 26 +++++++-------- .../test/java/feign/FeignUnderAsyncTest.java | 20 +++++------ .../java/feign/client/DefaultClientTest.java | 2 +- .../client/TrustingSSLSocketFactory.java | 4 +-- .../java/feign/examples/GitHubExample.java | 4 +-- .../feign/optionals/OptionalDecoderTests.java | 2 +- .../java/feign/stream/StreamDecoderTest.java | 10 +++--- .../fastjson2/examples/GitHubExample.java | 4 +-- .../form/feign/spring/DownloadClient.java | 7 ++-- .../java/feign/form/feign/spring/Server.java | 15 ++++----- .../feign/spring/SpringFormEncoderTest.java | 33 +++++++++---------- .../SpringManyMultipartFilesReaderTest.java | 9 +++-- .../test/java/feign/form/BasicClientTest.java | 33 +++++++++---------- .../java/feign/form/ByteArrayClientTest.java | 5 ++- .../java/feign/form/CustomClientTest.java | 9 +++-- .../java/feign/form/FormPropertyTest.java | 5 ++- form/src/test/java/feign/form/Server.java | 31 +++++++++-------- .../test/java/feign/form/WildCardMapTest.java | 3 +- .../java/feign/form/issues/Issue63Test.java | 7 ++-- .../java/feign/form/utils/UndertowServer.java | 7 ++-- .../feign/gson/examples/GitHubExample.java | 4 +-- .../feign/hc5/AsyncApacheHttp5ClientTest.java | 20 +++++------ .../feign/hystrix/HystrixBuilderTest.java | 28 ++++++++-------- .../jackson/jr/examples/GitHubExample.java | 4 +-- .../feign/jackson/examples/GitHubExample.java | 4 +-- .../examples/GitHubIteratorExample.java | 4 +-- .../test/Http2ClientAsyncTest.java | 22 ++++++------- .../test/java/feign/jaxb/JAXBCodecTest.java | 4 +-- .../feign/jaxb/JAXBContextFactoryTest.java | 4 +-- .../java/feign/jaxb/examples/IAMExample.java | 2 +- .../test/java/feign/jaxb/JAXBCodecTest.java | 4 +-- .../feign/jaxb/JAXBContextFactoryTest.java | 4 +-- .../java/feign/jaxb/examples/IAMExample.java | 2 +- .../feign/jaxrs/examples/GitHubExample.java | 4 +-- .../feign/jaxrs2/AbstractJAXRSClientTest.java | 6 ++-- .../feign/json/examples/GitHubExample.java | 4 +-- .../micrometer/AbstractMetricsTestBase.java | 8 ++--- .../feign/moshi/examples/GithubExample.java | 4 +-- .../feign/okhttp/OkHttpClientAsyncTest.java | 22 ++++++------- pom.xml | 5 +-- .../ReactiveFeignIntegrationTest.java | 8 ++--- .../reactive/examples/ConsoleLogger.java | 2 +- .../examples/ReactorGitHubExample.java | 10 +++--- .../examples/RxJavaGitHubExample.java | 4 +-- .../test/java/feign/ribbon/LBClientTest.java | 4 +-- .../java/feign/ribbon/RibbonClientTest.java | 8 ++--- .../test/java/feign/sax/SAXDecoderTest.java | 2 +- .../java/feign/sax/examples/IAMExample.java | 2 +- .../vertx/AbstractClientReconnectTest.java | 4 +-- .../feign/vertx/ConnectionsLeakTests.java | 4 +-- .../src/test/java/feign/vertx/TestUtils.java | 2 +- .../vertx/testcase/domain/OrderGenerator.java | 4 +-- .../vertx/AbstractClientReconnectTest.java | 4 +-- .../feign/vertx/ConnectionsLeakTests.java | 4 +-- 62 files changed, 258 insertions(+), 275 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dd72406d1b..b0ba8a6ada 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -29,7 +29,7 @@ commands: - run: name: 'Check if cache was restored' command: | - if [ -d "$HOME/.sdkman/candidates/java/21.0.2-tem" ] && [ -d ~/.m2/repository/io/github/openfeign ]; then + if [ -d "$HOME/.sdkman/candidates/java/25.0.2-tem" ] && [ -d ~/.m2/repository/io/github/openfeign ]; then echo "Complete cache hit detected - SDKMAN and Maven dependencies available." circleci step halt elif [ -d "$HOME/.sdkman/candidates/java/21.0.2-tem" ]; then @@ -47,16 +47,16 @@ commands: fi source "$HOME/.sdkman/bin/sdkman-init.sh" - run: - name: 'Install JDKs (8, 11, 17, 21)' + name: 'Install JDKs (8, 11, 17, 21, 25)' command: | source "$HOME/.sdkman/bin/sdkman-init.sh" - jdk_versions=("8.0.382-tem" "11.0.22-tem" "17.0.10-tem" "21.0.2-tem") + jdk_versions=("8.0.382-tem" "11.0.22-tem" "17.0.10-tem" "21.0.2-tem" "25.0.2-tem") for jdk_version in "${jdk_versions[@]}"; do if [ ! -d "$HOME/.sdkman/candidates/java/$jdk_version" ]; then echo "n" | sdk install java "$jdk_version" || true fi done - sdk default java 21.0.2-tem + sdk default java 25.0.2-tem - run: name: 'Configure Maven Toolchain' command: | diff --git a/.circleci/toolchains.xml b/.circleci/toolchains.xml index d6ef9d38d3..48764b609f 100644 --- a/.circleci/toolchains.xml +++ b/.circleci/toolchains.xml @@ -50,4 +50,13 @@ /home/circleci/.sdkman/candidates/java/21.0.2-tem + + jdk + + 25 + + + /home/circleci/.sdkman/candidates/java/25.0.2-tem + + \ No newline at end of file diff --git a/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderNoAnnotationTest.java b/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderNoAnnotationTest.java index 78e5062988..57cb8c06f6 100644 --- a/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderNoAnnotationTest.java +++ b/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderNoAnnotationTest.java @@ -32,7 +32,7 @@ public Class interfaceAtTest() { @Test void delegatesToDefaultErrorDecoder() throws Exception { - ErrorDecoder defaultErrorDecoder = (methodKey, response) -> new DefaultErrorDecoderException(); + ErrorDecoder defaultErrorDecoder = (_, _) -> new DefaultErrorDecoderException(); AnnotationErrorDecoder decoder = AnnotationErrorDecoder.builderFor(TestClientInterfaceWithNoAnnotations.class) diff --git a/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java b/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java index de0580ddd1..7a626d6ef0 100644 --- a/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java +++ b/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java @@ -38,7 +38,7 @@ class AlwaysEncodeBodyContractTest { private static class SampleContract extends AlwaysEncodeBodyContract { SampleContract() { AnnotationProcessor annotationProcessor = - (annotation, metadata) -> metadata.template().method(Request.HttpMethod.POST); + (_, metadata) -> metadata.template().method(Request.HttpMethod.POST); super.registerMethodAnnotation(SampleMethodAnnotation.class, annotationProcessor); } } diff --git a/core/src/test/java/feign/AsyncFeignTest.java b/core/src/test/java/feign/AsyncFeignTest.java index d1ac3c8772..62f2c8067f 100644 --- a/core/src/test/java/feign/AsyncFeignTest.java +++ b/core/src/test/java/feign/AsyncFeignTest.java @@ -508,7 +508,7 @@ void overrideTypeSpecificDecoder() throws Throwable { TestInterfaceAsync api = new TestInterfaceAsyncBuilder() - .decoder((response, type) -> "fail") + .decoder((_, _) -> "fail") .target("http://localhost:" + server.getPort()); assertThat(unwrap(api.post())).isEqualTo("fail"); @@ -551,7 +551,7 @@ void doesntRetryAfterResponseIsSent() throws Throwable { TestInterfaceAsync api = new TestInterfaceAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target("http://localhost:" + server.getPort()); @@ -569,7 +569,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { TestInterfaceAsync api = AsyncFeign.builder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); @@ -594,7 +594,7 @@ void throwsFeignExceptionWithoutBody() { TestInterfaceAsync api = AsyncFeign.builder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); @@ -621,7 +621,7 @@ void ensureRetryerClonesItself() throws Throwable { AsyncFeign.builder() .retryer(retryer) .errorDecoder( - (methodKey, response) -> + (_, response) -> new RetryableException( response.status(), "play it again sam!", @@ -647,7 +647,7 @@ void throwsOriginalExceptionAfterFailedRetries() throws Throwable { .exceptionPropagationPolicy(UNWRAP) .retryer(new Retryer.Default(1, 1, 2)) .errorDecoder( - (methodKey, response) -> + (_, response) -> new RetryableException( response.status(), "play it again sam!", @@ -673,7 +673,7 @@ void throwsRetryableExceptionIfNoUnderlyingCause() throws Throwable { .exceptionPropagationPolicy(UNWRAP) .retryer(new Retryer.Default(1, 1, 2)) .errorDecoder( - (methodKey, response) -> + (_, response) -> new RetryableException( response.status(), message, @@ -705,7 +705,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { // fake client as Client.Default follows redirects. TestInterfaceAsync api = AsyncFeign.builder() - .client(new AsyncClient.Default<>((request, options) -> response, execs)) + .client(new AsyncClient.Default<>((_, _) -> response, execs)) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); assertThat(unwrap(api.response()).headers()) @@ -730,7 +730,7 @@ public void cancelRetry(final int expectedTryCount) throws Throwable { final int RUNNING_TIME_MILLIS = 100; final ExecutorService execs = Executors.newSingleThreadExecutor(); final AsyncClient clientMock = - (request, options, requestContext) -> + (_, _, _) -> CompletableFuture.supplyAsync( () -> { final int tryCount = actualTryCount.addAndGet(1); @@ -796,7 +796,7 @@ void okIfDecodeRootCauseHasNoMessage() throws Throwable { TestInterfaceAsync api = new TestInterfaceAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -812,7 +812,7 @@ void decodingExceptionGetWrappedInDismiss404Mode() throws Throwable { new TestInterfaceAsyncBuilder() .dismiss404() .decoder( - (response, type) -> { + (response, _) -> { assertEquals(404, response.status()); throw new NoSuchElementException(); }) @@ -848,7 +848,7 @@ void okIfEncodeRootCauseHasNoMessage() throws Throwable { TestInterfaceAsync api = new TestInterfaceAsyncBuilder() .encoder( - (object, bodyType, template) -> { + (_, _, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -951,7 +951,7 @@ void responseMapperIsAppliedBeforeDelegate() throws IOException { } private ResponseMapper upperCaseResponseMapper() { - return (response, type) -> { + return (response, _) -> { try { return response.toBuilder() .body(Util.toString(response.body().asReader()).toUpperCase().getBytes()) @@ -1222,7 +1222,7 @@ static final class TestInterfaceAsyncBuilder { AsyncFeign.builder() .decoder(new Decoder.Default()) .encoder( - (object, bodyType, template) -> { + (object, _, template) -> { if (object instanceof Map) { template.body(new Gson().toJson(object)); } else { diff --git a/core/src/test/java/feign/BaseApiTest.java b/core/src/test/java/feign/BaseApiTest.java index 11789f05b4..be2cee7dd8 100644 --- a/core/src/test/java/feign/BaseApiTest.java +++ b/core/src/test/java/feign/BaseApiTest.java @@ -65,7 +65,7 @@ void resolvesParameterizedResult() throws InterruptedException { Feign.builder() .decoder( - (response, type) -> { + (_, type) -> { assertThat(type).isEqualTo(new TypeToken>() {}.getType()); return null; }) @@ -83,10 +83,10 @@ void resolvesBodyParameter() throws InterruptedException { Feign.builder() .encoder( - (object, bodyType, template) -> + (_, bodyType, _) -> assertThat(bodyType).isEqualTo(new TypeToken>() {}.getType())) .decoder( - (response, type) -> { + (_, type) -> { assertThat(type).isEqualTo(new TypeToken>() {}.getType()); return null; }) diff --git a/core/src/test/java/feign/BaseBuilderTest.java b/core/src/test/java/feign/BaseBuilderTest.java index 297f0e3bd3..11b9b7c089 100644 --- a/core/src/test/java/feign/BaseBuilderTest.java +++ b/core/src/test/java/feign/BaseBuilderTest.java @@ -30,9 +30,7 @@ class BaseBuilderTest { void checkEnrichTouchesAllAsyncBuilderFields() throws IllegalArgumentException, IllegalAccessException { test( - AsyncFeign.builder() - .requestInterceptor(template -> {}) - .responseInterceptor((ic, c) -> c.next(ic)), + AsyncFeign.builder().requestInterceptor(_ -> {}).responseInterceptor((ic, c) -> c.next(ic)), 14); } @@ -62,9 +60,6 @@ private void test(BaseBuilder builder, int expectedFieldsCount) void checkEnrichTouchesAllBuilderFields() throws IllegalArgumentException, IllegalAccessException { test( - Feign.builder() - .requestInterceptor(template -> {}) - .responseInterceptor((ic, c) -> c.next(ic)), - 12); + Feign.builder().requestInterceptor(_ -> {}).responseInterceptor((ic, c) -> c.next(ic)), 12); } } diff --git a/core/src/test/java/feign/FeignBuilderTest.java b/core/src/test/java/feign/FeignBuilderTest.java index 18393f6fea..2194c02490 100644 --- a/core/src/test/java/feign/FeignBuilderTest.java +++ b/core/src/test/java/feign/FeignBuilderTest.java @@ -210,7 +210,7 @@ void overrideEncoder() throws Exception { server.enqueue(new MockResponse().setBody("response data")); String url = "http://localhost:" + server.getPort(); - Encoder encoder = (object, bodyType, template) -> template.body(object.toString()); + Encoder encoder = (object, _, template) -> template.body(object.toString()); TestInterface api = Feign.builder().encoder(encoder).target(TestInterface.class, url); api.encodedPost(Arrays.asList("This", "is", "my", "request")); @@ -223,7 +223,7 @@ void overrideDecoder() { server.enqueue(new MockResponse().setBody("success!")); String url = "http://localhost:" + server.getPort(); - Decoder decoder = (response, type) -> "fail"; + Decoder decoder = (_, _) -> "fail"; TestInterface api = Feign.builder().decoder(decoder).target(TestInterface.class, url); assertThat(api.decodedPost()).isEqualTo("fail"); @@ -237,7 +237,7 @@ void overrideQueryMapEncoder() throws Exception { String url = "http://localhost:" + server.getPort(); QueryMapEncoder customMapEncoder = - ignored -> { + _ -> { Map queryMap = new HashMap<>(); queryMap.put("key1", "value1"); queryMap.put("key2", "value2"); @@ -347,7 +347,7 @@ void doNotCloseAfterDecode() { String url = "http://localhost:" + server.getPort(); Decoder decoder = - (response, type) -> + (response, _) -> new Iterator<>() { private boolean called = false; @@ -391,7 +391,7 @@ void doNotCloseAfterDecodeDecoderFailure() { String url = "http://localhost:" + server.getPort(); Decoder angryDecoder = - (response, type) -> { + (_, _) -> { throw new IOException("Failed to decode the response"); }; @@ -454,7 +454,7 @@ public void close() throws IOException { try { api.decodedLazyPost(); fail("Expected an exception"); - } catch (FeignException expected) { + } catch (FeignException _) { } assertThat(closed.get()).as("Responses must be closed when the decoder fails").isTrue(); } diff --git a/core/src/test/java/feign/FeignTest.java b/core/src/test/java/feign/FeignTest.java index 15d744d214..6369047419 100755 --- a/core/src/test/java/feign/FeignTest.java +++ b/core/src/test/java/feign/FeignTest.java @@ -534,7 +534,7 @@ void overrideTypeSpecificDecoder() throws Exception { TestInterface api = new TestInterfaceBuilder() - .decoder((response, type) -> "fail") + .decoder((_, _) -> "fail") .target("http://localhost:" + server.getPort()); assertThat("fail").isEqualTo(api.post()); @@ -577,7 +577,7 @@ void doesntRetryAfterResponseIsSent() throws Exception { TestInterface api = new TestInterfaceBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target("http://localhost:" + server.getPort()); @@ -593,7 +593,7 @@ void throwsFeignExceptionIncludingBody() { TestInterface api = Feign.builder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target(TestInterface.class, "http://localhost:" + server.getPort()); @@ -614,7 +614,7 @@ void throwsFeignExceptionWithoutBody() { TestInterface api = Feign.builder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target(TestInterface.class, "http://localhost:" + server.getPort()); @@ -641,7 +641,7 @@ void ensureRetryerClonesItself() throws Exception { Feign.builder() .retryer(retryer) .errorDecoder( - (methodKey, response) -> + (_, response) -> new RetryableException( response.status(), "play it again sam!", @@ -667,7 +667,7 @@ void throwsOriginalExceptionAfterFailedRetries() throws Exception { .exceptionPropagationPolicy(UNWRAP) .retryer(new Retryer.Default(1, 1, 2)) .errorDecoder( - (methodKey, response) -> + (_, response) -> new RetryableException( response.status(), "play it again sam!", @@ -692,7 +692,7 @@ void throwsRetryableExceptionIfNoUnderlyingCause() throws Exception { .exceptionPropagationPolicy(UNWRAP) .retryer(new Retryer.Default(1, 1, 2)) .errorDecoder( - (methodKey, response) -> + (_, response) -> new RetryableException( response.status(), message, @@ -721,7 +721,7 @@ void whenReturnTypeIsResponseNoErrorHandling() { // fake client as Client.Default follows redirects. TestInterface api = Feign.builder() - .client((request, options) -> response) + .client((_, _) -> response) .target(TestInterface.class, "http://localhost:" + server.getPort()); assertThat(api.response().headers()) @@ -758,7 +758,7 @@ void okIfDecodeRootCauseHasNoMessage() throws Exception { TestInterface api = new TestInterfaceBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -774,7 +774,7 @@ void decodingExceptionGetWrappedInDismiss404Mode() throws Exception { new TestInterfaceBuilder() .dismiss404() .decoder( - (response, type) -> { + (response, _) -> { assertEquals(404, response.status()); throw new NoSuchElementException(); }) @@ -806,7 +806,7 @@ void okIfEncodeRootCauseHasNoMessage() throws Exception { TestInterface api = new TestInterfaceBuilder() .encoder( - (object, bodyType, template) -> { + (_, _, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -889,7 +889,7 @@ void responseMapperIsAppliedBeforeDelegate() throws IOException { } private ResponseMapper upperCaseResponseMapper() { - return (response, type) -> { + return (response, _) -> { try { return response.toBuilder() .body(Util.toString(response.body().asReader(UTF_8)).toUpperCase().getBytes()) @@ -1426,7 +1426,7 @@ static final class TestInterfaceBuilder { new Feign.Builder() .decoder(new Decoder.Default()) .encoder( - (object, bodyType, template) -> { + (object, _, template) -> { if (object instanceof Map) { template.body(new Gson().toJson(object)); } else { diff --git a/core/src/test/java/feign/FeignUnderAsyncTest.java b/core/src/test/java/feign/FeignUnderAsyncTest.java index 94992ad5b3..d99c543cf7 100644 --- a/core/src/test/java/feign/FeignUnderAsyncTest.java +++ b/core/src/test/java/feign/FeignUnderAsyncTest.java @@ -451,7 +451,7 @@ void overrideTypeSpecificDecoder() throws Exception { TestInterface api = new TestInterfaceBuilder() - .decoder((response, type) -> "fail") + .decoder((_, _) -> "fail") .target("http://localhost:" + server.getPort()); assertThat("fail").isEqualTo(api.post()); @@ -464,7 +464,7 @@ void doesntRetryAfterResponseIsSent() throws Exception { TestInterface api = new TestInterfaceBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target("http://localhost:" + server.getPort()); @@ -480,7 +480,7 @@ void throwsFeignExceptionIncludingBody() { TestInterface api = AsyncFeign.builder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target(TestInterface.class, "http://localhost:" + server.getPort()); @@ -501,7 +501,7 @@ void throwsFeignExceptionWithoutBody() { TestInterface api = AsyncFeign.builder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target(TestInterface.class, "http://localhost:" + server.getPort()); @@ -533,7 +533,7 @@ void whenReturnTypeIsResponseNoErrorHandling() { // fake client as Client.Default follows redirects. TestInterface api = AsyncFeign.builder() - .client(new AsyncClient.Default<>((request, options) -> response, execs)) + .client(new AsyncClient.Default<>((_, _) -> response, execs)) .target(TestInterface.class, "http://localhost:" + server.getPort()); assertThat(api.response().headers()) @@ -571,7 +571,7 @@ void okIfDecodeRootCauseHasNoMessage() throws Exception { TestInterface api = new TestInterfaceBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -587,7 +587,7 @@ void decodingExceptionGetWrappedInDismiss404Mode() throws Exception { new TestInterfaceBuilder() .dismiss404() .decoder( - (response, type) -> { + (response, _) -> { assertEquals(404, response.status()); throw new NoSuchElementException(); }) @@ -619,7 +619,7 @@ void okIfEncodeRootCauseHasNoMessage() throws Exception { TestInterface api = new TestInterfaceBuilder() .encoder( - (object, bodyType, template) -> { + (_, _, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -704,7 +704,7 @@ void responseMapperIsAppliedBeforeDelegate() throws IOException { } private ResponseMapper upperCaseResponseMapper() { - return (response, type) -> { + return (response, _) -> { try { return response.toBuilder() .body(Util.toString(response.body().asReader(UTF_8)).toUpperCase().getBytes()) @@ -959,7 +959,7 @@ static final class TestInterfaceBuilder { AsyncFeign.builder() .decoder(new Decoder.Default()) .encoder( - (object, bodyType, template) -> { + (object, _, template) -> { if (object instanceof Map) { template.body(new Gson().toJson(object)); } else { diff --git a/core/src/test/java/feign/client/DefaultClientTest.java b/core/src/test/java/feign/client/DefaultClientTest.java index 6aa821c72a..6e05606e76 100644 --- a/core/src/test/java/feign/client/DefaultClientTest.java +++ b/core/src/test/java/feign/client/DefaultClientTest.java @@ -37,7 +37,7 @@ public class DefaultClientTest extends AbstractClientTest { protected Client disableHostnameVerification = - new Client.Default(TrustingSSLSocketFactory.get(), (s, sslSession) -> true); + new Client.Default(TrustingSSLSocketFactory.get(), (_, _) -> true); @Override public Builder newBuilder() { diff --git a/core/src/test/java/feign/client/TrustingSSLSocketFactory.java b/core/src/test/java/feign/client/TrustingSSLSocketFactory.java index 7f74c78614..0222ff1211 100644 --- a/core/src/test/java/feign/client/TrustingSSLSocketFactory.java +++ b/core/src/test/java/feign/client/TrustingSSLSocketFactory.java @@ -42,7 +42,7 @@ public final class TrustingSSLSocketFactory extends SSLSocketFactory private static final Map sslSocketFactories = new LinkedHashMap<>(); private static final char[] KEYSTORE_PASSWORD = "password".toCharArray(); - private static final String[] ENABLED_CIPHER_SUITES = {"TLS_RSA_WITH_AES_256_CBC_SHA"}; + private static final String[] ENABLED_CIPHER_SUITES = {"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"}; private final SSLSocketFactory delegate; private final String serverAlias; private final PrivateKey privateKey; @@ -50,7 +50,7 @@ public final class TrustingSSLSocketFactory extends SSLSocketFactory private TrustingSSLSocketFactory(String serverAlias) { try { - SSLContext sc = SSLContext.getInstance("SSL"); + SSLContext sc = SSLContext.getInstance("TLS"); sc.init(new KeyManager[] {this}, new TrustManager[] {this}, new SecureRandom()); this.delegate = sc.getSocketFactory(); } catch (Exception e) { diff --git a/core/src/test/java/feign/examples/GitHubExample.java b/core/src/test/java/feign/examples/GitHubExample.java index ac204e92a4..248876a5b8 100644 --- a/core/src/test/java/feign/examples/GitHubExample.java +++ b/core/src/test/java/feign/examples/GitHubExample.java @@ -42,10 +42,10 @@ public static void main(String... args) { .logLevel(Logger.Level.BASIC) .target(GitHub.class, "https://api.github.com"); - System.out.println("Let's fetch and print a list of the contributors to this library."); + IO.println("Let's fetch and print a list of the contributors to this library."); List contributors = github.contributors("netflix", "feign"); for (Contributor contributor : contributors) { - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } } diff --git a/core/src/test/java/feign/optionals/OptionalDecoderTests.java b/core/src/test/java/feign/optionals/OptionalDecoderTests.java index f0abc88de9..ef54854ac3 100644 --- a/core/src/test/java/feign/optionals/OptionalDecoderTests.java +++ b/core/src/test/java/feign/optionals/OptionalDecoderTests.java @@ -88,7 +88,7 @@ void test200WhenResponseBodyIsNull() throws IOException, InterruptedException { final OptionalInterface api = Feign.builder() - .decoder(new OptionalDecoder(((response, type) -> null))) + .decoder(new OptionalDecoder(((_, _) -> null))) .target(OptionalInterface.class, server.url("/").toString()); assertThat(api.getAsOptional().isPresent()).isFalse(); diff --git a/core/src/test/java/feign/stream/StreamDecoderTest.java b/core/src/test/java/feign/stream/StreamDecoderTest.java index 2819434851..d514dcc6b7 100644 --- a/core/src/test/java/feign/stream/StreamDecoderTest.java +++ b/core/src/test/java/feign/stream/StreamDecoderTest.java @@ -79,7 +79,7 @@ void simpleStreamTest() { Feign.builder() .decoder( StreamDecoder.create( - (response, type) -> + (response, _) -> new BufferedReader(response.body().asReader(UTF_8)).lines().iterator())) .doNotCloseAfterDecode() .target(StreamInterface.class, server.url("/").toString()); @@ -98,7 +98,7 @@ void simpleDefaultStreamTest() { Feign.builder() .decoder( StreamDecoder.create( - (r, t) -> { + (r, _) -> { BufferedReader bufferedReader = new BufferedReader(r.body().asReader(UTF_8)); return bufferedReader.lines().iterator(); })) @@ -119,11 +119,11 @@ void simpleDeleteDecoderTest() { Feign.builder() .decoder( StreamDecoder.create( - (r, t) -> { + (r, _) -> { BufferedReader bufferedReader = new BufferedReader(r.body().asReader(UTF_8)); return bufferedReader.lines().iterator(); }, - (r, t) -> "str")) + (_, _) -> "str")) .doNotCloseAfterDecode() .target(StreamInterface.class, server.url("/").toString()); @@ -144,7 +144,7 @@ void shouldCloseIteratorWhenStreamClosed() throws IOException { .build(); TestCloseableIterator it = new TestCloseableIterator(); - StreamDecoder decoder = StreamDecoder.create((r, t) -> it); + StreamDecoder decoder = StreamDecoder.create((_, _) -> it); try (Stream stream = (Stream) decoder.decode(response, new TypeReference>() {}.getType())) { diff --git a/fastjson2/src/test/java/feign/fastjson2/examples/GitHubExample.java b/fastjson2/src/test/java/feign/fastjson2/examples/GitHubExample.java index a74707b998..6721bf91d8 100644 --- a/fastjson2/src/test/java/feign/fastjson2/examples/GitHubExample.java +++ b/fastjson2/src/test/java/feign/fastjson2/examples/GitHubExample.java @@ -30,10 +30,10 @@ public static void main(String... args) { .decoder(new Fastjson2Decoder()) .target(GitHub.class, "https://api.github.com"); - System.out.println("Let's fetch and print a list of the contributors to this library."); + IO.println("Let's fetch and print a list of the contributors to this library."); List contributors = github.contributors("netflix", "feign"); for (Contributor contributor : contributors) { - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } } diff --git a/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java b/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java index aa4e42bc13..ce686675cc 100644 --- a/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java +++ b/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java @@ -19,7 +19,6 @@ import feign.codec.Decoder; import feign.form.spring.converter.SpringManyMultipartFilesReader; import java.util.ArrayList; -import lombok.val; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; @@ -46,13 +45,13 @@ class ClientConfiguration { @Bean Decoder feignDecoder() { - val springConverters = messageConverters.getObject().getConverters(); - val decoderConverters = new ArrayList>(springConverters.size() + 1); + var springConverters = messageConverters.getObject().getConverters(); + var decoderConverters = new ArrayList>(springConverters.size() + 1); decoderConverters.addAll(springConverters); decoderConverters.add(new SpringManyMultipartFilesReader(4096)); - val httpMessageConverters = new HttpMessageConverters(decoderConverters); + var httpMessageConverters = new HttpMessageConverters(decoderConverters); return new SpringDecoder( new ObjectFactory() { diff --git a/form-spring/src/test/java/feign/form/feign/spring/Server.java b/form-spring/src/test/java/feign/form/feign/spring/Server.java index ad51ef9017..ed2e0a711b 100644 --- a/form-spring/src/test/java/feign/form/feign/spring/Server.java +++ b/form-spring/src/test/java/feign/form/feign/spring/Server.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.util.Map; -import lombok.val; import org.apache.commons.text.StringEscapeUtils; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @@ -110,18 +109,18 @@ public ResponseEntity upload6( @GetMapping(path = "/multipart/download/{fileId}", produces = MULTIPART_FORM_DATA_VALUE) public MultiValueMap download(@PathVariable("fileId") String fileId) { - val multiParts = new LinkedMultiValueMap(); + var multiParts = new LinkedMultiValueMap(); - val infoString = "The text for file ID " + fileId + ". Testing unicode €"; - val infoPartheader = new HttpHeaders(); + var infoString = "The text for file ID " + fileId + ". Testing unicode €"; + var infoPartheader = new HttpHeaders(); infoPartheader.setContentType(new MediaType("text", "plain", UTF_8)); - val infoPart = new HttpEntity(infoString, infoPartheader); + var infoPart = new HttpEntity(infoString, infoPartheader); - val file = new ClassPathResource("testfile.txt"); - val filePartheader = new HttpHeaders(); + var file = new ClassPathResource("testfile.txt"); + var filePartheader = new HttpHeaders(); filePartheader.setContentType(APPLICATION_OCTET_STREAM); - val filePart = new HttpEntity(file, filePartheader); + var filePart = new HttpEntity(file, filePartheader); multiParts.add("info", infoPart); multiParts.add("file", filePart); diff --git a/form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java b/form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java index 5bf9fa3499..309397c0e2 100644 --- a/form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java +++ b/form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java @@ -23,7 +23,6 @@ import feign.Response; import java.util.HashMap; import java.util.List; -import lombok.val; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -47,9 +46,9 @@ class SpringFormEncoderTest { @Test void upload1Test() throws Exception { - val folder = "test_folder"; - val file = new MockMultipartFile("file", "test".getBytes(UTF_8)); - val message = "message test"; + var folder = "test_folder"; + var file = new MockMultipartFile("file", "test".getBytes(UTF_8)); + var message = "message test"; assertThat(client.upload1(folder, file, message)) .isEqualTo(new String(file.getBytes()) + ':' + message + ':' + folder); @@ -57,9 +56,9 @@ void upload1Test() throws Exception { @Test void upload2Test() throws Exception { - val folder = "test_folder"; - val file = new MockMultipartFile("file", "test".getBytes(UTF_8)); - val message = "message test"; + var folder = "test_folder"; + var file = new MockMultipartFile("file", "test".getBytes(UTF_8)); + var message = "message test"; assertThat(client.upload2(file, folder, message)) .isEqualTo(new String(file.getBytes()) + ':' + message + ':' + folder); @@ -67,11 +66,11 @@ void upload2Test() throws Exception { @Test void uploadFileNameAndContentTypeTest() throws Exception { - val folder = "test_folder"; - val file = + var folder = "test_folder"; + var file = new MockMultipartFile( "file", "hello.dat", "application/octet-stream", "test".getBytes(UTF_8)); - val message = "message test"; + var message = "message test"; assertThat(client.upload3(file, folder, message)) .isEqualTo(file.getOriginalFilename() + ':' + file.getContentType() + ':' + folder); @@ -79,28 +78,28 @@ void uploadFileNameAndContentTypeTest() throws Exception { @Test void upload4Test() throws Exception { - val map = new HashMap(); + var map = new HashMap(); map.put("one", 1); map.put("two", 2); - val userName = "popa"; - val id = "42"; + var userName = "popa"; + var id = "42"; assertThat(client.upload4(id, map, userName)).isEqualTo(userName + ':' + id + ':' + map.size()); } @Test void upload5Test() throws Exception { - val file = new MockMultipartFile("popa.txt", "Hello world".getBytes(UTF_8)); - val dto = new Dto("field 1 value", 42, file); + var file = new MockMultipartFile("popa.txt", "Hello world".getBytes(UTF_8)); + var dto = new Dto("field 1 value", 42, file); assertThat(client.upload5(dto)).isNotNull().extracting(Response::status).isEqualTo(200); } @Test void upload6ArrayTest() throws Exception { - val file1 = new MockMultipartFile("popa1", "popa1", null, "Hello".getBytes(UTF_8)); - val file2 = new MockMultipartFile("popa2", "popa2", null, " world".getBytes(UTF_8)); + var file1 = new MockMultipartFile("popa1", "popa1", null, "Hello".getBytes(UTF_8)); + var file2 = new MockMultipartFile("popa2", "popa2", null, " world".getBytes(UTF_8)); assertThat(client.upload6Array(new MultipartFile[] {file1, file2})).isEqualTo("Hello world"); } diff --git a/form-spring/src/test/java/feign/form/feign/spring/converter/SpringManyMultipartFilesReaderTest.java b/form-spring/src/test/java/feign/form/feign/spring/converter/SpringManyMultipartFilesReaderTest.java index 9fcded4c2c..ed551b23bd 100644 --- a/form-spring/src/test/java/feign/form/feign/spring/converter/SpringManyMultipartFilesReaderTest.java +++ b/form-spring/src/test/java/feign/form/feign/spring/converter/SpringManyMultipartFilesReaderTest.java @@ -24,7 +24,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import lombok.val; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; @@ -38,8 +37,8 @@ class SpringManyMultipartFilesReaderTest { @Test void readMultipartFormDataTest() throws IOException { - val multipartFilesReader = new SpringManyMultipartFilesReader(4096); - val multipartFiles = + var multipartFilesReader = new SpringManyMultipartFilesReader(4096); + var multipartFiles = multipartFilesReader.read(MultipartFile[].class, new ValidMultipartMessage()); assertThat(multipartFiles.length).isEqualTo(2); @@ -58,7 +57,7 @@ static class ValidMultipartMessage implements HttpInputMessage { @Override public InputStream getBody() throws IOException { - val multipartBody = + var multipartBody = "--" + DUMMY_MULTIPART_BOUNDARY + "\r\n" @@ -84,7 +83,7 @@ public InputStream getBody() throws IOException { @Override public HttpHeaders getHeaders() { - val httpHeaders = new HttpHeaders(); + var httpHeaders = new HttpHeaders(); httpHeaders.put( CONTENT_TYPE, singletonList(MULTIPART_FORM_DATA_VALUE + "; boundary=" + DUMMY_MULTIPART_BOUNDARY)); diff --git a/form/src/test/java/feign/form/BasicClientTest.java b/form/src/test/java/feign/form/BasicClientTest.java index 646ec2bb16..e4958d21a9 100644 --- a/form/src/test/java/feign/form/BasicClientTest.java +++ b/form/src/test/java/feign/form/BasicClientTest.java @@ -30,7 +30,6 @@ import java.nio.file.Path; import java.util.Arrays; import java.util.Map; -import lombok.val; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -45,7 +44,7 @@ class BasicClientTest { @BeforeAll static void configureClient() { - val logFile = logDir.resolve("log.txt").toString(); + var logFile = logDir.resolve("log.txt").toString(); API = Feign.builder() @@ -67,7 +66,7 @@ void testFormException() { @Test void testUpload() throws Exception { - val path = + var path = Path.of(Thread.currentThread().getContextClassLoader().getResource("file.txt").toURI()); assertThat(path).exists(); @@ -76,7 +75,7 @@ void testUpload() throws Exception { @Test void testUploadWithParam() throws Exception { - val path = + var path = Path.of(Thread.currentThread().getContextClassLoader().getResource("file.txt").toURI()); assertThat(path).exists(); @@ -85,7 +84,7 @@ void testUploadWithParam() throws Exception { @Test void testJson() { - val dto = new Dto("Artem", 11); + var dto = new Dto("Artem", 11); assertThat(API.json(dto)).isEqualTo("ok"); } @@ -100,11 +99,11 @@ void testQueryMap() { @Test void testMultipleFilesArray() throws Exception { - val path1 = + var path1 = Path.of(Thread.currentThread().getContextClassLoader().getResource("file.txt").toURI()); assertThat(path1).exists(); - val path2 = + var path2 = Path.of( Thread.currentThread().getContextClassLoader().getResource("another_file.txt").toURI()); assertThat(path2).exists(); @@ -116,11 +115,11 @@ void testMultipleFilesArray() throws Exception { @Test void testMultipleFilesList() throws Exception { - val path1 = + var path1 = Path.of(Thread.currentThread().getContextClassLoader().getResource("file.txt").toURI()); assertThat(path1).exists(); - val path2 = + var path2 = Path.of( Thread.currentThread().getContextClassLoader().getResource("another_file.txt").toURI()); assertThat(path2).exists(); @@ -132,9 +131,9 @@ void testMultipleFilesList() throws Exception { @Test void testUploadWithDto() throws Exception { - val dto = new Dto("Artem", 11); + var dto = new Dto("Artem", 11); - val path = + var path = Path.of(Thread.currentThread().getContextClassLoader().getResource("file.txt").toURI()); assertThat(path).exists(); @@ -146,7 +145,7 @@ void testUploadWithDto() throws Exception { @Test void testUnknownTypeFile() throws Exception { - val path = + var path = Path.of(Thread.currentThread().getContextClassLoader().getResource("file.abc").toURI()); assertThat(path).exists(); @@ -155,22 +154,22 @@ void testUnknownTypeFile() throws Exception { @Test void testFormData() throws Exception { - val formData = new FormData("application/custom-type", "popa.txt", "Allo".getBytes("UTF-8")); + var formData = new FormData("application/custom-type", "popa.txt", "Allo".getBytes("UTF-8")); assertThat(API.uploadFormData(formData)).isEqualTo("popa.txt:application/custom-type"); } @Test void testSubmitRepeatableQueryParam() throws Exception { - val names = new String[] {"Milada", "Thais"}; - val stringResponse = API.submitRepeatableQueryParam(names); + var names = new String[] {"Milada", "Thais"}; + var stringResponse = API.submitRepeatableQueryParam(names); assertThat(stringResponse).isEqualTo("Milada and Thais"); } @Test void testSubmitRepeatableFormParam() throws Exception { - val names = Arrays.asList("Milada", "Thais"); - val stringResponse = API.submitRepeatableFormParam(names); + var names = Arrays.asList("Milada", "Thais"); + var stringResponse = API.submitRepeatableFormParam(names); assertThat(stringResponse).isEqualTo("Milada and Thais"); } } diff --git a/form/src/test/java/feign/form/ByteArrayClientTest.java b/form/src/test/java/feign/form/ByteArrayClientTest.java index d83ecdaac4..917daea093 100644 --- a/form/src/test/java/feign/form/ByteArrayClientTest.java +++ b/form/src/test/java/feign/form/ByteArrayClientTest.java @@ -27,7 +27,6 @@ import feign.Response; import feign.jackson.JacksonEncoder; import java.nio.file.Path; -import lombok.val; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -42,8 +41,8 @@ class ByteArrayClientTest { @BeforeAll static void configureClient() { - val encoder = new FormEncoder(new JacksonEncoder()); - val logFile = logDir.resolve("log-byte.txt").toString(); + var encoder = new FormEncoder(new JacksonEncoder()); + var logFile = logDir.resolve("log-byte.txt").toString(); API = Feign.builder() diff --git a/form/src/test/java/feign/form/CustomClientTest.java b/form/src/test/java/feign/form/CustomClientTest.java index 8c1e6e48e1..7fd85b6e5b 100644 --- a/form/src/test/java/feign/form/CustomClientTest.java +++ b/form/src/test/java/feign/form/CustomClientTest.java @@ -30,7 +30,6 @@ import feign.form.multipart.Output; import feign.jackson.JacksonEncoder; import java.nio.file.Path; -import lombok.val; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -45,11 +44,11 @@ class CustomClientTest { @BeforeAll static void configureClient() { - val encoder = new FormEncoder(new JacksonEncoder()); - val processor = (MultipartFormContentProcessor) encoder.getContentProcessor(MULTIPART); + var encoder = new FormEncoder(new JacksonEncoder()); + var processor = (MultipartFormContentProcessor) encoder.getContentProcessor(MULTIPART); processor.addFirstWriter(new CustomByteArrayWriter()); - val logFile = logDir.resolve("log.txt").toString(); + var logFile = logDir.resolve("log.txt").toString(); API = Feign.builder() @@ -70,7 +69,7 @@ private static final class CustomByteArrayWriter extends ByteArrayWriter { protected void write(Output output, String key, Object value) throws EncodeException { writeFileMetadata(output, key, "popa.txt", null); - val bytes = (byte[]) value; + var bytes = (byte[]) value; output.write(bytes); } } diff --git a/form/src/test/java/feign/form/FormPropertyTest.java b/form/src/test/java/feign/form/FormPropertyTest.java index bc07aa8031..7450928824 100644 --- a/form/src/test/java/feign/form/FormPropertyTest.java +++ b/form/src/test/java/feign/form/FormPropertyTest.java @@ -25,7 +25,6 @@ import feign.RequestLine; import feign.jackson.JacksonEncoder; import java.nio.file.Path; -import lombok.val; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -40,7 +39,7 @@ class FormPropertyTest { @BeforeAll static void configureClient() { - val logFile = logDir.resolve("log.txt").toString(); + var logFile = logDir.resolve("log.txt").toString(); API = Feign.builder() @@ -52,7 +51,7 @@ static void configureClient() { @Test void test() { - val dto = new FormDto("Amigo", 23); + var dto = new FormDto("Amigo", 23); assertThat(API.postData(dto)).isEqualTo("Amigo=23"); } diff --git a/form/src/test/java/feign/form/Server.java b/form/src/test/java/feign/form/Server.java index a78ffb9883..e9aeb36553 100644 --- a/form/src/test/java/feign/form/Server.java +++ b/form/src/test/java/feign/form/Server.java @@ -28,7 +28,6 @@ import java.io.IOException; import java.util.Collection; import java.util.List; -import lombok.val; import org.apache.commons.text.StringEscapeUtils; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.http.HttpStatus; @@ -52,7 +51,7 @@ public class Server { @PostMapping("/form") public ResponseEntity form( @RequestParam("key1") String key1, @RequestParam("key2") String key2) { - val status = !key1.equals(key2) ? BAD_REQUEST : OK; + var status = !key1.equals(key2) ? BAD_REQUEST : OK; return ResponseEntity.status(status).body(null); } @@ -121,27 +120,27 @@ public ResponseEntity json(@RequestBody Dto dto) { @PostMapping("/query_map") public ResponseEntity queryMap(@RequestParam("filter") List filters) { - val status = filters != null && !filters.isEmpty() ? OK : I_AM_A_TEAPOT; + var status = filters != null && !filters.isEmpty() ? OK : I_AM_A_TEAPOT; return ResponseEntity.status(status).body(filters.size()); } @PostMapping(path = "/wild-card-map", consumes = APPLICATION_FORM_URLENCODED_VALUE) public ResponseEntity wildCardMap( @RequestParam("key1") String key1, @RequestParam("key2") String key2) { - val status = key1.equals(key2) ? OK : I_AM_A_TEAPOT; + var status = key1.equals(key2) ? OK : I_AM_A_TEAPOT; return ResponseEntity.status(status).body(null); } @PostMapping(path = "/upload/with_dto", consumes = MULTIPART_FORM_DATA_VALUE) public ResponseEntity uploadWithDto(Dto dto, @RequestPart("file") MultipartFile file) throws IOException { - val status = dto != null && dto.getName().equals("Artem") ? OK : I_AM_A_TEAPOT; + var status = dto != null && dto.getName().equals("Artem") ? OK : I_AM_A_TEAPOT; return ResponseEntity.status(status).body(file.getSize()); } @PostMapping(path = "/upload/byte_array", consumes = MULTIPART_FORM_DATA_VALUE) public ResponseEntity uploadByteArray(@RequestPart("file") MultipartFile file) { - val status = file != null ? OK : I_AM_A_TEAPOT; + var status = file != null ? OK : I_AM_A_TEAPOT; String safeFilename = HtmlUtils.htmlEscape(file.getOriginalFilename()); return ResponseEntity.status(status).body(safeFilename); } @@ -153,7 +152,7 @@ public ResponseEntity uploadByteArray(@RequestPart("file") MultipartFile // have the filename part it's // available in the parameter (getParameter()) public ResponseEntity uploadByteArrayParameter(MultipartHttpServletRequest request) { - val status = + var status = request.getFile("file") == null && request.getParameter("file") != null ? OK : I_AM_A_TEAPOT; @@ -162,13 +161,13 @@ public ResponseEntity uploadByteArrayParameter(MultipartHttpServletReque @PostMapping(path = "/upload/unknown_type", consumes = MULTIPART_FORM_DATA_VALUE) public ResponseEntity uploadUnknownType(@RequestPart("file") MultipartFile file) { - val status = file != null ? OK : I_AM_A_TEAPOT; + var status = file != null ? OK : I_AM_A_TEAPOT; return ResponseEntity.status(status).body(StringEscapeUtils.escapeHtml4(file.getContentType())); } @PostMapping(path = "/upload/form_data", consumes = MULTIPART_FORM_DATA_VALUE) public ResponseEntity uploadFormData(@RequestPart("file") MultipartFile file) { - val status = file != null ? OK : I_AM_A_TEAPOT; + var status = file != null ? OK : I_AM_A_TEAPOT; String sanitizedFilename = StringEscapeUtils.escapeHtml4(file.getOriginalFilename()); String sanitizedContentType = StringEscapeUtils.escapeHtml4(file.getContentType()); return ResponseEntity.status(status).body(sanitizedFilename + ':' + sanitizedContentType); @@ -176,11 +175,11 @@ public ResponseEntity uploadFormData(@RequestPart("file") MultipartFile @PostMapping(path = "/submit/url", consumes = APPLICATION_FORM_URLENCODED_VALUE) public ResponseEntity submitRepeatableQueryParam(@RequestParam("names") String[] names) { - val response = new StringBuilder(); + var response = new StringBuilder(); if (names != null && names.length == 2) { response.append(names[0]).append(" and ").append(names[1]); } - val status = response.length() > 0 ? OK : I_AM_A_TEAPOT; + var status = response.length() > 0 ? OK : I_AM_A_TEAPOT; return ResponseEntity.status(status).body(response.toString()); } @@ -188,12 +187,12 @@ public ResponseEntity submitRepeatableQueryParam(@RequestParam("names") @PostMapping(path = "/submit/form", consumes = MULTIPART_FORM_DATA_VALUE) public ResponseEntity submitRepeatableFormParam( @RequestParam("names") Collection names) { - val response = new StringBuilder(); + var response = new StringBuilder(); if (names != null && names.size() == 2) { - val iterator = names.iterator(); + var iterator = names.iterator(); response.append(iterator.next()).append(" and ").append(iterator.next()); } - val status = response.length() > 0 ? OK : I_AM_A_TEAPOT; + var status = response.length() > 0 ? OK : I_AM_A_TEAPOT; return ResponseEntity.status(status).body(response.toString()); } @@ -201,11 +200,11 @@ public ResponseEntity submitRepeatableFormParam( @PostMapping(path = "/form-data", consumes = APPLICATION_FORM_URLENCODED_VALUE) public ResponseEntity submitPostData( @RequestParam("f_name") String firstName, @RequestParam("age") Integer age) { - val response = new StringBuilder(); + var response = new StringBuilder(); if (firstName != null && age != null) { response.append(firstName).append("=").append(age); } - val status = response.length() > 0 ? OK : I_AM_A_TEAPOT; + var status = response.length() > 0 ? OK : I_AM_A_TEAPOT; return ResponseEntity.status(status).body(response.toString()); } diff --git a/form/src/test/java/feign/form/WildCardMapTest.java b/form/src/test/java/feign/form/WildCardMapTest.java index 9c8df4c08e..3dca096c8f 100644 --- a/form/src/test/java/feign/form/WildCardMapTest.java +++ b/form/src/test/java/feign/form/WildCardMapTest.java @@ -27,7 +27,6 @@ import java.nio.file.Path; import java.util.HashMap; import java.util.Map; -import lombok.val; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -42,7 +41,7 @@ class WildCardMapTest { @BeforeAll static void configureClient() { - val logFile = logDir.resolve("log.txt").toString(); + var logFile = logDir.resolve("log.txt").toString(); api = Feign.builder() diff --git a/form/src/test/java/feign/form/issues/Issue63Test.java b/form/src/test/java/feign/form/issues/Issue63Test.java index 7a6655eed6..e0a6dafd01 100644 --- a/form/src/test/java/feign/form/issues/Issue63Test.java +++ b/form/src/test/java/feign/form/issues/Issue63Test.java @@ -26,7 +26,6 @@ import io.undertow.server.HttpServerExchange; import java.util.HashMap; import java.util.Map; -import lombok.val; import org.junit.jupiter.api.Test; // https://github.com/OpenFeign/feign-form/issues/63 @@ -34,13 +33,13 @@ class Issue63Test { @Test void test() { - try (val server = UndertowServer.builder().callback(this::handleRequest).start()) { - val client = + try (var server = UndertowServer.builder().callback(this::handleRequest).start()) { + var client = Feign.builder() .encoder(new FormEncoder(new JacksonEncoder())) .target(Client.class, server.getConnectUrl()); - val data = new HashMap(); + var data = new HashMap(); data.put("from", "+987654321"); data.put("to", "+123456789"); data.put("body", "hello world"); diff --git a/form/src/test/java/feign/form/utils/UndertowServer.java b/form/src/test/java/feign/form/utils/UndertowServer.java index a6903b7a80..48704a1ab8 100644 --- a/form/src/test/java/feign/form/utils/UndertowServer.java +++ b/form/src/test/java/feign/form/utils/UndertowServer.java @@ -25,7 +25,6 @@ import java.net.InetSocketAddress; import lombok.Builder; import lombok.RequiredArgsConstructor; -import lombok.val; public final class UndertowServer implements AutoCloseable { @@ -33,7 +32,7 @@ public final class UndertowServer implements AutoCloseable { @Builder(buildMethodName = "start") private UndertowServer(FullBytesCallback callback) { - val port = + var port = SocketUtils.findFreePort() .orElseThrow(() -> new IllegalStateException("no available port to start server")); @@ -52,9 +51,9 @@ private UndertowServer(FullBytesCallback callback) { * @return listining server's url. */ public String getConnectUrl() { - val listenerInfo = undertow.getListenerInfo().iterator().next(); + var listenerInfo = undertow.getListenerInfo().iterator().next(); - val address = (InetSocketAddress) listenerInfo.getAddress(); + var address = (InetSocketAddress) listenerInfo.getAddress(); return String.format( "%s://%s:%d", listenerInfo.getProtcol(), address.getHostString(), address.getPort()); diff --git a/gson/src/test/java/feign/gson/examples/GitHubExample.java b/gson/src/test/java/feign/gson/examples/GitHubExample.java index 960a1bd8e2..3579a5cba0 100644 --- a/gson/src/test/java/feign/gson/examples/GitHubExample.java +++ b/gson/src/test/java/feign/gson/examples/GitHubExample.java @@ -28,10 +28,10 @@ public static void main(String... args) { GitHub github = Feign.builder().decoder(new GsonDecoder()).target(GitHub.class, "https://api.github.com"); - System.out.println("Let's fetch and print a list of the contributors to this library."); + IO.println("Let's fetch and print a list of the contributors to this library."); List contributors = github.contributors("netflix", "feign"); for (Contributor contributor : contributors) { - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } } diff --git a/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java b/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java index 323e5689e9..82440460a7 100644 --- a/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java +++ b/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java @@ -489,7 +489,7 @@ void overrideTypeSpecificDecoder() throws Throwable { final TestInterfaceAsync api = new TestInterfaceAsyncBuilder() - .decoder((response, type) -> "fail") + .decoder((_, _) -> "fail") .target("http://localhost:" + server.getPort()); assertThat(unwrap(api.post())).isEqualTo("fail"); @@ -502,7 +502,7 @@ void doesntRetryAfterResponseIsSent() throws Throwable { final TestInterfaceAsync api = new TestInterfaceAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target("http://localhost:" + server.getPort()); @@ -520,7 +520,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { final TestInterfaceAsync api = AsyncFeign.builder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); @@ -545,7 +545,7 @@ void throwsFeignExceptionWithoutBody() { final TestInterfaceAsync api = AsyncFeign.builder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); @@ -578,7 +578,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { // fake client as Client.Default follows redirects. final TestInterfaceAsync api = AsyncFeign.builder() - .client(new AsyncClient.Default<>((request, options) -> response, execs)) + .client(new AsyncClient.Default<>((_, _) -> response, execs)) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); assertThat(unwrap(api.response()).headers()) @@ -598,7 +598,7 @@ void okIfDecodeRootCauseHasNoMessage() throws Throwable { final TestInterfaceAsync api = new TestInterfaceAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -614,7 +614,7 @@ void decodingExceptionGetWrappedInDismiss404Mode() throws Throwable { new TestInterfaceAsyncBuilder() .dismiss404() .decoder( - (response, type) -> { + (response, _) -> { assertThat(response.status()).isEqualTo(404); throw new NoSuchElementException(); }) @@ -651,7 +651,7 @@ void okIfEncodeRootCauseHasNoMessage() throws Throwable { final TestInterfaceAsync api = new TestInterfaceAsyncBuilder() .encoder( - (object, bodyType, template) -> { + (_, _, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -754,7 +754,7 @@ void responseMapperIsAppliedBeforeDelegate() throws IOException { } private ResponseMapper upperCaseResponseMapper() { - return (response, type) -> { + return (response, _) -> { try { return response.toBuilder() .body(Util.toString(response.body().asReader()).toUpperCase().getBytes()) @@ -1079,7 +1079,7 @@ static final class TestInterfaceAsyncBuilder { .client(new AsyncApacheHttp5Client()) .decoder(new Decoder.Default()) .encoder( - (object, bodyType, template) -> { + (object, _, template) -> { if (object instanceof Map) { template.body(new Gson().toJson(object)); } else { diff --git a/hystrix/src/test/java/feign/hystrix/HystrixBuilderTest.java b/hystrix/src/test/java/feign/hystrix/HystrixBuilderTest.java index ed03c7af1f..5b48d7b2fd 100644 --- a/hystrix/src/test/java/feign/hystrix/HystrixBuilderTest.java +++ b/hystrix/src/test/java/feign/hystrix/HystrixBuilderTest.java @@ -170,7 +170,7 @@ void errorInFallbackHasExpectedBehavior() { server.enqueue(new MockResponse().setResponseCode(500)); final GitHub fallback = - (owner, repo) -> { + (_, _) -> { throw new RuntimeException("oops"); }; @@ -223,7 +223,7 @@ void rxObservable() { final TestSubscriber testSubscriber = new TestSubscriber<>(); observable.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).isEqualTo("foo"); + assertThat(testSubscriber.getOnNextEvents().getFirst()).isEqualTo("foo"); } @Test @@ -240,7 +240,7 @@ void rxObservableFallback() { final TestSubscriber testSubscriber = new TestSubscriber<>(); observable.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).isEqualTo("fallback"); + assertThat(testSubscriber.getOnNextEvents().getFirst()).isEqualTo("fallback"); } @Test @@ -257,7 +257,7 @@ void rxObservableInt() { final TestSubscriber testSubscriber = new TestSubscriber<>(); observable.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).isEqualTo(Integer.valueOf(1)); + assertThat(testSubscriber.getOnNextEvents().getFirst()).isEqualTo(Integer.valueOf(1)); } @Test @@ -274,7 +274,7 @@ void rxObservableIntFallback() { final TestSubscriber testSubscriber = new TestSubscriber<>(); observable.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).isEqualTo(Integer.valueOf(0)); + assertThat(testSubscriber.getOnNextEvents().getFirst()).isEqualTo(Integer.valueOf(0)); } @Test @@ -291,7 +291,7 @@ void rxObservableList() { final TestSubscriber> testSubscriber = new TestSubscriber<>(); observable.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).containsExactly("foo", "bar"); + assertThat(testSubscriber.getOnNextEvents().getFirst()).containsExactly("foo", "bar"); } @Test @@ -308,7 +308,7 @@ void rxObservableListFall() { final TestSubscriber> testSubscriber = new TestSubscriber<>(); observable.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).containsExactly("fallback"); + assertThat(testSubscriber.getOnNextEvents().getFirst()).containsExactly("fallback"); } @Test @@ -327,7 +327,7 @@ void rxObservableListFall_noFallback() { testSubscriber.awaitTerminalEvent(); assertThat(testSubscriber.getOnNextEvents()).isEmpty(); - assertThat(testSubscriber.getOnErrorEvents().get(0)) + assertThat(testSubscriber.getOnErrorEvents().getFirst()) .isInstanceOf(HystrixRuntimeException.class) .hasMessage("TestInterface#listObservable() failed and no fallback available."); } @@ -346,7 +346,7 @@ void rxSingle() { final TestSubscriber testSubscriber = new TestSubscriber<>(); single.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).isEqualTo("foo"); + assertThat(testSubscriber.getOnNextEvents().getFirst()).isEqualTo("foo"); } @Test @@ -363,7 +363,7 @@ void rxSingleFallback() { final TestSubscriber testSubscriber = new TestSubscriber<>(); single.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).isEqualTo("fallback"); + assertThat(testSubscriber.getOnNextEvents().getFirst()).isEqualTo("fallback"); } @Test @@ -380,7 +380,7 @@ void rxSingleInt() { final TestSubscriber testSubscriber = new TestSubscriber<>(); single.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).isEqualTo(Integer.valueOf(1)); + assertThat(testSubscriber.getOnNextEvents().getFirst()).isEqualTo(Integer.valueOf(1)); } @Test @@ -397,7 +397,7 @@ void rxSingleIntFallback() { final TestSubscriber testSubscriber = new TestSubscriber<>(); single.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).isEqualTo(Integer.valueOf(0)); + assertThat(testSubscriber.getOnNextEvents().getFirst()).isEqualTo(Integer.valueOf(0)); } @Test @@ -414,7 +414,7 @@ void rxSingleList() { final TestSubscriber> testSubscriber = new TestSubscriber<>(); single.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).containsExactly("foo", "bar"); + assertThat(testSubscriber.getOnNextEvents().getFirst()).containsExactly("foo", "bar"); } @Test @@ -431,7 +431,7 @@ void rxSingleListFallback() { final TestSubscriber> testSubscriber = new TestSubscriber<>(); single.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(); - assertThat(testSubscriber.getOnNextEvents().get(0)).containsExactly("fallback"); + assertThat(testSubscriber.getOnNextEvents().getFirst()).containsExactly("fallback"); } @Test diff --git a/jackson-jr/src/test/java/feign/jackson/jr/examples/GitHubExample.java b/jackson-jr/src/test/java/feign/jackson/jr/examples/GitHubExample.java index f33abb4e5e..604203f5dd 100644 --- a/jackson-jr/src/test/java/feign/jackson/jr/examples/GitHubExample.java +++ b/jackson-jr/src/test/java/feign/jackson/jr/examples/GitHubExample.java @@ -30,10 +30,10 @@ public static void main(String... args) { .decoder(new JacksonJrDecoder()) .target(GitHub.class, "https://api.github.com"); - System.out.println("Let's fetch and print a list of the contributors to this library."); + IO.println("Let's fetch and print a list of the contributors to this library."); List contributors = github.contributors("netflix", "feign"); for (Contributor contributor : contributors) { - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } } diff --git a/jackson/src/test/java/feign/jackson/examples/GitHubExample.java b/jackson/src/test/java/feign/jackson/examples/GitHubExample.java index 6f16cd6b5f..e7017576e2 100644 --- a/jackson/src/test/java/feign/jackson/examples/GitHubExample.java +++ b/jackson/src/test/java/feign/jackson/examples/GitHubExample.java @@ -30,10 +30,10 @@ public static void main(String... args) { .decoder(new JacksonDecoder()) .target(GitHub.class, "https://api.github.com"); - System.out.println("Let's fetch and print a list of the contributors to this library."); + IO.println("Let's fetch and print a list of the contributors to this library."); List contributors = github.contributors("netflix", "feign"); for (Contributor contributor : contributors) { - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } } diff --git a/jackson/src/test/java/feign/jackson/examples/GitHubIteratorExample.java b/jackson/src/test/java/feign/jackson/examples/GitHubIteratorExample.java index 4d3a6962d3..bd5a3987c8 100644 --- a/jackson/src/test/java/feign/jackson/examples/GitHubIteratorExample.java +++ b/jackson/src/test/java/feign/jackson/examples/GitHubIteratorExample.java @@ -33,12 +33,12 @@ public static void main(String... args) throws IOException { .doNotCloseAfterDecode() .target(GitHub.class, "https://api.github.com"); - System.out.println("Let's fetch and print a list of the contributors to this library."); + IO.println("Let's fetch and print a list of the contributors to this library."); Iterator contributors = github.contributors("OpenFeign", "feign"); try { while (contributors.hasNext()) { Contributor contributor = contributors.next(); - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } } finally { ((Closeable) contributors).close(); diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java index 52b177733c..680276e57c 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java @@ -484,9 +484,7 @@ void overrideTypeSpecificDecoder() throws Throwable { server.enqueue(new MockResponse().setBody("success!")); final TestInterfaceAsync api = - newAsyncBuilder() - .decoder((response, type) -> "fail") - .target("http://localhost:" + server.getPort()); + newAsyncBuilder().decoder((_, _) -> "fail").target("http://localhost:" + server.getPort()); assertThat(unwrap(api.post())).isEqualTo("fail"); } @@ -498,7 +496,7 @@ void doesntRetryAfterResponseIsSent() throws Throwable { final TestInterfaceAsync api = newAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target("http://localhost:" + server.getPort()); @@ -516,7 +514,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { final TestInterfaceAsync api = newAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target("http://localhost:" + server.getPort()); @@ -541,7 +539,7 @@ void throwsFeignExceptionWithoutBody() { final TestInterfaceAsync api = newAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target("http://localhost:" + server.getPort()); @@ -574,7 +572,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { // fake client as Client.Default follows redirects. final TestInterfaceAsync api = AsyncFeign.builder() - .client(new AsyncClient.Default<>((request, options) -> response, execs)) + .client(new AsyncClient.Default<>((_, _) -> response, execs)) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); assertThat(unwrap(api.response()).headers().get("Location")).contains("http://bar.com"); @@ -589,7 +587,7 @@ void okIfDecodeRootCauseHasNoMessage() throws Throwable { final TestInterfaceAsync api = newAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -605,7 +603,7 @@ void decodingExceptionGetWrappedInDismiss404Mode() throws Throwable { newAsyncBuilder() .dismiss404() .decoder( - (response, type) -> { + (response, _) -> { assertEquals(404, response.status()); throw new NoSuchElementException(); }) @@ -642,7 +640,7 @@ void okIfEncodeRootCauseHasNoMessage() throws Throwable { final TestInterfaceAsync api = newAsyncBuilder() .encoder( - (object, bodyType, template) -> { + (_, _, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -753,7 +751,7 @@ private static TestInterfaceAsyncBuilder newAsyncBuilder() { } private ResponseMapper upperCaseResponseMapper() { - return (response, type) -> { + return (response, _) -> { try { return response.toBuilder() .body(Util.toString(response.body().asReader()).toUpperCase().getBytes()) @@ -1025,7 +1023,7 @@ static final class TestInterfaceAsyncBuilder { .client(new Http2Client()) .decoder(new Decoder.Default()) .encoder( - (object, bodyType, template) -> { + (object, _, template) -> { if (object instanceof Map) { template.body(new Gson().toJson(object)); } else { diff --git a/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java b/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java index 77acd51a0d..d79d3c4725 100644 --- a/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java +++ b/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java @@ -350,7 +350,7 @@ void decodesIgnoringErrorsWithEventHandler() throws Exception { JAXBContextFactory factory = new JAXBContextFactory.Builder() .withUnmarshallerSchema(getMockIntObjSchema()) - .withUnmarshallerEventHandler(event -> true) + .withUnmarshallerEventHandler(_ -> true) .build(); assertThat(new JAXBDecoder(factory).decode(response, MockIntObject.class)) .isEqualTo(new MockIntObject()); @@ -378,7 +378,7 @@ void encodesIgnoringErrorsWithEventHandler() throws Exception { JAXBContextFactory jaxbContextFactory = new JAXBContextFactory.Builder() .withMarshallerSchema(getMockIntObjSchema()) - .withMarshallerEventHandler(event -> true) + .withMarshallerEventHandler(_ -> true) .build(); Encoder encoder = new JAXBEncoder(jaxbContextFactory); diff --git a/jaxb-jakarta/src/test/java/feign/jaxb/JAXBContextFactoryTest.java b/jaxb-jakarta/src/test/java/feign/jaxb/JAXBContextFactoryTest.java index 14c12216b8..e3301ec767 100644 --- a/jaxb-jakarta/src/test/java/feign/jaxb/JAXBContextFactoryTest.java +++ b/jaxb-jakarta/src/test/java/feign/jaxb/JAXBContextFactoryTest.java @@ -106,7 +106,7 @@ void buildsUnmarshallerWithSchema() throws Exception { @Test void buildsMarshallerWithCustomEventHandler() throws Exception { - ValidationEventHandler handler = event -> false; + ValidationEventHandler handler = _ -> false; JAXBContextFactory factory = new JAXBContextFactory.Builder().withMarshallerEventHandler(handler).build(); @@ -124,7 +124,7 @@ void buildsMarshallerWithDefaultEventHandler() throws Exception { @Test void buildsUnmarshallerWithCustomEventHandler() throws Exception { - ValidationEventHandler handler = event -> false; + ValidationEventHandler handler = _ -> false; JAXBContextFactory factory = new JAXBContextFactory.Builder().withUnmarshallerEventHandler(handler).build(); diff --git a/jaxb-jakarta/src/test/java/feign/jaxb/examples/IAMExample.java b/jaxb-jakarta/src/test/java/feign/jaxb/examples/IAMExample.java index e042758553..d62cef3650 100644 --- a/jaxb-jakarta/src/test/java/feign/jaxb/examples/IAMExample.java +++ b/jaxb-jakarta/src/test/java/feign/jaxb/examples/IAMExample.java @@ -37,7 +37,7 @@ public static void main(String... args) { .target(new IAMTarget(args[0], args[1])); GetUserResponse response = iam.userResponse(); - System.out.println("UserId: " + response.result.user.id); + IO.println("UserId: " + response.result.user.id); } interface IAM { diff --git a/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java b/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java index fa375e3114..464d857b8c 100644 --- a/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java +++ b/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java @@ -350,7 +350,7 @@ void decodesIgnoringErrorsWithEventHandler() throws Exception { JAXBContextFactory factory = new JAXBContextFactory.Builder() .withUnmarshallerSchema(getMockIntObjSchema()) - .withUnmarshallerEventHandler(event -> true) + .withUnmarshallerEventHandler(_ -> true) .build(); assertThat(new JAXBDecoder(factory).decode(response, MockIntObject.class)) .isEqualTo(new MockIntObject()); @@ -379,7 +379,7 @@ void encodesIgnoringErrorsWithEventHandler() throws Exception { JAXBContextFactory jaxbContextFactory = new JAXBContextFactory.Builder() .withMarshallerSchema(getMockIntObjSchema()) - .withMarshallerEventHandler(event -> true) + .withMarshallerEventHandler(_ -> true) .build(); Encoder encoder = new JAXBEncoder(jaxbContextFactory); diff --git a/jaxb/src/test/java/feign/jaxb/JAXBContextFactoryTest.java b/jaxb/src/test/java/feign/jaxb/JAXBContextFactoryTest.java index 5d4ab4d87d..baee12e45f 100644 --- a/jaxb/src/test/java/feign/jaxb/JAXBContextFactoryTest.java +++ b/jaxb/src/test/java/feign/jaxb/JAXBContextFactoryTest.java @@ -106,7 +106,7 @@ void buildsUnmarshallerWithSchema() throws Exception { @Test void buildsMarshallerWithCustomEventHandler() throws Exception { - ValidationEventHandler handler = event -> false; + ValidationEventHandler handler = _ -> false; JAXBContextFactory factory = new JAXBContextFactory.Builder().withMarshallerEventHandler(handler).build(); @@ -124,7 +124,7 @@ void buildsMarshallerWithDefaultEventHandler() throws Exception { @Test void buildsUnmarshallerWithCustomEventHandler() throws Exception { - ValidationEventHandler handler = event -> false; + ValidationEventHandler handler = _ -> false; JAXBContextFactory factory = new JAXBContextFactory.Builder().withUnmarshallerEventHandler(handler).build(); diff --git a/jaxb/src/test/java/feign/jaxb/examples/IAMExample.java b/jaxb/src/test/java/feign/jaxb/examples/IAMExample.java index 53ea7d30df..d73a4a25bf 100644 --- a/jaxb/src/test/java/feign/jaxb/examples/IAMExample.java +++ b/jaxb/src/test/java/feign/jaxb/examples/IAMExample.java @@ -37,7 +37,7 @@ public static void main(String... args) { .target(new IAMTarget(args[0], args[1])); GetUserResponse response = iam.userResponse(); - System.out.println("UserId: " + response.result.user.id); + IO.println("UserId: " + response.result.user.id); } interface IAM { diff --git a/jaxrs/src/test/java/feign/jaxrs/examples/GitHubExample.java b/jaxrs/src/test/java/feign/jaxrs/examples/GitHubExample.java index c579a1482f..f8e167af1e 100644 --- a/jaxrs/src/test/java/feign/jaxrs/examples/GitHubExample.java +++ b/jaxrs/src/test/java/feign/jaxrs/examples/GitHubExample.java @@ -31,10 +31,10 @@ public static void main(String... args) throws InterruptedException { .contract(new JAXRSContract()) .target(GitHub.class, "https://api.github.com"); - System.out.println("Let's fetch and print a list of the contributors to this library."); + IO.println("Let's fetch and print a list of the contributors to this library."); List contributors = github.contributors("netflix", "feign"); for (Contributor contributor : contributors) { - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } } diff --git a/jaxrs2/src/test/java/feign/jaxrs2/AbstractJAXRSClientTest.java b/jaxrs2/src/test/java/feign/jaxrs2/AbstractJAXRSClientTest.java index aaace9106f..21936f0e09 100644 --- a/jaxrs2/src/test/java/feign/jaxrs2/AbstractJAXRSClientTest.java +++ b/jaxrs2/src/test/java/feign/jaxrs2/AbstractJAXRSClientTest.java @@ -39,7 +39,7 @@ public abstract class AbstractJAXRSClientTest extends AbstractClientTest { public void patch() throws Exception { try { super.patch(); - } catch (final RuntimeException e) { + } catch (final RuntimeException _) { Assumptions.assumeFalse(false, "JaxRS client do not support PATCH requests"); } } @@ -48,7 +48,7 @@ public void patch() throws Exception { public void noResponseBodyForPut() throws Exception { try { super.noResponseBodyForPut(); - } catch (final IllegalStateException e) { + } catch (final IllegalStateException _) { Assumptions.assumeFalse(false, "JaxRS client do not support empty bodies on PUT"); } } @@ -57,7 +57,7 @@ public void noResponseBodyForPut() throws Exception { public void noResponseBodyForPatch() { try { super.noResponseBodyForPatch(); - } catch (final IllegalStateException e) { + } catch (final IllegalStateException _) { Assumptions.assumeFalse(false, "JaxRS client do not support PATCH requests"); } } diff --git a/json/src/test/java/feign/json/examples/GitHubExample.java b/json/src/test/java/feign/json/examples/GitHubExample.java index 4b122a852a..aca185a5ef 100644 --- a/json/src/test/java/feign/json/examples/GitHubExample.java +++ b/json/src/test/java/feign/json/examples/GitHubExample.java @@ -35,11 +35,11 @@ public static void main(String... args) { GitHub github = Feign.builder().decoder(new JsonDecoder()).target(GitHub.class, "https://api.github.com"); - System.out.println("Let's fetch and print a list of the contributors to this library."); + IO.println("Let's fetch and print a list of the contributors to this library."); JSONArray contributors = github.contributors("netflix", "feign"); contributors.forEach( contributor -> { - System.out.println(((JSONObject) contributor).getString("login")); + IO.println(((JSONObject) contributor).getString("login")); }); } } diff --git a/micrometer/src/test/java/feign/micrometer/AbstractMetricsTestBase.java b/micrometer/src/test/java/feign/micrometer/AbstractMetricsTestBase.java index 36663d7ab5..9f55299c40 100644 --- a/micrometer/src/test/java/feign/micrometer/AbstractMetricsTestBase.java +++ b/micrometer/src/test/java/feign/micrometer/AbstractMetricsTestBase.java @@ -159,7 +159,7 @@ void clientPropagatesUncheckedException() { customizeBuilder( Feign.builder() .client( - (request, options) -> { + (request, _) -> { notFound.set(new FeignException.NotFound("test", request, null, null)); throw notFound.get(); }) @@ -196,7 +196,7 @@ void decoderPropagatesUncheckedException() { Feign.builder() .client(new MockClient().ok(HttpMethod.GET, "/get", "1234567890abcde")) .decoder( - (response, type) -> { + (response, _) -> { notFound.set( new FeignException.NotFound("test", response.request(), null, null)); throw notFound.get(); @@ -215,7 +215,7 @@ void shouldMetricCollectionWithCustomException() { customizeBuilder( Feign.builder() .client( - (request, options) -> { + (_, _) -> { throw new RuntimeException("Test error"); }) .addCapability(createMetricCapability())) @@ -304,7 +304,7 @@ void decoderExceptionCounterHasUriLabelWithPathExpression() { Feign.builder() .client(new MockClient().ok(HttpMethod.GET, "/get/123", "1234567890abcde")) .decoder( - (response, type) -> { + (response, _) -> { notFound.set( new FeignException.NotFound("test", response.request(), null, null)); throw notFound.get(); diff --git a/moshi/src/test/java/feign/moshi/examples/GithubExample.java b/moshi/src/test/java/feign/moshi/examples/GithubExample.java index 0c93d744e5..b1e5e2c049 100644 --- a/moshi/src/test/java/feign/moshi/examples/GithubExample.java +++ b/moshi/src/test/java/feign/moshi/examples/GithubExample.java @@ -31,10 +31,10 @@ public static void main(String... args) { .decoder(new MoshiDecoder()) .target(GitHub.class, "https://api.github.com"); - System.out.println("Let's fetch and print a list of the contributors to this library."); + IO.println("Let's fetch and print a list of the contributors to this library."); List contributors = github.contributors("netflix", "feign"); for (Contributor contributor : contributors) { - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } } diff --git a/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java b/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java index a268c76105..a4ff3a5485 100644 --- a/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java +++ b/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java @@ -483,9 +483,7 @@ void overrideTypeSpecificDecoder() throws Throwable { server.enqueue(new MockResponse().setBody("success!")); final TestInterfaceAsync api = - newAsyncBuilder() - .decoder((response, type) -> "fail") - .target("http://localhost:" + server.getPort()); + newAsyncBuilder().decoder((_, _) -> "fail").target("http://localhost:" + server.getPort()); assertThat(unwrap(api.post())).isEqualTo("fail"); } @@ -497,7 +495,7 @@ void doesntRetryAfterResponseIsSent() throws Throwable { final TestInterfaceAsync api = newAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target("http://localhost:" + server.getPort()); @@ -515,7 +513,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { final TestInterfaceAsync api = newAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target("http://localhost:" + server.getPort()); @@ -540,7 +538,7 @@ void throwsFeignExceptionWithoutBody() { final TestInterfaceAsync api = newAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new IOException("timeout"); }) .target("http://localhost:" + server.getPort()); @@ -573,7 +571,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { // fake client as Client.Default follows redirects. final TestInterfaceAsync api = AsyncFeign.builder() - .client(new AsyncClient.Default<>((request, options) -> response, execs)) + .client(new AsyncClient.Default<>((_, _) -> response, execs)) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); assertThat(unwrap(api.response()).headers().get("Location")).contains("http://bar.com"); @@ -588,7 +586,7 @@ void okIfDecodeRootCauseHasNoMessage() throws Throwable { final TestInterfaceAsync api = newAsyncBuilder() .decoder( - (response, type) -> { + (_, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -604,7 +602,7 @@ void decodingExceptionGetWrappedInDismiss404Mode() throws Throwable { newAsyncBuilder() .dismiss404() .decoder( - (response, type) -> { + (response, _) -> { assertEquals(404, response.status()); throw new NoSuchElementException(); }) @@ -641,7 +639,7 @@ void okIfEncodeRootCauseHasNoMessage() throws Throwable { final TestInterfaceAsync api = newAsyncBuilder() .encoder( - (object, bodyType, template) -> { + (_, _, _) -> { throw new RuntimeException(); }) .target("http://localhost:" + server.getPort()); @@ -752,7 +750,7 @@ private static TestInterfaceAsyncBuilder newAsyncBuilder() { } private ResponseMapper upperCaseResponseMapper() { - return (response, type) -> { + return (response, _) -> { try { return response.toBuilder() .body(Util.toString(response.body().asReader()).toUpperCase().getBytes()) @@ -1024,7 +1022,7 @@ static final class TestInterfaceAsyncBuilder { .client(new OkHttpClient()) .decoder(new Decoder.Default()) .encoder( - (object, bodyType, template) -> { + (object, _, template) -> { if (object instanceof Map) { template.body(new Gson().toJson(object)); } else { diff --git a/pom.xml b/pom.xml index 1e392888f3..90da33c8e8 100644 --- a/pom.xml +++ b/pom.xml @@ -152,7 +152,7 @@ 1.8 - 21 + 25 ${main.java.version} @@ -655,6 +655,7 @@ true -parameters + -proc:full ${latest.java.version} ${latest.java.version} @@ -1120,7 +1121,7 @@ org.openrewrite.java.testing.junit5.AssertToAssertions org.openrewrite.java.testing.assertj.JUnitToAssertj org.openrewrite.java.testing.assertj.Assertj - org.openrewrite.java.migrate.UpgradeToJava21 + org.openrewrite.java.migrate.UpgradeToJava25 **/src/main/java/** diff --git a/reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java b/reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java index 482ca09c80..7e583f0986 100644 --- a/reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java +++ b/reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java @@ -134,7 +134,7 @@ void reactorTargetFull() throws Exception { StepVerifier.create(service.usersMono()) .assertNext( - users -> assertThat(users.get(0)).hasFieldOrPropertyWithValue("username", "test")) + users -> assertThat(users.getFirst()).hasFieldOrPropertyWithValue("username", "test")) .expectComplete() .verify(); assertThat(webServer.takeRequest().getPath()).isEqualToIgnoringCase("/users"); @@ -167,7 +167,7 @@ void rxJavaTarget() throws Exception { StepVerifier.create(service.users()) .assertNext( - users -> assertThat(users.get(0)).hasFieldOrPropertyWithValue("username", "test")) + users -> assertThat(users.getFirst()).hasFieldOrPropertyWithValue("username", "test")) .expectComplete() .verify(); assertThat(webServer.takeRequest().getPath()).isEqualToIgnoringCase("/users"); @@ -179,7 +179,7 @@ void invocationFactoryIsNotSupported() { .isThrownBy( () -> { ReactorFeign.builder() - .invocationHandlerFactory((target, dispatch) -> null) + .invocationHandlerFactory((_, _) -> null) .target(TestReactiveXService.class, "http://localhost"); }); } @@ -399,7 +399,7 @@ public String query() { public static class ConsoleLogger extends Logger { @Override protected void log(String configKey, String format, Object... args) { - System.out.println(String.format(methodTag(configKey) + format, args)); + IO.println(String.format(methodTag(configKey) + format, args)); } } diff --git a/reactive/src/test/java/feign/reactive/examples/ConsoleLogger.java b/reactive/src/test/java/feign/reactive/examples/ConsoleLogger.java index fd0d0c274b..4f27d1c317 100644 --- a/reactive/src/test/java/feign/reactive/examples/ConsoleLogger.java +++ b/reactive/src/test/java/feign/reactive/examples/ConsoleLogger.java @@ -20,6 +20,6 @@ public class ConsoleLogger extends Logger { @Override protected void log(String configKey, String format, Object... args) { - System.out.println(String.format(methodTag(configKey) + format, args)); + IO.println(String.format(methodTag(configKey) + format, args)); } } diff --git a/reactive/src/test/java/feign/reactive/examples/ReactorGitHubExample.java b/reactive/src/test/java/feign/reactive/examples/ReactorGitHubExample.java index 700f0736fa..aae9d56109 100644 --- a/reactive/src/test/java/feign/reactive/examples/ReactorGitHubExample.java +++ b/reactive/src/test/java/feign/reactive/examples/ReactorGitHubExample.java @@ -36,19 +36,17 @@ public static void main(String... args) { .logLevel(Logger.Level.FULL) .target(GitHub.class, "https://api.github.com"); - System.out.println( - "Let's fetch and print a list of the contributors to this library (Using Flux)."); + IO.println("Let's fetch and print a list of the contributors to this library (Using Flux)."); List contributorsFromFlux = github.contributorsFlux("OpenFeign", "feign").collectList().block(); for (Contributor contributor : contributorsFromFlux) { - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } - System.out.println( - "Let's fetch and print a list of the contributors to this library (Using Mono)."); + IO.println("Let's fetch and print a list of the contributors to this library (Using Mono)."); List contributorsFromMono = github.contributorsMono("OpenFeign", "feign").block(); for (Contributor contributor : contributorsFromMono) { - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } } diff --git a/reactive/src/test/java/feign/reactive/examples/RxJavaGitHubExample.java b/reactive/src/test/java/feign/reactive/examples/RxJavaGitHubExample.java index 960b9826be..f3631a5263 100644 --- a/reactive/src/test/java/feign/reactive/examples/RxJavaGitHubExample.java +++ b/reactive/src/test/java/feign/reactive/examples/RxJavaGitHubExample.java @@ -35,11 +35,11 @@ public static void main(String... args) { .logLevel(Logger.Level.FULL) .target(GitHub.class, "https://api.github.com"); - System.out.println("Let's fetch and print a list of the contributors to this library."); + IO.println("Let's fetch and print a list of the contributors to this library."); List contributorsFromFlux = github.contributors("OpenFeign", "feign").blockingLast(); for (Contributor contributor : contributorsFromFlux) { - System.out.println(contributor.login + " (" + contributor.contributions + ")"); + IO.println(contributor.login + " (" + contributor.contributions + ")"); } } diff --git a/ribbon/src/test/java/feign/ribbon/LBClientTest.java b/ribbon/src/test/java/feign/ribbon/LBClientTest.java index 14f0d96bc2..ad29059cbe 100644 --- a/ribbon/src/test/java/feign/ribbon/LBClientTest.java +++ b/ribbon/src/test/java/feign/ribbon/LBClientTest.java @@ -58,8 +58,8 @@ void ribbonRequest() throws URISyntaxException { // test that requestOrigin and requestRecreate are same except the header 'Content-Length' // ps, requestOrigin and requestRecreate won't be null assertThat(requestOrigin.toString()) - .contains(String.format("%s %s HTTP/1.1\n", method, urlWithEncodedJson)); + .contains("%s %s HTTP/1.1\n".formatted(method, urlWithEncodedJson)); assertThat(requestRecreate.toString()) - .contains(String.format("%s %s HTTP/1.1\nContent-Length: 0\n", method, urlWithEncodedJson)); + .contains("%s %s HTTP/1.1\nContent-Length: 0\n".formatted(method, urlWithEncodedJson)); } } diff --git a/ribbon/src/test/java/feign/ribbon/RibbonClientTest.java b/ribbon/src/test/java/feign/ribbon/RibbonClientTest.java index d725ec595a..eefe1d5d20 100644 --- a/ribbon/src/test/java/feign/ribbon/RibbonClientTest.java +++ b/ribbon/src/test/java/feign/ribbon/RibbonClientTest.java @@ -139,7 +139,7 @@ void ioExceptionFailsAfterTooManyFailures() throws IOException, InterruptedExcep try { api.post(); fail("No exception thrown"); - } catch (RetryableException ignored) { + } catch (RetryableException _) { } // TODO: why are these retrying? @@ -170,7 +170,7 @@ void ribbonRetryConfigurationOnSameServer() throws IOException, InterruptedExcep try { api.post(); fail("No exception thrown"); - } catch (RetryableException ignored) { + } catch (RetryableException _) { } assertThat(server1.getRequestCount() >= 2 || server2.getRequestCount() >= 2).isTrue(); @@ -201,7 +201,7 @@ void ribbonRetryConfigurationOnMultipleServers() throws IOException, Interrupted try { api.post(); fail("No exception thrown"); - } catch (RetryableException ignored) { + } catch (RetryableException _) { } assertThat(server1.getRequestCount()).isGreaterThanOrEqualTo(1); @@ -298,7 +298,7 @@ void ribbonRetryOnStatusCodes() throws IOException, InterruptedException { try { api.post(); fail("No exception thrown"); - } catch (Exception ignored) { + } catch (Exception _) { } assertThat(server1.getRequestCount()).isEqualTo(1); diff --git a/sax/src/test/java/feign/sax/SAXDecoderTest.java b/sax/src/test/java/feign/sax/SAXDecoderTest.java index 16ece9f2c3..21fdc29890 100644 --- a/sax/src/test/java/feign/sax/SAXDecoderTest.java +++ b/sax/src/test/java/feign/sax/SAXDecoderTest.java @@ -112,7 +112,7 @@ void notFoundDecodesToEmpty() throws Exception { static enum NetworkStatus { GOOD, - FAILED; + FAILED } static class NetworkStatusStringHandler extends DefaultHandler diff --git a/sax/src/test/java/feign/sax/examples/IAMExample.java b/sax/src/test/java/feign/sax/examples/IAMExample.java index cc4be444a1..5b2527cdb0 100644 --- a/sax/src/test/java/feign/sax/examples/IAMExample.java +++ b/sax/src/test/java/feign/sax/examples/IAMExample.java @@ -30,7 +30,7 @@ public static void main(String... args) { Feign.builder() // .decoder(SAXDecoder.builder().registerContentHandler(UserIdHandler.class).build()) // .target(new IAMTarget(args[0], args[1])); - System.out.println(iam.userId()); + IO.println(iam.userId()); } interface IAM { diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/AbstractClientReconnectTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/AbstractClientReconnectTest.java index 9f9a809ac6..5419ce504a 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/AbstractClientReconnectTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/AbstractClientReconnectTest.java @@ -112,9 +112,7 @@ void allRequestsShouldBeAnswered(VertxTestContext testContext) { CompositeFuture sendRequests(int requests) { List> requestList = - IntStream.range(0, requests) - .mapToObj(ignored -> client.hello()) - .collect(Collectors.toList()); + IntStream.range(0, requests).mapToObj(_ -> client.hello()).collect(Collectors.toList()); return Future.all(requestList); } diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java b/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java index 4d236f1cbc..dae2645f3e 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java @@ -112,11 +112,11 @@ void http2NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { void assertNotLeaks( HelloServiceAPI client, VertxTestContext testContext, int nbRequests, int poolSize) { List> futures = - IntStream.range(0, nbRequests).mapToObj(ignored -> client.hello()).collect(toList()); + IntStream.range(0, nbRequests).mapToObj(_ -> client.hello()).collect(toList()); Future.all(futures) .onComplete( - ignored -> + _ -> testContext.verify( () -> { try { diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/TestUtils.java b/vertx/feign-vertx/src/test/java/feign/vertx/TestUtils.java index 96b4779d05..9ecd178a1b 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/TestUtils.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/TestUtils.java @@ -29,7 +29,7 @@ public class TestUtils { public static String encodeAsJsonString(final Object object) { try { return MAPPER.writeValueAsString(object); - } catch (JsonProcessingException unexpectedException) { + } catch (JsonProcessingException _) { return ""; } } diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/OrderGenerator.java b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/OrderGenerator.java index e411b18cdd..176d96642b 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/OrderGenerator.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/testcase/domain/OrderGenerator.java @@ -34,9 +34,9 @@ public IceCreamOrder generate() { final int nbBalls = peekBallsNumber(); final int nbMixins = peekMixinNumber(); - IntStream.rangeClosed(1, nbBalls).mapToObj(i -> this.peekFlavor()).forEach(order::addBall); + IntStream.rangeClosed(1, nbBalls).mapToObj(_ -> this.peekFlavor()).forEach(order::addBall); - IntStream.rangeClosed(1, nbMixins).mapToObj(i -> this.peekMixin()).forEach(order::addMixin); + IntStream.rangeClosed(1, nbMixins).mapToObj(_ -> this.peekMixin()).forEach(order::addMixin); return order; } diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/AbstractClientReconnectTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/AbstractClientReconnectTest.java index 169d49dfc0..4a09259ce9 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/AbstractClientReconnectTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/AbstractClientReconnectTest.java @@ -112,9 +112,7 @@ void allRequestsShouldBeAnswered(VertxTestContext testContext) { CompositeFuture sendRequests(int requests) { List requestList = - IntStream.range(0, requests) - .mapToObj(ignored -> client.hello()) - .collect(Collectors.toList()); + IntStream.range(0, requests).mapToObj(_ -> client.hello()).collect(Collectors.toList()); return CompositeFuture.all(requestList); } diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java index cc67db08c0..15669e2c7f 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java @@ -115,11 +115,11 @@ void http2NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { void assertNotLeaks( HelloServiceAPI client, VertxTestContext testContext, int nbRequests, int poolSize) { List futures = - IntStream.range(0, nbRequests).mapToObj(ignored -> client.hello()).collect(toList()); + IntStream.range(0, nbRequests).mapToObj(_ -> client.hello()).collect(toList()); CompositeFuture.all(futures) .onComplete( - ignored -> + _ -> testContext.verify( () -> { try { From b2e8e673334458bfc41b2e04918f7e913d378254 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 6 Feb 2026 13:47:33 -0300 Subject: [PATCH 350/615] Remove easy-jacoco-maven-plugin Signed-off-by: Marvin Froeder --- .mvn/extensions.xml | 5 ----- pom.xml | 30 ------------------------------ 2 files changed, 35 deletions(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 94c59b51ea..be94d013ac 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -26,9 +26,4 @@ common-custom-user-data-maven-extension 2.1.0 - - com.marvinformatics.jacoco - easy-jacoco-maven-plugin - 0.1.4 - diff --git a/pom.xml b/pom.xml index 90da33c8e8..bff68dcca5 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,6 @@ 1.2.8 4.0.0 0.8.14 - 0.1.4 6.28.1 3.26.0 3.26.0 @@ -926,35 +925,6 @@ - - com.marvinformatics.jacoco - easy-jacoco-maven-plugin - ${easy-jacoco-maven-plugin.version} - - - - - - INSTRUCTION - COVEREDRATIO - 0.70 - - - - - true - - true - - - feign/** - - - feign-benchmark - feign-apt-test-generator - - - From bce0b28fc0791bf4e95edd6a792e56be583be2b4 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 6 Feb 2026 13:58:10 -0300 Subject: [PATCH 351/615] Remove jacoco and parallel build flag Signed-off-by: Marvin Froeder --- .circleci/config.yml | 4 ++-- pom.xml | 13 +------------ 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b0ba8a6ada..08b806e783 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -92,7 +92,7 @@ commands: - run: name: 'Configure GPG keys' command: | - echo -e "$GPG_KEY" | base64 -d | gpg --batch --yes --import + printf '%s' "$GPG_KEY" | base64 -d | gpg --batch --yes --import nexus-deploy: steps: - run: @@ -147,7 +147,7 @@ jobs: name: 'Test' command: | source "$HOME/.sdkman/bin/sdkman-init.sh" - ./mvnw -ntp -B verify -T1C + ./mvnw -ntp -B verify - verify-formatting deploy: diff --git a/pom.xml b/pom.xml index bff68dcca5..42c7192f56 100644 --- a/pom.xml +++ b/pom.xml @@ -199,7 +199,6 @@ 3.2.0 1.2.8 4.0.0 - 0.8.14 6.28.1 3.26.0 3.26.0 @@ -556,7 +555,7 @@ true false - ${jvm.options} ${argLine} + ${jvm.options} @@ -915,16 +914,6 @@ - - org.jacoco - jacoco-maven-plugin - ${jacoco-maven-plugin.version} - - - feign/** - - - From deee4759774c4486bc39dbcf5bef0d263511e148 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 6 Feb 2026 19:20:11 -0300 Subject: [PATCH 352/615] prepare release 13.7 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 49 files changed, 49 insertions(+), 49 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 760bc3d5bb..8a42cb1fcc 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index d3eb3165d0..a1c3199c8e 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index bffc654e47..cc8e609cc4 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 02f493ff3b..63fbeb8ac0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index d137ae0b4c..1c2f49dd80 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 620a5976dc..4a0230cd4d 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 6e885acae1..c43a10293d 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index ae9539a053..5fca1fb298 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 8253cdf48a..7547cb8c80 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 4493615581..67f5327186 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 794e9a7179..ffbd2880e8 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 498e170242..0f3ad97b40 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 21f22c415f..1b217e7f9d 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 928c422335..fa0c734d92 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-googlehttpclient diff --git a/gson/pom.xml b/gson/pom.xml index d1a946b03f..e1428f5894 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 3090cf5332..a493230e64 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index ef83da18aa..4a28235fc4 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 1800dae670..76b6059215 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 5cf4a6ee5b..b5c0a3c652 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 061fbb380e..b1efd62542 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 5035d8b94b..70550e4787 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index de7e9225cd..5e64cc6151 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index e1cff99852..51f7b28581 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index deb84b4e07..26aba291bc 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 7d773f0ec0..1ae19936aa 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 38fc67c75f..91c2762644 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 62d6b3a80a..1a9cce1ac7 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 835071b883..6ba219ae14 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 57638ee98b..f69b5c54e1 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index a21e93e356..91ef735b8b 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 127fd1b483..3243e5a0e4 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index fb4caedf30..cf2b677593 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 44107908c5..47aaaf5c78 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 02a2863ed3..0bc1580024 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 2b3d51cf18..2186b4a714 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index a20bc44b17..dc0ca0dd6a 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-okhttp diff --git a/pom.xml b/pom.xml index 42c7192f56..cf075a3629 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index ca2dfc50f5..fe8e53a327 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 88a205f876..a7e91876b8 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 9ad392c4e9..35fdbf2d4a 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 4552ec48bc..d10acb769e 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 5f7dec40ce..458eddd5f2 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 09e03f3869..5d6509594d 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index dedbc8aa82..9a3c7dc196 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 0e480f31df..60fd6ddb1d 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index fec0f6a413..6e862bafb4 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.7-SNAPSHOT + 13.7 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index a759b785c3..5a381fd8e9 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.7-SNAPSHOT + 13.7 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 8b4387b051..8909516d1b 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.7-SNAPSHOT + 13.7 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index f8f8bedaef..cf2b82e9e2 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7-SNAPSHOT + 13.7 feign-vertx-parent From f04e8a4edd4b4a82141a17794ce8557a6c8ad54d Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 6 Feb 2026 19:20:20 -0300 Subject: [PATCH 353/615] [ci skip] updating versions to next development iteration 13.8-SNAPSHOT --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 49 files changed, 49 insertions(+), 49 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 8a42cb1fcc..01dee937ff 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index a1c3199c8e..082abe0100 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index cc8e609cc4..d99666fbce 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 63fbeb8ac0..fba385c4df 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 1c2f49dd80..6bbef5d9f0 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 4a0230cd4d..b8f2705626 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index c43a10293d..b07493cdca 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 5fca1fb298..c9c4bfc882 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 7547cb8c80..d9b5d2a81a 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 67f5327186..01b3be0eed 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index ffbd2880e8..62aef4c99b 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 0f3ad97b40..85a7e4210d 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 1b217e7f9d..fb646c21fa 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index fa0c734d92..17b8bd66bd 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-googlehttpclient diff --git a/gson/pom.xml b/gson/pom.xml index e1428f5894..b8cf5cada4 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index a493230e64..d736d9e7b7 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 4a28235fc4..d2a98601c7 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 76b6059215..21f0775b46 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index b5c0a3c652..c7a5604d84 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index b1efd62542..e3b9e47219 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 70550e4787..0cfc8976aa 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 5e64cc6151..f615df00d0 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 51f7b28581..9709dffb7d 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 26aba291bc..475134fc2e 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 1ae19936aa..3a64c01612 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 91c2762644..5470fa747b 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 1a9cce1ac7..9b1ec21ce1 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 6ba219ae14..dfee5d0a1c 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index f69b5c54e1..ac058a757e 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 91ef735b8b..f07e902dea 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 3243e5a0e4..a5ae81ec1d 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index cf2b677593..3ef76e2a65 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 47aaaf5c78..c93a942d14 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 0bc1580024..565d9cf80d 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 2186b4a714..6d160bbb64 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index dc0ca0dd6a..eab4785c97 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index cf075a3629..2dc5c2de58 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index fe8e53a327..2a490e9a57 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index a7e91876b8..fc3ca30ec6 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 35fdbf2d4a..10b52bb149 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index d10acb769e..7f2e335970 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 458eddd5f2..627b33be82 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 5d6509594d..e25715e0ab 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 9a3c7dc196..fdd0a763ec 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 60fd6ddb1d..998527191b 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 6e862bafb4..6119cea9ab 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.7 + 13.8-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 5a381fd8e9..4627c60a23 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.7 + 13.8-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 8909516d1b..f7941a4712 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.7 + 13.8-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index cf2b82e9e2..d5be4fd4ed 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.7 + 13.8-SNAPSHOT feign-vertx-parent From 5793c55e395f9e3fdeecc54c5437956bac643db8 Mon Sep 17 00:00:00 2001 From: Marvin Date: Fri, 6 Feb 2026 20:59:45 -0300 Subject: [PATCH 354/615] Upgrade Spring Boot 4.0.2, Spring Framework 7.0.3, Spring Cloud OpenFeign 5.0.1 (#3211) * Upgrade Spring Boot 4.0.2, Spring Framework 7.0.3, Spring Cloud OpenFeign 5.0.1 Signed-off-by: Marvin Froeder * Increase Http2ClientAsyncTest timeout from 1s to 10s Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder --- .../java/feign/form/feign/spring/Client.java | 9 ++---- .../form/feign/spring/DownloadClient.java | 32 ++++++------------- .../SpringManyMultipartFilesReaderTest.java | 6 ++-- .../test/Http2ClientAsyncTest.java | 2 +- pom.xml | 6 ++-- spring/pom.xml | 2 +- 6 files changed, 19 insertions(+), 38 deletions(-) diff --git a/form-spring/src/test/java/feign/form/feign/spring/Client.java b/form-spring/src/test/java/feign/form/feign/spring/Client.java index 14371fe89b..dbd2040a9c 100644 --- a/form-spring/src/test/java/feign/form/feign/spring/Client.java +++ b/form-spring/src/test/java/feign/form/feign/spring/Client.java @@ -25,10 +25,9 @@ import feign.form.spring.SpringFormEncoder; import java.util.List; import java.util.Map; -import org.springframework.beans.factory.ObjectFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.cloud.openfeign.support.FeignHttpMessageConverters; import org.springframework.cloud.openfeign.support.SpringEncoder; import org.springframework.context.annotation.Bean; import org.springframework.web.bind.annotation.PathVariable; @@ -91,10 +90,8 @@ String upload4( class ClientConfiguration { - @Autowired private ObjectFactory messageConverters; - @Bean - Encoder feignEncoder() { + Encoder feignEncoder(ObjectProvider messageConverters) { return new SpringFormEncoder(new SpringEncoder(messageConverters)); } diff --git a/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java b/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java index ce686675cc..4645d950c6 100644 --- a/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java +++ b/form-spring/src/test/java/feign/form/feign/spring/DownloadClient.java @@ -18,14 +18,12 @@ import feign.Logger; import feign.codec.Decoder; import feign.form.spring.converter.SpringManyMultipartFilesReader; -import java.util.ArrayList; -import org.springframework.beans.factory.ObjectFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.cloud.openfeign.support.FeignHttpMessageConverters; +import org.springframework.cloud.openfeign.support.HttpMessageConverterCustomizer; import org.springframework.cloud.openfeign.support.SpringDecoder; import org.springframework.context.annotation.Bean; -import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; @@ -41,26 +39,14 @@ interface DownloadClient { class ClientConfiguration { - @Autowired private ObjectFactory messageConverters; - @Bean - Decoder feignDecoder() { - var springConverters = messageConverters.getObject().getConverters(); - var decoderConverters = new ArrayList>(springConverters.size() + 1); - - decoderConverters.addAll(springConverters); - decoderConverters.add(new SpringManyMultipartFilesReader(4096)); - - var httpMessageConverters = new HttpMessageConverters(decoderConverters); - - return new SpringDecoder( - new ObjectFactory() { + HttpMessageConverterCustomizer multipartConverterCustomizer() { + return converters -> converters.add(new SpringManyMultipartFilesReader(4096)); + } - @Override - public HttpMessageConverters getObject() { - return httpMessageConverters; - } - }); + @Bean + Decoder feignDecoder(ObjectProvider messageConverters) { + return new SpringDecoder(messageConverters); } @Bean diff --git a/form-spring/src/test/java/feign/form/feign/spring/converter/SpringManyMultipartFilesReaderTest.java b/form-spring/src/test/java/feign/form/feign/spring/converter/SpringManyMultipartFilesReaderTest.java index ed551b23bd..d7f4d1b423 100644 --- a/form-spring/src/test/java/feign/form/feign/spring/converter/SpringManyMultipartFilesReaderTest.java +++ b/form-spring/src/test/java/feign/form/feign/spring/converter/SpringManyMultipartFilesReaderTest.java @@ -15,7 +15,6 @@ */ package feign.form.feign.spring.converter; -import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.http.HttpHeaders.CONTENT_TYPE; import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; @@ -84,9 +83,8 @@ public InputStream getBody() throws IOException { @Override public HttpHeaders getHeaders() { var httpHeaders = new HttpHeaders(); - httpHeaders.put( - CONTENT_TYPE, - singletonList(MULTIPART_FORM_DATA_VALUE + "; boundary=" + DUMMY_MULTIPART_BOUNDARY)); + httpHeaders.set( + CONTENT_TYPE, MULTIPART_FORM_DATA_VALUE + "; boundary=" + DUMMY_MULTIPART_BOUNDARY); return httpHeaders; } } diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java index 680276e57c..d0d00c3a36 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java @@ -460,7 +460,7 @@ void configKeyUsesChildType() throws Exception { private T unwrap(CompletableFuture cf) throws Throwable { try { - return cf.get(1, TimeUnit.SECONDS); + return cf.get(10, TimeUnit.SECONDS); } catch (final ExecutionException e) { throw e.getCause(); } diff --git a/pom.xml b/pom.xml index 2dc5c2de58..5690e24bec 100644 --- a/pom.xml +++ b/pom.xml @@ -165,7 +165,7 @@ 1.15.2 2.0.17 20250517 - 3.5.6 + 4.0.2 6.0.2 2.21.0 @@ -237,9 +237,9 @@ 1.5.3 3.0.2 2025.1.1 - 4.3.0 + 5.0.1 7.0.3 - 6.2.11 + 7.0.3 2.3.23.Final 1.18.0 diff --git a/spring/pom.xml b/spring/pom.xml index fdd0a763ec..a441d7130f 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -31,7 +31,7 @@ 17 - 6.2.11 + 7.0.3 From b5903f0e1851d4f0ceba22a4cc4c96e966cc1c9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Feb 2026 00:01:16 +0000 Subject: [PATCH 355/615] build(deps): Bump micrometer.version from 1.16.1 to 1.16.2 Bumps `micrometer.version` from 1.16.1 to 1.16.2. Updates `io.micrometer:micrometer-core` from 1.16.1 to 1.16.2 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.1...v1.16.2) Updates `io.micrometer:micrometer-test` from 1.16.1 to 1.16.2 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.1...v1.16.2) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.16.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-version: 1.16.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index c93a942d14..c98d50beb6 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.16.1 + 1.16.2 From fe640f55a86973e85be93ccb23da8686ec51e7d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Feb 2026 00:01:17 +0000 Subject: [PATCH 356/615] build(deps): Bump org.apache.maven.plugins:maven-source-plugin Bumps [org.apache.maven.plugins:maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.3.1 to 3.4.0. - [Release notes](https://github.com/apache/maven-source-plugin/releases) - [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.3.1...maven-source-plugin-3.4.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-source-plugin dependency-version: 3.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5690e24bec..053a2406ac 100644 --- a/pom.xml +++ b/pom.xml @@ -178,7 +178,7 @@ 5.4 3.15.0 3.1.4 - 3.3.1 + 3.4.0 3.12.0 5.0.0 3.5.0 From f0e935f8a3f0b7af0c87df1bdf1047edb907736b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Feb 2026 00:01:17 +0000 Subject: [PATCH 357/615] build(deps): Bump org.json:json from 20250517 to 20251224 Bumps [org.json:json](https://github.com/douglascrockford/JSON-java) from 20250517 to 20251224. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/commits) --- updated-dependencies: - dependency-name: org.json:json dependency-version: '20251224' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5690e24bec..6494db5cab 100644 --- a/pom.xml +++ b/pom.xml @@ -164,7 +164,7 @@ 2.13.2 1.15.2 2.0.17 - 20250517 + 20251224 4.0.2 6.0.2 From 20d2946cd4295b0d17c6337a415de440d19e21cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Feb 2026 00:01:19 +0000 Subject: [PATCH 358/615] build(deps): Bump org.apache.httpcomponents.client5:httpclient5 Bumps [org.apache.httpcomponents.client5:httpclient5](https://github.com/apache/httpcomponents-client) from 5.5.1 to 5.6. - [Changelog](https://github.com/apache/httpcomponents-client/blob/master/RELEASE_NOTES.txt) - [Commits](https://github.com/apache/httpcomponents-client/compare/rel/v5.5.1...rel/v5.6) --- updated-dependencies: - dependency-name: org.apache.httpcomponents.client5:httpclient5 dependency-version: '5.6' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5690e24bec..66e1e6b0e0 100644 --- a/pom.xml +++ b/pom.xml @@ -214,7 +214,7 @@ 0.23.0 4.5.0 4.5.14 - 5.5.1 + 5.6 1.5.18 3.1.0 4.0.0 From d62b64740473eab2ae31acd591adaf7e6b14af2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Feb 2026 05:35:04 +0000 Subject: [PATCH 359/615] build(deps): Bump com.alibaba.fastjson2:fastjson2 Bumps [com.alibaba.fastjson2:fastjson2](https://github.com/alibaba/fastjson2) from 2.0.60.android8 to 2.0.61.android8. - [Release notes](https://github.com/alibaba/fastjson2/releases) - [Commits](https://github.com/alibaba/fastjson2/compare/2.0.60.android8...2.0.61.android8) --- updated-dependencies: - dependency-name: com.alibaba.fastjson2:fastjson2 dependency-version: 2.0.61.android8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dfeb93cb53..a110ef4e42 100644 --- a/pom.xml +++ b/pom.xml @@ -172,7 +172,7 @@ 3.0.2 3.27.7 5.21.0 - 2.0.60.android8 + 2.0.61.android8 1.5.3 5.4 From d74ef9995e7f965f86e257dacc2ef1fa9e86d6d7 Mon Sep 17 00:00:00 2001 From: Marvin Date: Mon, 9 Feb 2026 14:57:22 -0300 Subject: [PATCH 360/615] Add feign-graphql and feign-graphql-apt modules (#3212) * Add feign-graphql-apt module for GraphQL schema-based type generation Signed-off-by: Marvin Froeder * Generate Java records instead of POJOs in feign-graphql-apt Signed-off-by: Marvin Froeder * Apply Java 17/25 modernization, add READMEs, and update mindmap Signed-off-by: Marvin Froeder * Remove X-Feign-GraphQL headers, add decoder delegate support Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder --- .circleci/config.yml | 2 +- .gitignore | 1 + CLAUDE.md => AGENTS.md | 11 +- graphql-apt/README.md | 57 ++ graphql-apt/pom.xml | 89 +++ .../graphql/apt/GraphqlSchemaProcessor.java | 445 +++++++++++++++ .../feign/graphql/apt/GraphqlTypeMapper.java | 75 +++ .../feign/graphql/apt/QueryValidator.java | 61 +++ .../java/feign/graphql/apt/SchemaLoader.java | 64 +++ .../java/feign/graphql/apt/TypeGenerator.java | 401 ++++++++++++++ .../apt/GraphqlSchemaProcessorTest.java | 517 ++++++++++++++++++ .../test/resources/scalar-test-schema.graphql | 14 + .../src/test/resources/test-schema.graphql | 150 +++++ graphql/README.md | 147 +++++ graphql/pom.xml | 63 +++ .../java/feign/graphql/GraphqlContract.java | 100 ++++ .../java/feign/graphql/GraphqlDecoder.java | 129 +++++ .../java/feign/graphql/GraphqlEncoder.java | 80 +++ .../feign/graphql/GraphqlErrorException.java | 39 ++ .../main/java/feign/graphql/GraphqlQuery.java | 28 + .../java/feign/graphql/GraphqlSchema.java | 30 + .../src/main/java/feign/graphql/Scalar.java | 28 + .../java/feign/graphql/GraphqlClientTest.java | 190 +++++++ .../feign/graphql/GraphqlContractTest.java | 121 ++++ .../feign/graphql/GraphqlDecoderTest.java | 148 +++++ .../feign/graphql/GraphqlEncoderTest.java | 97 ++++ pom.xml | 10 + src/docs/overview-mindmap.iuml | 14 +- vertx/pom.xml | 1 + 29 files changed, 3106 insertions(+), 6 deletions(-) rename CLAUDE.md => AGENTS.md (90%) create mode 100644 graphql-apt/README.md create mode 100644 graphql-apt/pom.xml create mode 100644 graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java create mode 100644 graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java create mode 100644 graphql-apt/src/main/java/feign/graphql/apt/QueryValidator.java create mode 100644 graphql-apt/src/main/java/feign/graphql/apt/SchemaLoader.java create mode 100644 graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java create mode 100644 graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java create mode 100644 graphql-apt/src/test/resources/scalar-test-schema.graphql create mode 100644 graphql-apt/src/test/resources/test-schema.graphql create mode 100644 graphql/README.md create mode 100644 graphql/pom.xml create mode 100644 graphql/src/main/java/feign/graphql/GraphqlContract.java create mode 100644 graphql/src/main/java/feign/graphql/GraphqlDecoder.java create mode 100644 graphql/src/main/java/feign/graphql/GraphqlEncoder.java create mode 100644 graphql/src/main/java/feign/graphql/GraphqlErrorException.java create mode 100644 graphql/src/main/java/feign/graphql/GraphqlQuery.java create mode 100644 graphql/src/main/java/feign/graphql/GraphqlSchema.java create mode 100644 graphql/src/main/java/feign/graphql/Scalar.java create mode 100644 graphql/src/test/java/feign/graphql/GraphqlClientTest.java create mode 100644 graphql/src/test/java/feign/graphql/GraphqlContractTest.java create mode 100644 graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java create mode 100644 graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java diff --git a/.circleci/config.yml b/.circleci/config.yml index 08b806e783..598323cc97 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -99,7 +99,7 @@ commands: name: 'Deploy Core Modules Sonatype' command: | source "$HOME/.sdkman/bin/sdkman-init.sh" - ./mvnw -ntp -nsu -s .circleci/settings.xml -P release -pl -:feign-benchmark -DskipTests=true deploy + ./mvnw -ntp -nsu -s .circleci/settings.xml -P release -pl -:feign-benchmark,-:feign-vertx4-test,-:feign-vertx5-test -DskipTests=true deploy # our job defaults defaults: &defaults diff --git a/.gitignore b/.gitignore index d19b71053c..3302792f89 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,4 @@ atlassian-ide-plugin.xml # maven versions *.versionsBackup .mvn/.develocity/develocity-workspace-id +.sdkmanrc diff --git a/CLAUDE.md b/AGENTS.md similarity index 90% rename from CLAUDE.md rename to AGENTS.md index 33b037e165..23a8257c03 100644 --- a/CLAUDE.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ -# CLAUDE.md +# AGENTS.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +This file provides guidance to AI coding assistants when working with code in this repository. ## Build Commands @@ -122,3 +122,10 @@ Some modules define the same Maven property name (e.g., `jersey.version`, `vertx 1. Add the dependency to the root entry's `ignore` list (fully ignored, not just major) 2. Add a per-directory entry for the new module with `allow` for the specific dependency and `ignore` for `version-update:semver-major` 3. Verify existing modules with the same property also have their own per-directory entries + +## Documentation Requirements + +- New modules must include a `README.md` with usage examples following the style of existing module READMEs (e.g., `jackson/README.md`, `graphql/README.md`) +- New public functionality (annotations, contracts, encoders, decoders) must be documented in the module's `README.md` +- README should include: Maven dependency coordinates, `Feign.builder()` configuration examples, and advanced usage if applicable +- Update this file's Integration Modules list when adding a new module diff --git a/graphql-apt/README.md b/graphql-apt/README.md new file mode 100644 index 0000000000..db67c2418a --- /dev/null +++ b/graphql-apt/README.md @@ -0,0 +1,57 @@ +Feign GraphQL APT +=================== + +Annotation processor for `feign-graphql` that generates Java records from GraphQL schemas at compile time. + +Given a `@GraphqlSchema`-annotated interface, this processor: + +- Parses the referenced `.graphql` schema file +- Validates all `@GraphqlQuery` strings against the schema +- Generates Java records for result types, input types, and enums +- Maps custom scalars to Java types via `@Scalar` annotations + +See the [feign-graphql README](../graphql/README.md) for usage examples. + +## Generated Output + +For a schema type like: + +```graphql +type User { + id: ID! + name: String! + email: String + status: Status! +} + +enum Status { + ACTIVE + INACTIVE +} +``` + +The processor generates: + +```java +public record User(String id, String name, String email, Status status) {} +``` + +```java +public enum Status { + ACTIVE, + INACTIVE +} +``` + +## Maven Configuration + +Add as a `provided` dependency so it runs during compilation but is not included at runtime: + +```xml + + io.github.openfeign.experimental + feign-graphql-apt + ${feign.version} + provided + +``` diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml new file mode 100644 index 0000000000..4f96d5320d --- /dev/null +++ b/graphql-apt/pom.xml @@ -0,0 +1,89 @@ + + + + 4.0.0 + + + io.github.openfeign + feign-parent + 13.8-SNAPSHOT + + + io.github.openfeign.experimental + feign-graphql-apt + Feign GraphQL APT + Feign annotation processor for GraphQL schema-based type generation + + + 17 + true + + + + + io.github.openfeign + feign-graphql + ${project.version} + + + + com.graphql-java + graphql-java + ${graphql-java.version} + + + + com.squareup + javapoet + ${javapoet.version} + + + + com.google.auto.service + auto-service + ${auto-service-annotations.version} + provided + + + + com.google.testing.compile + compile-testing + ${compile-testing.version} + test + + + junit + junit + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + --add-opens jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED + + + + + diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java new file mode 100644 index 0000000000..0f6e321088 --- /dev/null +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java @@ -0,0 +1,445 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql.apt; + +import com.google.auto.service.AutoService; +import com.squareup.javapoet.TypeName; +import feign.graphql.GraphqlQuery; +import feign.graphql.GraphqlSchema; +import feign.graphql.Scalar; +import graphql.language.Document; +import graphql.language.Field; +import graphql.language.FieldDefinition; +import graphql.language.ListType; +import graphql.language.NonNullType; +import graphql.language.ObjectTypeDefinition; +import graphql.language.OperationDefinition; +import graphql.language.SelectionSet; +import graphql.language.Type; +import graphql.language.VariableDefinition; +import graphql.parser.Parser; +import graphql.schema.GraphQLSchema; +import graphql.schema.idl.SchemaParser; +import graphql.schema.idl.TypeDefinitionRegistry; +import graphql.schema.idl.UnExecutableSchemaGenerator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Filer; +import javax.annotation.processing.Messager; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; + +@AutoService(Processor.class) +@SupportedAnnotationTypes("feign.graphql.GraphqlSchema") +@SupportedSourceVersion(SourceVersion.RELEASE_17) +public class GraphqlSchemaProcessor extends AbstractProcessor { + + private Filer filer; + private Messager messager; + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + this.filer = processingEnv.getFiler(); + this.messager = processingEnv.getMessager(); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (var element : roundEnv.getElementsAnnotatedWith(GraphqlSchema.class)) { + if (!(element instanceof TypeElement)) { + continue; + } + processInterface((TypeElement) element); + } + return true; + } + + private void processInterface(TypeElement typeElement) { + var schemaAnnotation = typeElement.getAnnotation(GraphqlSchema.class); + var schemaPath = schemaAnnotation.value(); + + var loader = new SchemaLoader(filer, messager); + var schemaContent = loader.load(schemaPath, typeElement); + if (schemaContent == null) { + return; + } + + var schemaParser = new SchemaParser(); + TypeDefinitionRegistry registry; + try { + registry = schemaParser.parse(schemaContent); + } catch (Exception e) { + messager.printMessage( + Diagnostic.Kind.ERROR, "Failed to parse GraphQL schema: " + e.getMessage(), typeElement); + return; + } + + var customScalars = collectScalarMappings(typeElement); + + if (!validateCustomScalars(registry, customScalars, typeElement)) { + return; + } + + var graphqlSchema = UnExecutableSchemaGenerator.makeUnExecutableSchema(registry); + + var generateTypes = schemaAnnotation.generateTypes(); + + var targetPackage = getPackageName(typeElement); + var typeMapper = new GraphqlTypeMapper(targetPackage, customScalars); + var validator = new QueryValidator(messager); + var generator = new TypeGenerator(filer, messager, registry, typeMapper, targetPackage); + + for (var enclosed : typeElement.getEnclosedElements()) { + if (!(enclosed instanceof ExecutableElement method)) { + continue; + } + var queryAnnotation = method.getAnnotation(GraphqlQuery.class); + if (queryAnnotation == null) { + continue; + } + + processMethod( + method, + queryAnnotation, + graphqlSchema, + registry, + generator, + validator, + generateTypes, + targetPackage); + } + } + + private Map collectScalarMappings(TypeElement typeElement) { + var scalars = new HashMap(); + collectScalarsFromType(typeElement, scalars); + collectScalarsFromParents(typeElement, scalars); + return scalars; + } + + private void collectScalarsFromType(TypeElement typeElement, Map scalars) { + for (var enclosed : typeElement.getEnclosedElements()) { + if (!(enclosed instanceof ExecutableElement method)) { + continue; + } + var scalarAnnotation = method.getAnnotation(Scalar.class); + if (scalarAnnotation == null) { + continue; + } + var scalarName = scalarAnnotation.value(); + var javaType = TypeName.get(method.getReturnType()); + scalars.put(scalarName, javaType); + } + } + + private void collectScalarsFromParents(TypeElement typeElement, Map scalars) { + for (var iface : typeElement.getInterfaces()) { + if (iface instanceof DeclaredType type) { + var element = type.asElement(); + if (element instanceof TypeElement parentType) { + collectScalarsFromType(parentType, scalars); + collectScalarsFromParents(parentType, scalars); + } + } + } + } + + private static final Set GRAPHQL_BUILT_IN_SCALARS = + Set.of("String", "Int", "Float", "Boolean", "ID"); + + private boolean validateCustomScalars( + TypeDefinitionRegistry registry, + Map customScalars, + TypeElement typeElement) { + var schemaScalars = registry.scalars(); + var valid = true; + for (var scalarName : schemaScalars.keySet()) { + if (GRAPHQL_BUILT_IN_SCALARS.contains(scalarName)) { + continue; + } + if (!customScalars.containsKey(scalarName)) { + messager.printMessage( + Diagnostic.Kind.ERROR, + "Custom scalar '" + + scalarName + + "' is used in the schema but no @Scalar(\"" + + scalarName + + "\") method is defined. " + + "Add a @Scalar(\"" + + scalarName + + "\") default method to this interface or a parent interface.", + typeElement); + valid = false; + } + } + return valid; + } + + private void processMethod( + ExecutableElement method, + GraphqlQuery queryAnnotation, + GraphQLSchema graphqlSchema, + TypeDefinitionRegistry registry, + TypeGenerator generator, + QueryValidator validator, + boolean generateTypes, + String targetPackage) { + + var queryString = queryAnnotation.value(); + Document document; + try { + document = Parser.parse(queryString); + } catch (Exception e) { + messager.printMessage( + Diagnostic.Kind.ERROR, "Failed to parse GraphQL query: " + e.getMessage(), method); + return; + } + + if (!validator.validate(graphqlSchema, document, method) || !generateTypes) { + return; + } + + var operation = findOperation(document); + if (operation == null) { + messager.printMessage( + Diagnostic.Kind.ERROR, "No operation definition found in GraphQL query", method); + return; + } + + var returnTypeName = getSimpleTypeName(method.getReturnType()); + if (returnTypeName != null && !isExistingExternalType(method.getReturnType(), targetPackage)) { + var rootType = getRootType(operation, registry); + if (rootType != null) { + var rootField = findRootField(operation.getSelectionSet()); + if (rootField != null && rootField.getSelectionSet() != null) { + var rootFieldDef = findFieldDefinition(rootType, rootField.getName()); + if (rootFieldDef != null) { + var fieldTypeName = unwrapTypeName(rootFieldDef.getType()); + var fieldObjectType = + registry.getType(fieldTypeName, ObjectTypeDefinition.class).orElse(null); + if (fieldObjectType != null) { + generator.generateResultType( + returnTypeName, rootField.getSelectionSet(), fieldObjectType, method); + } + } + } + } + } + + var params = method.getParameters(); + var variableDefs = operation.getVariableDefinitions(); + + for (var param : params) { + var paramTypeName = getSimpleTypeName(param.asType()); + if (paramTypeName == null || isJavaBuiltIn(paramTypeName)) { + continue; + } + + if (isExistingExternalType(param.asType(), targetPackage)) { + continue; + } + + var graphqlInputTypeName = findGraphqlInputType(paramTypeName, variableDefs); + if (graphqlInputTypeName != null) { + generator.generateInputType(paramTypeName, graphqlInputTypeName, method); + } + } + } + + private OperationDefinition findOperation(Document document) { + for (var def : document.getDefinitions()) { + if (def instanceof OperationDefinition definition) { + return definition; + } + } + return null; + } + + private Field findRootField(SelectionSet selectionSet) { + if (selectionSet == null) { + return null; + } + for (var selection : selectionSet.getSelections()) { + if (selection instanceof Field field) { + return field; + } + } + return null; + } + + private FieldDefinition findFieldDefinition(ObjectTypeDefinition typeDef, String fieldName) { + for (var fd : typeDef.getFieldDefinitions()) { + if (fd.getName().equals(fieldName)) { + return fd; + } + } + return null; + } + + private ObjectTypeDefinition getRootType( + OperationDefinition operation, TypeDefinitionRegistry registry) { + var rootTypeName = + switch (operation.getOperation()) { + case MUTATION -> + registry + .schemaDefinition() + .flatMap( + sd -> + sd.getOperationTypeDefinitions().stream() + .filter(otd -> otd.getName().equals("mutation")) + .findFirst()) + .map(otd -> otd.getTypeName().getName()) + .orElse("Mutation"); + case SUBSCRIPTION -> + registry + .schemaDefinition() + .flatMap( + sd -> + sd.getOperationTypeDefinitions().stream() + .filter(otd -> otd.getName().equals("subscription")) + .findFirst()) + .map(otd -> otd.getTypeName().getName()) + .orElse("Subscription"); + default -> + registry + .schemaDefinition() + .flatMap( + sd -> + sd.getOperationTypeDefinitions().stream() + .filter(otd -> otd.getName().equals("query")) + .findFirst()) + .map(otd -> otd.getTypeName().getName()) + .orElse("Query"); + }; + return registry.getType(rootTypeName, ObjectTypeDefinition.class).orElse(null); + } + + private String findGraphqlInputType( + String javaParamTypeName, List variableDefs) { + for (var varDef : variableDefs) { + var graphqlTypeName = unwrapTypeName(varDef.getType()); + if (graphqlTypeName.equals(javaParamTypeName)) { + return graphqlTypeName; + } + } + return javaParamTypeName; + } + + private String unwrapTypeName(Type type) { + if (type instanceof NonNullType nullType) { + return unwrapTypeName(nullType.getType()); + } + if (type instanceof ListType listType) { + return unwrapTypeName(listType.getType()); + } + if (type instanceof graphql.language.TypeName name) { + return name.getName(); + } + return "String"; + } + + private static final Set JAVA_BUILT_INS = + Set.of( + "String", + "Integer", + "Long", + "Double", + "Float", + "Boolean", + "Object", + "Byte", + "Short", + "Character", + "BigDecimal", + "BigInteger"); + + private boolean isJavaBuiltIn(String typeName) { + return JAVA_BUILT_INS.contains(typeName); + } + + private String getSimpleTypeName(TypeMirror typeMirror) { + if (typeMirror instanceof DeclaredType declaredType) { + var typeElement = declaredType.asElement(); + var simpleName = typeElement.getSimpleName().toString(); + + if ("List".equals(simpleName)) { + var typeArgs = declaredType.getTypeArguments(); + if (!typeArgs.isEmpty()) { + return getSimpleTypeName(typeArgs.get(0)); + } + } + + return simpleName; + } + return null; + } + + private boolean isExistingExternalType(TypeMirror typeMirror, String targetPackage) { + var unwrapped = unwrapListTypeMirror(typeMirror); + if (unwrapped.getKind() == TypeKind.ERROR) { + return false; + } + if (unwrapped instanceof DeclaredType type) { + var element = type.asElement(); + if (element instanceof TypeElement typeElement) { + var qualifiedName = typeElement.getQualifiedName().toString(); + var lastDot = qualifiedName.lastIndexOf('.'); + var typePkg = lastDot > 0 ? qualifiedName.substring(0, lastDot) : ""; + return !typePkg.equals(targetPackage); + } + } + return false; + } + + private TypeMirror unwrapListTypeMirror(TypeMirror typeMirror) { + if (typeMirror instanceof DeclaredType declaredType) { + var simpleName = declaredType.asElement().getSimpleName().toString(); + if ("List".equals(simpleName)) { + var typeArgs = declaredType.getTypeArguments(); + if (!typeArgs.isEmpty()) { + return typeArgs.get(0); + } + } + } + return typeMirror; + } + + private String getPackageName(TypeElement typeElement) { + var enclosing = typeElement.getEnclosingElement(); + while (enclosing != null && !(enclosing instanceof PackageElement)) { + enclosing = enclosing.getEnclosingElement(); + } + if (enclosing instanceof PackageElement element) { + return element.getQualifiedName().toString(); + } + return ""; + } +} diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java new file mode 100644 index 0000000000..d9be1fa18f --- /dev/null +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java @@ -0,0 +1,75 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql.apt; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import graphql.language.ListType; +import graphql.language.NonNullType; +import graphql.language.Type; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GraphqlTypeMapper { + + private static final Map BUILT_IN_SCALARS = + Map.of( + "String", ClassName.get(String.class), + "Int", ClassName.get(Integer.class), + "Float", ClassName.get(Double.class), + "Boolean", ClassName.get(Boolean.class), + "ID", ClassName.get(String.class)); + + private final String targetPackage; + private final Map customScalars; + + public GraphqlTypeMapper(String targetPackage, Map customScalars) { + this.targetPackage = targetPackage; + this.customScalars = new HashMap<>(customScalars); + } + + public TypeName map(Type type) { + if (type instanceof NonNullType nullType) { + return map(nullType.getType()); + } + if (type instanceof ListType listType) { + var elementType = map(listType.getType()); + return ParameterizedTypeName.get(ClassName.get(List.class), elementType); + } + if (type instanceof graphql.language.TypeName name) { + return mapScalarOrNamed(name.getName()); + } + return ClassName.get(String.class); + } + + private TypeName mapScalarOrNamed(String name) { + var builtIn = BUILT_IN_SCALARS.get(name); + if (builtIn != null) { + return builtIn; + } + var custom = customScalars.get(name); + if (custom != null) { + return custom; + } + return ClassName.get(targetPackage, name); + } + + public boolean isScalar(String name) { + return BUILT_IN_SCALARS.containsKey(name) || customScalars.containsKey(name); + } +} diff --git a/graphql-apt/src/main/java/feign/graphql/apt/QueryValidator.java b/graphql-apt/src/main/java/feign/graphql/apt/QueryValidator.java new file mode 100644 index 0000000000..17c5e304d0 --- /dev/null +++ b/graphql-apt/src/main/java/feign/graphql/apt/QueryValidator.java @@ -0,0 +1,61 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql.apt; + +import graphql.GraphQLError; +import graphql.language.Document; +import graphql.schema.GraphQLSchema; +import graphql.validation.Validator; +import java.util.Locale; +import javax.annotation.processing.Messager; +import javax.lang.model.element.Element; +import javax.tools.Diagnostic; + +public class QueryValidator { + + private final Messager messager; + + public QueryValidator(Messager messager) { + this.messager = messager; + } + + public boolean validate(GraphQLSchema schema, Document document, Element methodElement) { + var validator = new Validator(); + var errors = validator.validateDocument(schema, document, Locale.ENGLISH); + + if (errors.isEmpty()) { + return true; + } + + for (GraphQLError error : errors) { + var locations = error.getLocations(); + if (locations != null && !locations.isEmpty()) { + var loc = locations.get(0); + messager.printMessage( + Diagnostic.Kind.ERROR, + "GraphQL validation error at line %d, column %d: %s" + .formatted(loc.getLine(), loc.getColumn(), error.getMessage()), + methodElement); + } else { + messager.printMessage( + Diagnostic.Kind.ERROR, + "GraphQL validation error: " + error.getMessage(), + methodElement); + } + } + return false; + } +} diff --git a/graphql-apt/src/main/java/feign/graphql/apt/SchemaLoader.java b/graphql-apt/src/main/java/feign/graphql/apt/SchemaLoader.java new file mode 100644 index 0000000000..16f971d0f0 --- /dev/null +++ b/graphql-apt/src/main/java/feign/graphql/apt/SchemaLoader.java @@ -0,0 +1,64 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql.apt; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import javax.annotation.processing.Filer; +import javax.annotation.processing.Messager; +import javax.lang.model.element.Element; +import javax.tools.Diagnostic; +import javax.tools.StandardLocation; + +public class SchemaLoader { + + private final Filer filer; + private final Messager messager; + + public SchemaLoader(Filer filer, Messager messager) { + this.filer = filer; + this.messager = messager; + } + + public String load(String path, Element element) { + StandardLocation[] locations = { + StandardLocation.CLASS_PATH, StandardLocation.SOURCE_PATH, StandardLocation.CLASS_OUTPUT + }; + + for (var location : locations) { + try { + var resource = filer.getResource(location, "", path); + try (var is = resource.openInputStream(); + Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) { + var sb = new StringBuilder(); + var buf = new char[4096]; + int read; + while ((read = reader.read(buf)) != -1) { + sb.append(buf, 0, read); + } + return sb.toString(); + } + } catch (IOException e) { + // try next location + } + } + + messager.printMessage(Diagnostic.Kind.ERROR, "GraphQL schema not found: " + path, element); + return null; + } +} diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java new file mode 100644 index 0000000000..3b70e8480f --- /dev/null +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java @@ -0,0 +1,401 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql.apt; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import graphql.language.EnumTypeDefinition; +import graphql.language.Field; +import graphql.language.FieldDefinition; +import graphql.language.InputObjectTypeDefinition; +import graphql.language.ListType; +import graphql.language.NonNullType; +import graphql.language.ObjectTypeDefinition; +import graphql.language.SelectionSet; +import graphql.language.Type; +import graphql.schema.idl.TypeDefinitionRegistry; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; +import javax.annotation.processing.Filer; +import javax.annotation.processing.FilerException; +import javax.annotation.processing.Messager; +import javax.lang.model.element.Element; +import javax.lang.model.element.Modifier; +import javax.tools.Diagnostic; + +public class TypeGenerator { + + private final Filer filer; + private final Messager messager; + private final TypeDefinitionRegistry registry; + private final GraphqlTypeMapper typeMapper; + private final String targetPackage; + private final Set generatedTypes = new HashSet<>(); + private final Queue pendingTypes = new ArrayDeque<>(); + + public TypeGenerator( + Filer filer, + Messager messager, + TypeDefinitionRegistry registry, + GraphqlTypeMapper typeMapper, + String targetPackage) { + this.filer = filer; + this.messager = messager; + this.registry = registry; + this.typeMapper = typeMapper; + this.targetPackage = targetPackage; + } + + public void generateResultType( + String className, + SelectionSet selectionSet, + ObjectTypeDefinition parentType, + Element element) { + if (generatedTypes.contains(className)) { + return; + } + generatedTypes.add(className); + + var fields = new ArrayList(); + + for (var selection : selectionSet.getSelections()) { + if (!(selection instanceof Field)) { + continue; + } + var field = (Field) selection; + var fieldName = field.getName(); + + var schemaDef = findFieldDefinition(parentType, fieldName); + if (schemaDef == null) { + continue; + } + + var fieldType = schemaDef.getType(); + var rawTypeName = unwrapTypeName(fieldType); + + if (field.getSelectionSet() != null && !field.getSelectionSet().getSelections().isEmpty()) { + var nestedClassName = capitalize(fieldName); + generateNestedResultType(nestedClassName, field.getSelectionSet(), rawTypeName, element); + var nestedType = wrapType(fieldType, ClassName.get(targetPackage, nestedClassName)); + fields.add(toRecordField(fieldName, nestedType)); + } else { + var javaType = typeMapper.map(fieldType); + fields.add(toRecordField(fieldName, javaType)); + enqueueIfNonScalar(rawTypeName); + } + } + + writeRecord(className, fields, element); + processPendingTypes(element); + } + + public void generateInputType(String className, String graphqlTypeName, Element element) { + if (generatedTypes.contains(className)) { + return; + } + generatedTypes.add(className); + + var maybeDef = registry.getType(graphqlTypeName, InputObjectTypeDefinition.class); + if (maybeDef.isEmpty()) { + messager.printMessage( + Diagnostic.Kind.ERROR, "GraphQL input type not found: " + graphqlTypeName, element); + return; + } + + var inputDef = maybeDef.get(); + var fields = new ArrayList(); + + for (var valueDef : inputDef.getInputValueDefinitions()) { + var fieldName = valueDef.getName(); + var fieldType = valueDef.getType(); + var javaType = typeMapper.map(fieldType); + fields.add(toRecordField(fieldName, javaType)); + + var rawTypeName = unwrapTypeName(fieldType); + enqueueIfNonScalar(rawTypeName); + } + + writeRecord(className, fields, element); + processPendingTypes(element); + } + + private void generateNestedResultType( + String className, SelectionSet selectionSet, String graphqlTypeName, Element element) { + if (generatedTypes.contains(className)) { + return; + } + + var maybeDef = registry.getType(graphqlTypeName, ObjectTypeDefinition.class); + if (maybeDef.isEmpty()) { + return; + } + + generateResultType(className, selectionSet, maybeDef.get(), element); + } + + private void processPendingTypes(Element element) { + while (!pendingTypes.isEmpty()) { + var typeName = pendingTypes.poll(); + if (generatedTypes.contains(typeName)) { + continue; + } + + var enumDef = registry.getType(typeName, EnumTypeDefinition.class); + if (enumDef.isPresent()) { + generateEnum(typeName, enumDef.get(), element); + continue; + } + + var inputDef = registry.getType(typeName, InputObjectTypeDefinition.class); + if (inputDef.isPresent()) { + generateInputType(typeName, typeName, element); + continue; + } + + var objectDef = registry.getType(typeName, ObjectTypeDefinition.class); + if (objectDef.isPresent()) { + generateFullObjectType(typeName, objectDef.get(), element); + } + } + } + + private void generateEnum(String className, EnumTypeDefinition enumDef, Element element) { + if (generatedTypes.contains(className)) { + return; + } + generatedTypes.add(className); + + var enumBuilder = TypeSpec.enumBuilder(className).addModifiers(Modifier.PUBLIC); + + for (var value : enumDef.getEnumValueDefinitions()) { + enumBuilder.addEnumConstant(value.getName()); + } + + writeType(enumBuilder.build(), element); + } + + private void generateFullObjectType( + String className, ObjectTypeDefinition objectDef, Element element) { + if (generatedTypes.contains(className)) { + return; + } + generatedTypes.add(className); + + var fields = new ArrayList(); + + for (var fieldDef : objectDef.getFieldDefinitions()) { + var fieldName = fieldDef.getName(); + var javaType = typeMapper.map(fieldDef.getType()); + fields.add(toRecordField(fieldName, javaType)); + + var rawTypeName = unwrapTypeName(fieldDef.getType()); + enqueueIfNonScalar(rawTypeName); + } + + writeRecord(className, fields, element); + processPendingTypes(element); + } + + private void enqueueIfNonScalar(String typeName) { + if (!typeMapper.isScalar(typeName) && !generatedTypes.contains(typeName)) { + pendingTypes.add(typeName); + } + } + + private FieldDefinition findFieldDefinition(ObjectTypeDefinition typeDef, String fieldName) { + for (var fd : typeDef.getFieldDefinitions()) { + if (fd.getName().equals(fieldName)) { + return fd; + } + } + return null; + } + + private String unwrapTypeName(Type type) { + if (type instanceof NonNullType nullType) { + return unwrapTypeName(nullType.getType()); + } + if (type instanceof ListType listType) { + return unwrapTypeName(listType.getType()); + } + if (type instanceof graphql.language.TypeName name) { + return name.getName(); + } + return "String"; + } + + private TypeName wrapType(Type schemaType, TypeName innerType) { + if (schemaType instanceof NonNullType type) { + return wrapType(type.getType(), innerType); + } + if (schemaType instanceof ListType type) { + return ParameterizedTypeName.get( + ClassName.get(List.class), wrapType(type.getType(), innerType)); + } + return innerType; + } + + private String capitalize(String s) { + if (s == null || s.isEmpty()) { + return s; + } + return Character.toUpperCase(s.charAt(0)) + s.substring(1); + } + + private void writeType(TypeSpec typeSpec, Element element) { + try { + var javaFile = JavaFile.builder(targetPackage, typeSpec).build(); + javaFile.writeTo(filer); + } catch (FilerException e) { + // Type already generated by another interface in the same compilation round + } catch (IOException e) { + messager.printMessage( + Diagnostic.Kind.ERROR, + "Failed to write generated type " + typeSpec.name + ": " + e.getMessage(), + element); + } + } + + private RecordField toRecordField(String name, TypeName typeName) { + var typeString = typeNameToString(typeName); + var importFqn = resolveImport(typeName); + return new RecordField(typeString, name, importFqn, typeName); + } + + private String typeNameToString(TypeName typeName) { + if (typeName instanceof ParameterizedTypeName parameterized) { + var raw = parameterized.rawType.simpleName(); + var typeArgs = + parameterized.typeArguments.stream() + .map(this::typeNameToString) + .collect(Collectors.joining(", ")); + return raw + "<" + typeArgs + ">"; + } + if (typeName instanceof ClassName name) { + return name.simpleName(); + } + return typeName.toString(); + } + + private String resolveImport(TypeName typeName) { + if (typeName instanceof ParameterizedTypeName parameterized) { + resolveImport(parameterized.rawType); + for (var typeArg : parameterized.typeArguments) { + resolveImport(typeArg); + } + return fqnIfNeeded(parameterized.rawType); + } + if (typeName instanceof ClassName name) { + return fqnIfNeeded(name); + } + return null; + } + + private String fqnIfNeeded(ClassName className) { + var pkg = className.packageName(); + if (pkg.equals("java.lang") || pkg.equals(targetPackage) || pkg.isEmpty()) { + return null; + } + return pkg + "." + className.simpleName(); + } + + private Set collectImports(List fields) { + var imports = new TreeSet(); + for (var field : fields) { + collectImportsFromTypeName(field.typeName, imports); + } + return imports; + } + + private void collectImportsFromTypeName(TypeName typeName, Set imports) { + if (typeName instanceof ParameterizedTypeName parameterized) { + collectImportsFromTypeName(parameterized.rawType, imports); + for (var typeArg : parameterized.typeArguments) { + collectImportsFromTypeName(typeArg, imports); + } + } else if (typeName instanceof ClassName name) { + var fqn = fqnIfNeeded(name); + if (fqn != null) { + imports.add(fqn); + } + } + } + + private void writeRecord(String className, List fields, Element element) { + var fqn = targetPackage.isEmpty() ? className : targetPackage + "." + className; + try { + var sourceFile = filer.createSourceFile(fqn, element); + try (var out = new PrintWriter(sourceFile.openWriter())) { + if (!targetPackage.isEmpty()) { + out.println("package " + targetPackage + ";"); + out.println(); + } + + var imports = collectImports(fields); + if (!imports.isEmpty()) { + for (var imp : imports) { + out.println("import " + imp + ";"); + } + out.println(); + } + + var params = + fields.stream().map(f -> f.typeString + " " + f.name).collect(Collectors.joining(", ")); + + out.println("public record " + className + "(" + params + ") {}"); + } + } catch (FilerException e) { + // Type already generated by another interface in the same compilation round + } catch (IOException e) { + messager.printMessage( + Diagnostic.Kind.ERROR, + "Failed to write generated type " + className + ": " + e.getMessage(), + element); + } + } + + static class RecordField { + final String typeString; + final String name; + final String importFqn; + final TypeName typeName; + + RecordField(String typeString, String name, String importFqn) { + this.typeString = typeString; + this.name = name; + this.importFqn = importFqn; + this.typeName = null; + } + + RecordField(String typeString, String name, String importFqn, TypeName typeName) { + this.typeString = typeString; + this.name = name; + this.importFqn = importFqn; + this.typeName = typeName; + } + } +} diff --git a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java new file mode 100644 index 0000000000..cd272b2f25 --- /dev/null +++ b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java @@ -0,0 +1,517 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql.apt; + +import static com.google.testing.compile.CompilationSubject.assertThat; +import static com.google.testing.compile.Compiler.javac; + +import com.google.testing.compile.JavaFileObjects; +import org.junit.jupiter.api.Test; + +class GraphqlSchemaProcessorTest { + + @Test + void validMutationGeneratesTypes() { + var source = + JavaFileObjects.forSourceString( + "test.MyApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface MyApi { + @GraphqlQuery(\""" + mutation createUser($input: CreateUserInput!) { + createUser(input: $input) { id name email status } + }\""") + CreateUserResult createUser(CreateUserInput input); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.CreateUserResult"); + assertThat(compilation).generatedSourceFile("test.CreateUserInput"); + } + + @Test + void invalidQueryReportsError() { + var source = + JavaFileObjects.forSourceString( + "test.BadApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface BadApi { + @GraphqlQuery("{ nonExistentField }") + BadResult query(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("GraphQL validation error"); + } + + @Test + void missingSchemaReportsError() { + var source = + JavaFileObjects.forSourceString( + "test.NoSchemaApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("nonexistent-schema.graphql") + interface NoSchemaApi { + @GraphqlQuery("{ user(id: \\"1\\") { id } }") + Object query(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("GraphQL schema not found"); + } + + @Test + void nestedTypesAreGenerated() { + var source = + JavaFileObjects.forSourceString( + "test.NestedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface NestedApi { + @GraphqlQuery(\""" + { user(id: "1") { id name address { street city country } } } + \""") + UserResult getUser(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.UserResult"); + assertThat(compilation).generatedSourceFile("test.Address"); + } + + @Test + void enumsAreGeneratedAsJavaEnums() { + var source = + JavaFileObjects.forSourceString( + "test.EnumApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface EnumApi { + @GraphqlQuery(\""" + mutation updateStatus($id: ID!, $status: Status!) { + updateStatus(id: $id, status: $status) { id status } + }\""") + StatusResult updateStatus(String id, Status status); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.StatusResult"); + assertThat(compilation).generatedSourceFile("test.Status"); + } + + @Test + void listTypesMapToJavaList() { + var source = + JavaFileObjects.forSourceString( + "test.ListApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface ListApi { + @GraphqlQuery("{ user(id: \\"1\\") { id name tags } }") + UserWithTagsResult getUser(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.UserWithTagsResult"); + } + + @Test + void multipleMethodsSharingInputType() { + var source = + JavaFileObjects.forSourceString( + "test.SharedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface SharedApi { + @GraphqlQuery(\""" + mutation createUser($input: CreateUserInput!) { + createUser(input: $input) { id name } + }\""") + CreateResult1 createUser1(CreateUserInput input); + + @GraphqlQuery(\""" + mutation createUser($input: CreateUserInput!) { + createUser(input: $input) { id email } + }\""") + CreateResult2 createUser2(CreateUserInput input); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.CreateUserInput"); + assertThat(compilation).generatedSourceFile("test.CreateResult1"); + assertThat(compilation).generatedSourceFile("test.CreateResult2"); + } + + @Test + void deeplyNestedOrganizationQuery() { + var source = + JavaFileObjects.forSourceString( + "test.DeepApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface DeepApi { + @GraphqlQuery(\""" + { + organization(id: "1") { + id name + address { street city coordinates { latitude longitude } } + departments { + id name + lead { id name status } + members { id name email } + subDepartments { id name tags { key value } } + tags { key value } + } + metadata { foundedYear industry categories { name tags { key value } } } + } + }\""") + OrgResult getOrganization(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.OrgResult"); + assertThat(compilation).generatedSourceFile("test.Address"); + assertThat(compilation).generatedSourceFile("test.Coordinates"); + assertThat(compilation).generatedSourceFile("test.Departments"); + assertThat(compilation).generatedSourceFile("test.Metadata"); + } + + @Test + void complexMutationWithNestedInputs() { + var source = + JavaFileObjects.forSourceString( + "test.ComplexMutationApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface ComplexMutationApi { + @GraphqlQuery(\""" + mutation createOrg($input: CreateOrgInput!) { + createOrganization(input: $input) { + id name + departments { id name subDepartments { id name } } + } + }\""") + CreateOrgResult createOrg(CreateOrgInput input); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.CreateOrgResult"); + assertThat(compilation).generatedSourceFile("test.CreateOrgInput"); + assertThat(compilation).generatedSourceFile("test.DepartmentInput"); + assertThat(compilation).generatedSourceFile("test.TagInput"); + assertThat(compilation).generatedSourceFile("test.AddressInput"); + assertThat(compilation).generatedSourceFile("test.OrgMetadataInput"); + assertThat(compilation).generatedSourceFile("test.CategoryInput"); + } + + @Test + void searchWithComplexFilterInput() { + var source = + JavaFileObjects.forSourceString( + "test.SearchApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface SearchApi { + @GraphqlQuery(\""" + query searchOrgs($criteria: OrgSearchCriteria!) { + searchOrganizations(criteria: $criteria) { + id name + departments { id name lead { id name } tags { key value } } + metadata { foundedYear categories { name parentCategory { name } } } + } + }\""") + SearchResult searchOrganizations(OrgSearchCriteria criteria); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.SearchResult"); + assertThat(compilation).generatedSourceFile("test.OrgSearchCriteria"); + assertThat(compilation).generatedSourceFile("test.DepartmentFilterInput"); + assertThat(compilation).generatedSourceFile("test.TagInput"); + } + + @Test + void listReturnTypeGeneratesElementType() { + var source = + JavaFileObjects.forSourceString( + "test.ListReturnApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import java.util.List; + + @GraphqlSchema("test-schema.graphql") + interface ListReturnApi { + @GraphqlQuery(\""" + query listUsers($filter: UserFilter) { + users(filter: $filter) { id name email status } + }\""") + List listUsers(UserFilter filter); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.UserListResult"); + assertThat(compilation).generatedSourceFile("test.UserFilter"); + } + + @Test + void existingExternalTypeSkipsGeneration() { + var source = + JavaFileObjects.forSourceString( + "test.ExternalTypeApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface ExternalTypeApi { + @GraphqlQuery(\""" + mutation createUser($input: CreateUserInput!) { + createUser(input: $input) { id name email } + }\""") + CreateResult createUser(feign.graphql.GraphqlQuery input); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.CreateResult"); + } + + @Test + void userWithOrganizationMultipleLevelReuse() { + var source = + JavaFileObjects.forSourceString( + "test.ReuseApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface ReuseApi { + @GraphqlQuery(\""" + { + user(id: "1") { + id name status + address { street city country coordinates { latitude longitude } } + organization { + id name + address { street city coordinates { latitude longitude } } + departments { id name members { id name } } + } + } + }\""") + FullUserResult getFullUser(); + + @GraphqlQuery(\""" + query listUsers($filter: UserFilter) { + users(filter: $filter) { id name email tags } + }\""") + UserListResult listUsers(UserFilter filter); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.FullUserResult"); + assertThat(compilation).generatedSourceFile("test.Status"); + } + + @Test + void scalarAnnotationMapsCustomScalar() { + var source = + JavaFileObjects.forSourceString( + "test.ScalarApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.Scalar; + + @GraphqlSchema("scalar-test-schema.graphql") + interface ScalarApi { + @Scalar("DateTime") + default String dateTime(String raw) { return raw; } + + @GraphqlQuery("{ event(id: \\"1\\") { id name startTime endTime } }") + EventResult getEvent(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.EventResult"); + } + + @Test + void missingScalarAnnotationReportsError() { + var source = + JavaFileObjects.forSourceString( + "test.MissingScalarApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("scalar-test-schema.graphql") + interface MissingScalarApi { + @GraphqlQuery("{ event(id: \\"1\\") { id name startTime } }") + EventResult getEvent(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("Custom scalar 'DateTime'"); + assertThat(compilation).hadErrorContaining("@Scalar(\"DateTime\")"); + } + + @Test + void scalarFromParentInterfaceIsInherited() { + var parentSource = + JavaFileObjects.forSourceString( + "test.ScalarDefinitions", + """ + package test; + + import feign.graphql.Scalar; + + interface ScalarDefinitions { + @Scalar("DateTime") + default String dateTime(String raw) { return raw; } + } + """); + + var source = + JavaFileObjects.forSourceString( + "test.ChildApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("scalar-test-schema.graphql") + interface ChildApi extends ScalarDefinitions { + @GraphqlQuery("{ event(id: \\"1\\") { id name startTime } }") + EventResult getEvent(); + } + """); + + var compilation = + javac().withProcessors(new GraphqlSchemaProcessor()).compile(parentSource, source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.EventResult"); + } +} diff --git a/graphql-apt/src/test/resources/scalar-test-schema.graphql b/graphql-apt/src/test/resources/scalar-test-schema.graphql new file mode 100644 index 0000000000..d8aa82dd05 --- /dev/null +++ b/graphql-apt/src/test/resources/scalar-test-schema.graphql @@ -0,0 +1,14 @@ +"An RFC-3339 compliant DateTime Scalar" +scalar DateTime + +type Query { + event(id: ID!): Event + events: [Event] +} + +type Event { + id: ID! + name: String! + startTime: DateTime! + endTime: DateTime +} diff --git a/graphql-apt/src/test/resources/test-schema.graphql b/graphql-apt/src/test/resources/test-schema.graphql new file mode 100644 index 0000000000..ec88456d8a --- /dev/null +++ b/graphql-apt/src/test/resources/test-schema.graphql @@ -0,0 +1,150 @@ +type Query { + user(id: ID!): User + users(filter: UserFilter): [User] + organization(id: ID!): Organization + searchOrganizations(criteria: OrgSearchCriteria!): [Organization] +} + +type Mutation { + createUser(input: CreateUserInput!): User + updateStatus(id: ID!, status: Status!): User + createOrganization(input: CreateOrgInput!): Organization +} + +type User { + id: ID! + name: String! + email: String + status: Status! + address: Address + tags: [String] + organization: Organization +} + +type Organization { + id: ID! + name: String! + address: Address + departments: [Department] + metadata: OrgMetadata +} + +type Department { + id: ID! + name: String! + lead: User + members: [User] + subDepartments: [Department] + tags: [Tag] +} + +type Tag { + key: String! + value: String! +} + +type OrgMetadata { + foundedYear: Int + industry: String + categories: [Category] +} + +type Category { + name: String! + parentCategory: Category + tags: [Tag] +} + +type Address { + street: String + city: String + country: String + coordinates: Coordinates +} + +type Coordinates { + latitude: Float + longitude: Float +} + +input CreateUserInput { + name: String! + email: String! + status: Status + address: AddressInput + tags: [String] + orgId: ID +} + +input UserFilter { + nameContains: String + status: Status + tagFilter: TagFilterInput +} + +input TagFilterInput { + keys: [String] + matchAll: Boolean +} + +input AddressInput { + street: String + city: String + country: String + coordinates: CoordinatesInput +} + +input CoordinatesInput { + latitude: Float + longitude: Float +} + +input CreateOrgInput { + name: String! + address: AddressInput + departments: [DepartmentInput] + metadata: OrgMetadataInput +} + +input DepartmentInput { + name: String! + leadUserId: ID + subDepartments: [DepartmentInput] + tags: [TagInput] +} + +input TagInput { + key: String! + value: String! +} + +input OrgMetadataInput { + foundedYear: Int + industry: String + categories: [CategoryInput] +} + +input CategoryInput { + name: String! + parentCategoryName: String + tags: [TagInput] +} + +input OrgSearchCriteria { + nameContains: String + industries: [String] + minFoundedYear: Int + departmentFilter: DepartmentFilterInput +} + +input DepartmentFilterInput { + nameContains: String + minMembers: Int + tags: [TagInput] +} + +enum Status { + ACTIVE + INACTIVE + PENDING +} diff --git a/graphql/README.md b/graphql/README.md new file mode 100644 index 0000000000..0f654915eb --- /dev/null +++ b/graphql/README.md @@ -0,0 +1,147 @@ +Feign GraphQL +=================== + +This module adds support for declarative GraphQL clients using Feign. It provides a `GraphqlContract`, `GraphqlEncoder`, and `GraphqlDecoder` that transform annotated interfaces into fully functional GraphQL clients. + +The companion module `feign-graphql-apt` provides compile-time type generation from GraphQL schemas, producing Java records for query results and input types. + +## Dependencies + +Add both modules to use schema-driven type generation: + +```xml + + io.github.openfeign + feign-graphql + ${feign.version} + + + + io.github.openfeign.experimental + feign-graphql-apt + ${feign.version} + provided + +``` + +## Basic Usage + +Define a GraphQL schema in `src/main/resources`: + +```graphql +type Query { + user(id: ID!): User +} + +type User { + id: ID! + name: String! + email: String +} +``` + +Annotate your Feign interface with `@GraphqlSchema` pointing to the schema file and `@GraphqlQuery` on each method with the GraphQL query string: + +```java +@GraphqlSchema("my-schema.graphql") +interface UserApi { + + @GraphqlQuery("query { user(id: $id) { id name email } }") + User getUser(@Param("id") String id); +} +``` + +The annotation processor generates a Java record for `User` at compile time: + +```java +public record User(String id, String name, String email) {} +``` + +Build the client with `GraphqlContract`, `GraphqlEncoder`, and `GraphqlDecoder`: + +```java +UserApi api = Feign.builder() + .contract(new GraphqlContract()) + .encoder(new GraphqlEncoder(new JacksonEncoder())) + .decoder(new GraphqlDecoder()) + .target(UserApi.class, "https://api.example.com/graphql"); + +User user = api.getUser("123"); +``` + +## Mutations with Variables + +Methods with parameters are sent as GraphQL variables: + +```java +@GraphqlSchema("my-schema.graphql") +interface UserApi { + + @GraphqlQuery("mutation($input: CreateUserInput!) { createUser(input: $input) { id name } }") + User createUser(@Param("input") CreateUserInput input); +} +``` + +The processor generates a record for the input type as well: + +```java +public record CreateUserInput(String name, String email) {} +``` + +## Custom Scalars + +When your schema defines custom scalars, map them to Java types using `@Scalar` on default methods: + +```graphql +scalar DateTime + +type Event { + id: ID! + name: String! + startTime: DateTime! +} +``` + +```java +@GraphqlSchema("event-schema.graphql") +interface EventApi { + + @Scalar("DateTime") + default Instant dateTime() { return null; } + + @GraphqlQuery("query { events { id name startTime } }") + List getEvents(); +} +``` + +The processor maps `DateTime` fields to `java.time.Instant` in the generated record: + +```java +public record Event(String id, String name, Instant startTime) {} +``` + +## Disabling Type Generation + +If you provide your own model classes, disable automatic generation: + +```java +@GraphqlSchema(value = "my-schema.graphql", generateTypes = false) +interface UserApi { + // ... +} +``` + +Queries are still validated against the schema at compile time. + +## Error Handling + +GraphQL errors in the response throw `GraphqlErrorException`: + +```java +try { + User user = api.getUser("invalid-id"); +} catch (GraphqlErrorException e) { + String operation = e.operation(); + String errors = e.errors(); +} +``` diff --git a/graphql/pom.xml b/graphql/pom.xml new file mode 100644 index 0000000000..8fdff507fb --- /dev/null +++ b/graphql/pom.xml @@ -0,0 +1,63 @@ + + + + 4.0.0 + + + io.github.openfeign + feign-parent + 13.8-SNAPSHOT + + + feign-graphql + Feign GraphQL + Feign GraphQL runtime support for declarative GraphQL clients + + + + ${project.groupId} + feign-core + + + + com.fasterxml.jackson.core + jackson-databind + + + + ${project.groupId} + feign-core + test-jar + test + + + + com.squareup.okhttp3 + mockwebserver + test + + + + ${project.groupId} + feign-jackson + ${project.version} + test + + + diff --git a/graphql/src/main/java/feign/graphql/GraphqlContract.java b/graphql/src/main/java/feign/graphql/GraphqlContract.java new file mode 100644 index 0000000000..65caffc5ac --- /dev/null +++ b/graphql/src/main/java/feign/graphql/GraphqlContract.java @@ -0,0 +1,100 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import feign.Contract; +import feign.Request.HttpMethod; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GraphqlContract extends Contract.Default { + + private static final Pattern OPERATION_FIELD_PATTERN = + Pattern.compile("\\{\\s*(\\w+)\\s*[({]", Pattern.DOTALL); + + private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\s*(\\w+)\\s*:"); + + private final Map metadata = new ConcurrentHashMap<>(); + + public GraphqlContract() { + super.registerMethodAnnotation( + GraphqlQuery.class, + (annotation, data) -> { + String query = annotation.value(); + + if (data.template().method() == null) { + data.template().method(HttpMethod.POST); + data.template().uri("/"); + } + + String variableName = extractFirstVariable(query); + metadata.put(data.configKey(), new QueryMetadata(query, variableName)); + }); + } + + Map queryMetadata() { + return metadata; + } + + static String extractOperationField(String query) { + int braceCount = 0; + boolean inOperation = false; + + for (int i = 0; i < query.length(); i++) { + char c = query.charAt(i); + if (c == '{') { + braceCount++; + if (braceCount == 1) { + inOperation = true; + } else if (braceCount == 2 && inOperation) { + String prefix = query.substring(0, i).trim(); + Matcher m = OPERATION_FIELD_PATTERN.matcher(prefix + "{"); + if (m.find()) { + return m.group(1); + } + } + } else if (c == '}') { + braceCount--; + } + } + + Matcher m = OPERATION_FIELD_PATTERN.matcher(query); + if (m.find()) { + return m.group(1); + } + return null; + } + + static String extractFirstVariable(String query) { + Matcher m = VARIABLE_PATTERN.matcher(query); + if (m.find()) { + return m.group(1); + } + return null; + } + + static class QueryMetadata { + final String query; + final String variableName; + + QueryMetadata(String query, String variableName) { + this.query = query; + this.variableName = variableName; + } + } +} diff --git a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java new file mode 100644 index 0000000000..060890cb16 --- /dev/null +++ b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java @@ -0,0 +1,129 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import feign.Response; +import feign.Util; +import feign.codec.Decoder; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.lang.reflect.Type; +import java.util.Iterator; + +public class GraphqlDecoder implements Decoder { + + private final ObjectMapper mapper; + private final Decoder delegate; + + public GraphqlDecoder() { + this(new ObjectMapper(), null); + } + + public GraphqlDecoder(ObjectMapper mapper) { + this(mapper, null); + } + + public GraphqlDecoder(Decoder delegate) { + this(new ObjectMapper(), delegate); + } + + public GraphqlDecoder(ObjectMapper mapper, Decoder delegate) { + this.mapper = mapper; + this.delegate = delegate; + } + + @Override + public Object decode(Response response, Type type) throws IOException { + if (response.status() == 404 || response.status() == 204) { + return Util.emptyValueOf(type); + } + if (response.body() == null) { + return null; + } + + Reader reader = response.body().asReader(response.charset()); + if (!reader.markSupported()) { + reader = new BufferedReader(reader, 1); + } + + JsonNode root = mapper.readTree(reader); + + JsonNode errorsNode = root.path("errors"); + if (!errorsNode.isMissingNode() && errorsNode.isArray() && !errorsNode.isEmpty()) { + String operationField = resolveOperationField(root, response); + throw new GraphqlErrorException( + response.status(), operationField, errorsNode.toString(), response.request()); + } + + JsonNode dataNode = root.path("data"); + if (dataNode.isMissingNode() || dataNode.isNull() || !dataNode.isObject()) { + return Util.emptyValueOf(type); + } + + Iterator fieldNames = dataNode.fieldNames(); + if (!fieldNames.hasNext()) { + return Util.emptyValueOf(type); + } + + String firstField = fieldNames.next(); + JsonNode operationData = dataNode.get(firstField); + if (operationData == null || operationData.isNull()) { + return Util.emptyValueOf(type); + } + + if (delegate != null) { + byte[] dataBytes = mapper.writeValueAsBytes(operationData); + Response dataResponse = + Response.builder() + .status(response.status()) + .reason(response.reason()) + .headers(response.headers()) + .request(response.request()) + .body(dataBytes) + .build(); + return delegate.decode(dataResponse, type); + } + + return mapper.readValue(mapper.treeAsTokens(operationData), mapper.constructType(type)); + } + + private String resolveOperationField(JsonNode root, Response response) { + JsonNode dataNode = root.path("data"); + if (!dataNode.isMissingNode() && dataNode.isObject()) { + Iterator names = dataNode.fieldNames(); + if (names.hasNext()) { + return names.next(); + } + } + + if (response.request() != null && response.request().body() != null) { + try { + JsonNode requestBody = mapper.readTree(response.request().body()); + String query = requestBody.path("query").asText(null); + if (query != null) { + return GraphqlContract.extractOperationField(query); + } + } catch (Exception e) { + // ignore parsing errors + } + } + + return "unknown"; + } +} diff --git a/graphql/src/main/java/feign/graphql/GraphqlEncoder.java b/graphql/src/main/java/feign/graphql/GraphqlEncoder.java new file mode 100644 index 0000000000..a3d1aaa30a --- /dev/null +++ b/graphql/src/main/java/feign/graphql/GraphqlEncoder.java @@ -0,0 +1,80 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import feign.RequestInterceptor; +import feign.RequestTemplate; +import feign.codec.EncodeException; +import feign.codec.Encoder; +import java.lang.reflect.Type; +import java.util.LinkedHashMap; +import java.util.Map; + +public class GraphqlEncoder implements Encoder, RequestInterceptor { + + private final Encoder delegate; + private final Map queryMetadata; + + public GraphqlEncoder(Encoder delegate, GraphqlContract contract) { + this.delegate = delegate; + this.queryMetadata = contract.queryMetadata(); + } + + @Override + public void encode(Object object, Type bodyType, RequestTemplate template) + throws EncodeException { + GraphqlContract.QueryMetadata meta = lookupMetadata(template); + if (meta == null) { + delegate.encode(object, bodyType, template); + return; + } + + Map graphqlBody = new LinkedHashMap<>(); + graphqlBody.put("query", meta.query); + + if (object != null && meta.variableName != null) { + Map variables = new LinkedHashMap<>(); + variables.put(meta.variableName, object); + graphqlBody.put("variables", variables); + } + + delegate.encode(graphqlBody, MAP_STRING_WILDCARD, template); + } + + @Override + public void apply(RequestTemplate template) { + if (template.body() != null) { + return; + } + + GraphqlContract.QueryMetadata meta = lookupMetadata(template); + if (meta == null) { + return; + } + + Map graphqlBody = new LinkedHashMap<>(); + graphqlBody.put("query", meta.query); + + delegate.encode(graphqlBody, MAP_STRING_WILDCARD, template); + } + + private GraphqlContract.QueryMetadata lookupMetadata(RequestTemplate template) { + if (template.methodMetadata() == null) { + return null; + } + return queryMetadata.get(template.methodMetadata().configKey()); + } +} diff --git a/graphql/src/main/java/feign/graphql/GraphqlErrorException.java b/graphql/src/main/java/feign/graphql/GraphqlErrorException.java new file mode 100644 index 0000000000..942b96fed7 --- /dev/null +++ b/graphql/src/main/java/feign/graphql/GraphqlErrorException.java @@ -0,0 +1,39 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import feign.FeignException; +import feign.Request; + +public class GraphqlErrorException extends FeignException { + + private final String operation; + private final String errors; + + public GraphqlErrorException(int status, String operation, String errors, Request request) { + super(status, String.format("GraphQL %s operation failed: %s", operation, errors), request); + this.operation = operation; + this.errors = errors; + } + + public String operation() { + return operation; + } + + public String errors() { + return errors; + } +} diff --git a/graphql/src/main/java/feign/graphql/GraphqlQuery.java b/graphql/src/main/java/feign/graphql/GraphqlQuery.java new file mode 100644 index 0000000000..beef534899 --- /dev/null +++ b/graphql/src/main/java/feign/graphql/GraphqlQuery.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface GraphqlQuery { + + String value(); +} diff --git a/graphql/src/main/java/feign/graphql/GraphqlSchema.java b/graphql/src/main/java/feign/graphql/GraphqlSchema.java new file mode 100644 index 0000000000..785bdf19c2 --- /dev/null +++ b/graphql/src/main/java/feign/graphql/GraphqlSchema.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface GraphqlSchema { + + String value(); + + boolean generateTypes() default true; +} diff --git a/graphql/src/main/java/feign/graphql/Scalar.java b/graphql/src/main/java/feign/graphql/Scalar.java new file mode 100644 index 0000000000..1a9ba21e5d --- /dev/null +++ b/graphql/src/main/java/feign/graphql/Scalar.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Scalar { + + String value(); +} diff --git a/graphql/src/test/java/feign/graphql/GraphqlClientTest.java b/graphql/src/test/java/feign/graphql/GraphqlClientTest.java new file mode 100644 index 0000000000..ce47c4e0fe --- /dev/null +++ b/graphql/src/test/java/feign/graphql/GraphqlClientTest.java @@ -0,0 +1,190 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import feign.Feign; +import feign.Headers; +import feign.Param; +import feign.jackson.JacksonEncoder; +import java.util.List; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class GraphqlClientTest { + + private final ObjectMapper mapper = + new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + private MockWebServer server; + + public static class User { + public String id; + public String name; + public String email; + } + + public static class CreateUserInput { + public String name; + public String email; + } + + public static class CreateUserResult { + public String id; + public String name; + } + + @Headers("Content-Type: application/json") + interface TestApi { + + @GraphqlQuery( + "mutation createUser($input: CreateUserInput!) {" + + " createUser(input: $input) { id name } }") + CreateUserResult createUser(CreateUserInput input); + + @GraphqlQuery("query getUser($id: String!) {" + " getUser(id: $id) { id name email } }") + User getUser(String id); + + @GraphqlQuery("query listPending { listPending { id name } }") + List listPending(); + + @GraphqlQuery("query getUser($id: String!) {" + " getUser(id: $id) { id name email } }") + @Headers("Authorization: {auth}") + User getUserWithAuth(@Param("auth") String auth, String id); + } + + @BeforeEach + void setUp() throws Exception { + server = new MockWebServer(); + server.start(); + } + + @AfterEach + void tearDown() throws Exception { + server.shutdown(); + } + + private TestApi buildClient() { + var contract = new GraphqlContract(); + var graphqlEncoder = new GraphqlEncoder(new JacksonEncoder(mapper), contract); + return Feign.builder() + .contract(contract) + .encoder(graphqlEncoder) + .decoder(new GraphqlDecoder(mapper)) + .requestInterceptor(graphqlEncoder) + .target(TestApi.class, server.url("/graphql").toString()); + } + + @Test + void mutationWithVariables() throws Exception { + server.enqueue( + new MockResponse() + .setBody("{\"data\":{\"createUser\":{\"id\":\"42\",\"name\":\"Alice\"}}}") + .addHeader("Content-Type", "application/json")); + + var input = new CreateUserInput(); + input.name = "Alice"; + input.email = "alice@example.com"; + + var result = buildClient().createUser(input); + + assertThat(result.id).isEqualTo("42"); + assertThat(result.name).isEqualTo("Alice"); + + var recorded = server.takeRequest(); + assertThat(recorded.getMethod()).isEqualTo("POST"); + var body = mapper.readTree(recorded.getBody().readUtf8()); + assertThat(body.get("query").asText()).contains("createUser"); + assertThat(body.get("variables").get("input").get("name").asText()).isEqualTo("Alice"); + } + + @Test + void queryWithStringVariable() throws Exception { + server.enqueue( + new MockResponse() + .setBody( + "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Bob\",\"email\":\"bob@test.com\"}}}") + .addHeader("Content-Type", "application/json")); + + var user = buildClient().getUser("1"); + + assertThat(user.id).isEqualTo("1"); + assertThat(user.name).isEqualTo("Bob"); + assertThat(user.email).isEqualTo("bob@test.com"); + + var recorded = server.takeRequest(); + var body = mapper.readTree(recorded.getBody().readUtf8()); + assertThat(body.get("variables").get("id").asText()).isEqualTo("1"); + } + + @Test + void noVariableQuerySetsBodyViaInterceptor() throws Exception { + server.enqueue( + new MockResponse() + .setBody( + "{\"data\":{\"listPending\":[{\"id\":\"1\",\"name\":\"A\"},{\"id\":\"2\",\"name\":\"B\"}]}}") + .addHeader("Content-Type", "application/json")); + + var users = buildClient().listPending(); + + assertThat(users).hasSize(2); + assertThat(users.getFirst().name).isEqualTo("A"); + + var recorded = server.takeRequest(); + var body = mapper.readTree(recorded.getBody().readUtf8()); + assertThat(body.get("query").asText()).contains("listPending"); + assertThat(body.has("variables")).isFalse(); + } + + @Test + void graphqlErrorsThrowException() { + server.enqueue( + new MockResponse() + .setBody("{\"errors\":[{\"message\":\"Something went wrong\"}],\"data\":null}") + .addHeader("Content-Type", "application/json")); + + var input = new CreateUserInput(); + input.name = "Alice"; + + assertThatThrownBy(() -> buildClient().createUser(input)) + .isInstanceOf(GraphqlErrorException.class) + .hasMessageContaining("createUser") + .hasMessageContaining("Something went wrong"); + } + + @Test + void authHeaderPassedThrough() throws Exception { + server.enqueue( + new MockResponse() + .setBody( + "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Bob\",\"email\":\"bob@test.com\"}}}") + .addHeader("Content-Type", "application/json")); + + var user = buildClient().getUserWithAuth("Bearer mytoken", "1"); + + assertThat(user.id).isEqualTo("1"); + + var recorded = server.takeRequest(); + assertThat(recorded.getHeader("Authorization")).isEqualTo("Bearer mytoken"); + } +} diff --git a/graphql/src/test/java/feign/graphql/GraphqlContractTest.java b/graphql/src/test/java/feign/graphql/GraphqlContractTest.java new file mode 100644 index 0000000000..ec5846cf6f --- /dev/null +++ b/graphql/src/test/java/feign/graphql/GraphqlContractTest.java @@ -0,0 +1,121 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import static org.assertj.core.api.Assertions.assertThat; + +import feign.Request.HttpMethod; +import org.junit.jupiter.api.Test; + +class GraphqlContractTest { + + private final GraphqlContract contract = new GraphqlContract(); + + interface MutationApi { + @GraphqlQuery( + "mutation backendUpdateRuntimeStatus($event: RuntimeStatusInput!) {" + + " backendUpdateRuntimeStatus(event: $event) { _uuid deploymentId } }") + Object updateStatus(Object event); + } + + interface QueryWithVariableApi { + @GraphqlQuery( + "query backendProjectsLookup($projectId: String!) {" + + " backendProjectsLookup(projectId: $projectId) { projectId orgId } }") + Object lookup(String projectId); + } + + interface NoVariableQueryApi { + @GraphqlQuery( + "query backendPendingDeployments {" + + " backendPendingDeployments { projectId environment } }") + Object pending(); + } + + @Test + void mutationSetsPostMethod() { + var metadata = contract.parseAndValidateMetadata(MutationApi.class); + assertThat(metadata).hasSize(1); + assertThat(metadata.getFirst().template().method()).isEqualTo(HttpMethod.POST.name()); + } + + @Test + void mutationStoresQueryMetadata() { + contract.parseAndValidateMetadata(MutationApi.class); + assertThat(contract.queryMetadata()).hasSize(1); + var meta = contract.queryMetadata().values().iterator().next(); + assertThat(meta.query).contains("backendUpdateRuntimeStatus"); + assertThat(meta.variableName).isEqualTo("event"); + } + + @Test + void queryWithVariableStoresMetadata() { + contract.parseAndValidateMetadata(QueryWithVariableApi.class); + assertThat(contract.queryMetadata()).hasSize(1); + var meta = contract.queryMetadata().values().iterator().next(); + assertThat(meta.query).contains("backendProjectsLookup"); + assertThat(meta.variableName).isEqualTo("projectId"); + } + + @Test + void noVariableQueryHasNullVariableName() { + contract.parseAndValidateMetadata(NoVariableQueryApi.class); + assertThat(contract.queryMetadata()).hasSize(1); + var meta = contract.queryMetadata().values().iterator().next(); + assertThat(meta.query).contains("backendPendingDeployments"); + assertThat(meta.variableName).isNull(); + } + + @Test + void noHeadersSetOnTemplate() { + var metadata = contract.parseAndValidateMetadata(MutationApi.class); + var headers = metadata.getFirst().template().headers(); + assertThat(headers).isEmpty(); + } + + @Test + void extractOperationFieldFromMutation() { + var query = + "mutation backendUpdateRuntimeStatus($event: RuntimeStatusInput!) {" + + " backendUpdateRuntimeStatus(event: $event) { _uuid } }"; + assertThat(GraphqlContract.extractOperationField(query)) + .isEqualTo("backendUpdateRuntimeStatus"); + } + + @Test + void extractOperationFieldFromSimpleQuery() { + var query = "query backendPendingDeployments { backendPendingDeployments { projectId } }"; + assertThat(GraphqlContract.extractOperationField(query)).isEqualTo("backendPendingDeployments"); + } + + @Test + void extractOperationFieldFromAnonymousQuery() { + var query = "{ user(id: \"1\") { id name } }"; + assertThat(GraphqlContract.extractOperationField(query)).isEqualTo("user"); + } + + @Test + void extractFirstVariableFromMutation() { + var query = "mutation backendUpdateRuntimeStatus($event: RuntimeStatusInput!) { x }"; + assertThat(GraphqlContract.extractFirstVariable(query)).isEqualTo("event"); + } + + @Test + void extractFirstVariableReturnsNullWhenNone() { + var query = "query backendPendingDeployments { x }"; + assertThat(GraphqlContract.extractFirstVariable(query)).isNull(); + } +} diff --git a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java new file mode 100644 index 0000000000..045d15cf3c --- /dev/null +++ b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java @@ -0,0 +1,148 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import feign.Request; +import feign.Request.HttpMethod; +import feign.Response; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; + +class GraphqlDecoderTest { + + private final ObjectMapper mapper = + new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private final GraphqlDecoder decoder = new GraphqlDecoder(mapper); + + public static class User { + public String id; + public String name; + } + + @Test + void decodesDataField() throws Exception { + var json = "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Alice\"}}}"; + var response = buildResponse(json); + + var user = (User) decoder.decode(response, User.class); + + assertThat(user.id).isEqualTo("1"); + assertThat(user.name).isEqualTo("Alice"); + } + + @Test + void decodesListResponse() throws Exception { + var json = + "{\"data\":{\"listUsers\":[{\"id\":\"1\",\"name\":\"Alice\"},{\"id\":\"2\",\"name\":\"Bob\"}]}}"; + var response = buildResponse(json); + + @SuppressWarnings("unchecked") + var users = + (List) + decoder.decode( + response, mapper.getTypeFactory().constructCollectionType(List.class, User.class)); + + assertThat(users).hasSize(2); + assertThat(users.getFirst().name).isEqualTo("Alice"); + assertThat(users.get(1).name).isEqualTo("Bob"); + } + + @Test + void throwsGraphqlErrorExceptionOnErrors() { + var json = "{\"errors\":[{\"message\":\"Not found\"}],\"data\":{\"getUser\":null}}"; + var response = buildResponse(json); + + assertThatThrownBy(() -> decoder.decode(response, User.class)) + .isInstanceOf(GraphqlErrorException.class) + .hasMessageContaining("getUser") + .hasMessageContaining("Not found"); + } + + @Test + void returnsNullForNullData() throws Exception { + var json = "{\"data\":{\"getUser\":null}}"; + var response = buildResponse(json); + + var result = decoder.decode(response, User.class); + assertThat(result).isNull(); + } + + @Test + void returnsNullForEmptyData() throws Exception { + var json = "{\"data\":{}}"; + var response = buildResponse(json); + + var result = decoder.decode(response, User.class); + assertThat(result).isNull(); + } + + @Test + void returnsEmptyFor404() throws Exception { + var response = + Response.builder() + .status(404) + .reason("Not Found") + .headers(Collections.emptyMap()) + .request(buildRequest()) + .body(new byte[0]) + .build(); + + var result = decoder.decode(response, User.class); + assertThat(result).isNull(); + } + + @Test + void delegatesToCustomDecoder() throws Exception { + var json = "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Alice\"}}}"; + var customDecoder = + new GraphqlDecoder( + mapper, + (resp, type) -> + mapper.readValue(resp.body().asReader(resp.charset()), mapper.constructType(type))); + var response = buildResponse(json); + + var user = (User) customDecoder.decode(response, User.class); + + assertThat(user.id).isEqualTo("1"); + assertThat(user.name).isEqualTo("Alice"); + } + + private Response buildResponse(String body) { + return Response.builder() + .status(200) + .reason("OK") + .headers(Collections.emptyMap()) + .request(buildRequest()) + .body(body, StandardCharsets.UTF_8) + .build(); + } + + private Request buildRequest() { + return Request.create( + HttpMethod.POST, + "http://localhost/graphql", + Collections.emptyMap(), + Request.Body.empty(), + null); + } +} diff --git a/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java new file mode 100644 index 0000000000..a8b8f0eeb7 --- /dev/null +++ b/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java @@ -0,0 +1,97 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.databind.ObjectMapper; +import feign.RequestTemplate; +import feign.jackson.JacksonEncoder; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class GraphqlEncoderTest { + + private final ObjectMapper mapper = new ObjectMapper(); + private final GraphqlContract contract = new GraphqlContract(); + private final GraphqlEncoder encoder = new GraphqlEncoder(new JacksonEncoder(mapper), contract); + + interface MutationApi { + @GraphqlQuery( + "mutation createUser($input: CreateUserInput!) { createUser(input: $input) { id } }") + Object createUser(Object input); + } + + interface NoVariableApi { + @GraphqlQuery("query pending { pending { id } }") + Object pending(); + } + + private RequestTemplate templateFor(Class apiClass) { + var metadataList = contract.parseAndValidateMetadata(apiClass); + var md = metadataList.getFirst(); + var template = new RequestTemplate(); + template.methodMetadata(md); + return template; + } + + @Test + void encodesBodyWithVariables() throws Exception { + var template = templateFor(MutationApi.class); + var body = Map.of("name", "John", "email", "john@example.com"); + encoder.encode(body, Map.class, template); + + var result = mapper.readTree(template.body()); + assertThat(result.has("query")).isTrue(); + assertThat(result.get("query").asText()).contains("createUser"); + assertThat(result.has("variables")).isTrue(); + assertThat(result.get("variables").has("input")).isTrue(); + assertThat(result.get("variables").get("input").get("name").asText()).isEqualTo("John"); + } + + @Test + void delegatesToWrappedEncoderForNonGraphql() { + var template = new RequestTemplate(); + encoder.encode("plain body", String.class, template); + assertThat(template.body()).isNotNull(); + } + + @Test + void interceptorSetsBodyForNoVariableQuery() throws Exception { + var template = templateFor(NoVariableApi.class); + encoder.apply(template); + + var result = mapper.readTree(template.body()); + assertThat(result.get("query").asText()).contains("pending"); + assertThat(result.has("variables")).isFalse(); + } + + @Test + void interceptorSkipsWhenBodyAlreadySet() { + var template = templateFor(MutationApi.class); + template.body("already set"); + encoder.apply(template); + assertThat(new String(template.body())).isEqualTo("already set"); + } + + @Test + void interceptorSkipsForNonGraphql() { + var template = new RequestTemplate(); + template.body("some body"); + encoder.apply(template); + assertThat(new String(template.body())).isEqualTo("some body"); + } +} diff --git a/pom.xml b/pom.xml index a110ef4e42..cc3a8c2386 100644 --- a/pom.xml +++ b/pom.xml @@ -117,6 +117,8 @@ micrometer mock apt-test-generator + graphql + graphql-apt annotation-error-decoder example-github example-github-with-coroutine @@ -212,9 +214,11 @@ 1.6.0 1.15.0 0.23.0 + 22.4 4.5.0 4.5.14 5.6 + 1.13.0 1.5.18 3.1.0 4.0.0 @@ -411,6 +415,12 @@ test + + ${project.groupId} + feign-graphql + ${project.version} + + ${project.groupId} feign-form diff --git a/src/docs/overview-mindmap.iuml b/src/docs/overview-mindmap.iuml index d4fa6d0698..bd84375752 100644 --- a/src/docs/overview-mindmap.iuml +++ b/src/docs/overview-mindmap.iuml @@ -13,15 +13,20 @@ *** Apache HC5 *** OkHttp *** Vertx +*** Reactive Wrappers ** contracts *** Feign *** JAX-RS *** JAX-RS 2 *** JAX-RS 3 / Jakarta -*** Spring 5 +*** JAX-RS 4 +*** Spring *** SOAP *** SOAP Jakarta *** Spring boot (3rd party) +** language +*** Kotlin +*** GraphQL left side @@ -29,15 +34,18 @@ left side *** GSON *** JAXB *** JAXB Jakarta -*** Jackson 1 -*** Jackson 2 +*** Jackson +*** Jackson 3 *** Jackson JAXB *** Jackson Jr *** Sax *** JSON-java *** Moshi *** Fastjson2 +*** Form +*** Form Spring ** metrics +*** Dropwizard Metrics 4 *** Dropwizard Metrics 5 *** Micrometer ** extras diff --git a/vertx/pom.xml b/vertx/pom.xml index d5be4fd4ed..c3fd09e8c7 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -26,6 +26,7 @@ feign-vertx-parent pom + Feign Vertx (Parent) feign-vertx From eced437cc26c72f0e7ad9f143c05e6053f7b2651 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:01:39 -0300 Subject: [PATCH 361/615] build(deps): Bump tools.jackson:jackson-bom from 3.0.2 to 3.0.4 (#3213) Bumps [tools.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 3.0.2 to 3.0.4. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-3.0.2...jackson-bom-3.0.4) --- updated-dependencies: - dependency-name: tools.jackson:jackson-bom dependency-version: 3.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cc3a8c2386..671951ca2e 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 6.0.2 2.21.0 - 3.0.2 + 3.0.4 3.27.7 5.21.0 2.0.61.android8 From 8cb8293945b65c2b9c4c80666ff23c74e03becc4 Mon Sep 17 00:00:00 2001 From: NiMv1 <54713626+NiMv1@users.noreply.github.com> Date: Mon, 9 Feb 2026 21:02:33 +0300 Subject: [PATCH 362/615] Add methodKey to RetryableException (#3157) * Add methodKey to RetryableException for better retry identification * Apply code formatting --------- Co-authored-by: NiMv1 --- .../main/java/feign/RetryableException.java | 46 ++++++++++++++++++- .../main/java/feign/codec/ErrorDecoder.java | 3 +- .../java/feign/RetryableExceptionTest.java | 41 +++++++++++++++++ 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/feign/RetryableException.java b/core/src/main/java/feign/RetryableException.java index 2e210fef6d..6c69986316 100644 --- a/core/src/main/java/feign/RetryableException.java +++ b/core/src/main/java/feign/RetryableException.java @@ -26,10 +26,11 @@ */ public class RetryableException extends FeignException { - private static final long serialVersionUID = 2L; + private static final long serialVersionUID = 3L; private final Long retryAfter; private final HttpMethod httpMethod; + private final String methodKey; /** * Represents a non-retryable exception when Retry-After information is explicitly not provided. @@ -46,6 +47,7 @@ public RetryableException(int status, String message, HttpMethod httpMethod, Req super(status, message, request); this.httpMethod = httpMethod; this.retryAfter = null; + this.methodKey = null; } /** @@ -65,6 +67,7 @@ public RetryableException( super(status, message, request, cause); this.httpMethod = httpMethod; this.retryAfter = null; + this.methodKey = null; } /** @@ -95,6 +98,32 @@ public RetryableException( super(status, message, request, cause); this.httpMethod = httpMethod; this.retryAfter = retryAfter; + this.methodKey = null; + } + + /** + * Represents a retryable exception with methodKey for identifying the method being retried. + * + * @param status the HTTP status code + * @param message the exception message + * @param httpMethod the HTTP method (GET, POST, etc.) + * @param cause the underlying cause of the exception + * @param retryAfter the retry delay in milliseconds + * @param request the original HTTP request + * @param methodKey the method key identifying the Feign method + */ + public RetryableException( + int status, + String message, + HttpMethod httpMethod, + Throwable cause, + Long retryAfter, + Request request, + String methodKey) { + super(status, message, request, cause); + this.httpMethod = httpMethod; + this.retryAfter = retryAfter; + this.methodKey = methodKey; } /** @@ -119,6 +148,7 @@ public RetryableException( super(status, message, request, cause); this.httpMethod = httpMethod; this.retryAfter = retryAfter != null ? retryAfter.getTime() : null; + this.methodKey = null; } /** @@ -139,6 +169,7 @@ public RetryableException( super(status, message, request); this.httpMethod = httpMethod; this.retryAfter = retryAfter; + this.methodKey = null; } /** @@ -156,6 +187,7 @@ public RetryableException( super(status, message, request); this.httpMethod = httpMethod; this.retryAfter = retryAfter != null ? retryAfter.getTime() : null; + this.methodKey = null; } /** @@ -183,6 +215,7 @@ public RetryableException( super(status, message, request, responseBody, responseHeaders); this.httpMethod = httpMethod; this.retryAfter = retryAfter; + this.methodKey = null; } /** @@ -209,6 +242,7 @@ public RetryableException( super(status, message, request, responseBody, responseHeaders); this.httpMethod = httpMethod; this.retryAfter = retryAfter != null ? retryAfter.getTime() : null; + this.methodKey = null; } /** @@ -222,4 +256,14 @@ public Long retryAfter() { public HttpMethod method() { return this.httpMethod; } + + /** + * Returns the method key identifying the Feign method that was being invoked. This corresponds to + * the methodKey parameter in {@link feign.codec.ErrorDecoder#decode}. + * + * @return the method key, or null if not set + */ + public String methodKey() { + return this.methodKey; + } } diff --git a/core/src/main/java/feign/codec/ErrorDecoder.java b/core/src/main/java/feign/codec/ErrorDecoder.java index 29f07a0b2b..83c72ee887 100644 --- a/core/src/main/java/feign/codec/ErrorDecoder.java +++ b/core/src/main/java/feign/codec/ErrorDecoder.java @@ -109,7 +109,8 @@ public Exception decode(String methodKey, Response response) { response.request().httpMethod(), exception, retryAfter, - response.request()); + response.request(), + methodKey); } return exception; } diff --git a/core/src/test/java/feign/RetryableExceptionTest.java b/core/src/test/java/feign/RetryableExceptionTest.java index 6e60e6482a..0bd9a73127 100644 --- a/core/src/test/java/feign/RetryableExceptionTest.java +++ b/core/src/test/java/feign/RetryableExceptionTest.java @@ -49,4 +49,45 @@ void createRetryableExceptionWithResponseAndResponseHeader() { assertThat(retryableException.responseHeaders()).containsKey("TEST_HEADER"); assertThat(retryableException.responseHeaders().get("TEST_HEADER")).contains("TEST_CONTENT"); } + + @Test + void createRetryableExceptionWithMethodKey() { + // given + Long retryAfter = 5000L; + String methodKey = "TestClient#testMethod()"; + Request request = + Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8); + Throwable cause = new RuntimeException("test cause"); + + // when + RetryableException retryableException = + new RetryableException( + 503, + "Service Unavailable", + Request.HttpMethod.GET, + cause, + retryAfter, + request, + methodKey); + + // then + assertThat(retryableException).isNotNull(); + assertThat(retryableException.methodKey()).isEqualTo(methodKey); + assertThat(retryableException.retryAfter()).isEqualTo(retryAfter); + assertThat(retryableException.method()).isEqualTo(Request.HttpMethod.GET); + } + + @Test + void methodKeyIsNullWhenNotProvided() { + // given + Request request = + Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8); + + // when + RetryableException retryableException = + new RetryableException(503, "Service Unavailable", Request.HttpMethod.GET, request); + + // then + assertThat(retryableException.methodKey()).isNull(); + } } From 1a89b5adc700d998878be312458b13d81da40048 Mon Sep 17 00:00:00 2001 From: Marvin Date: Mon, 9 Feb 2026 15:27:16 -0300 Subject: [PATCH 363/615] Set graphql module to Java 17, apply var and clean up imports (#3215) Signed-off-by: Marvin Froeder --- graphql/pom.xml | 4 +++ .../java/feign/graphql/GraphqlContract.java | 13 ++++---- .../java/feign/graphql/GraphqlDecoder.java | 30 +++++++++---------- .../java/feign/graphql/GraphqlEncoder.java | 10 +++---- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/graphql/pom.xml b/graphql/pom.xml index 8fdff507fb..3c446afe1d 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -29,6 +29,10 @@ Feign GraphQL Feign GraphQL runtime support for declarative GraphQL clients + + 17 + + ${project.groupId} diff --git a/graphql/src/main/java/feign/graphql/GraphqlContract.java b/graphql/src/main/java/feign/graphql/GraphqlContract.java index 65caffc5ac..6f089e8555 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlContract.java +++ b/graphql/src/main/java/feign/graphql/GraphqlContract.java @@ -19,7 +19,6 @@ import feign.Request.HttpMethod; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Matcher; import java.util.regex.Pattern; public class GraphqlContract extends Contract.Default { @@ -35,14 +34,14 @@ public GraphqlContract() { super.registerMethodAnnotation( GraphqlQuery.class, (annotation, data) -> { - String query = annotation.value(); + var query = annotation.value(); if (data.template().method() == null) { data.template().method(HttpMethod.POST); data.template().uri("/"); } - String variableName = extractFirstVariable(query); + var variableName = extractFirstVariable(query); metadata.put(data.configKey(), new QueryMetadata(query, variableName)); }); } @@ -62,8 +61,8 @@ static String extractOperationField(String query) { if (braceCount == 1) { inOperation = true; } else if (braceCount == 2 && inOperation) { - String prefix = query.substring(0, i).trim(); - Matcher m = OPERATION_FIELD_PATTERN.matcher(prefix + "{"); + var prefix = query.substring(0, i).trim(); + var m = OPERATION_FIELD_PATTERN.matcher(prefix + "{"); if (m.find()) { return m.group(1); } @@ -73,7 +72,7 @@ static String extractOperationField(String query) { } } - Matcher m = OPERATION_FIELD_PATTERN.matcher(query); + var m = OPERATION_FIELD_PATTERN.matcher(query); if (m.find()) { return m.group(1); } @@ -81,7 +80,7 @@ static String extractOperationField(String query) { } static String extractFirstVariable(String query) { - Matcher m = VARIABLE_PATTERN.matcher(query); + var m = VARIABLE_PATTERN.matcher(query); if (m.find()) { return m.group(1); } diff --git a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java index 060890cb16..3560341054 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java @@ -22,9 +22,7 @@ import feign.codec.Decoder; import java.io.BufferedReader; import java.io.IOException; -import java.io.Reader; import java.lang.reflect.Type; -import java.util.Iterator; public class GraphqlDecoder implements Decoder { @@ -57,39 +55,39 @@ public Object decode(Response response, Type type) throws IOException { return null; } - Reader reader = response.body().asReader(response.charset()); + var reader = response.body().asReader(response.charset()); if (!reader.markSupported()) { reader = new BufferedReader(reader, 1); } - JsonNode root = mapper.readTree(reader); + var root = mapper.readTree(reader); - JsonNode errorsNode = root.path("errors"); + var errorsNode = root.path("errors"); if (!errorsNode.isMissingNode() && errorsNode.isArray() && !errorsNode.isEmpty()) { - String operationField = resolveOperationField(root, response); + var operationField = resolveOperationField(root, response); throw new GraphqlErrorException( response.status(), operationField, errorsNode.toString(), response.request()); } - JsonNode dataNode = root.path("data"); + var dataNode = root.path("data"); if (dataNode.isMissingNode() || dataNode.isNull() || !dataNode.isObject()) { return Util.emptyValueOf(type); } - Iterator fieldNames = dataNode.fieldNames(); + var fieldNames = dataNode.fieldNames(); if (!fieldNames.hasNext()) { return Util.emptyValueOf(type); } - String firstField = fieldNames.next(); - JsonNode operationData = dataNode.get(firstField); + var firstField = fieldNames.next(); + var operationData = dataNode.get(firstField); if (operationData == null || operationData.isNull()) { return Util.emptyValueOf(type); } if (delegate != null) { - byte[] dataBytes = mapper.writeValueAsBytes(operationData); - Response dataResponse = + var dataBytes = mapper.writeValueAsBytes(operationData); + var dataResponse = Response.builder() .status(response.status()) .reason(response.reason()) @@ -104,9 +102,9 @@ public Object decode(Response response, Type type) throws IOException { } private String resolveOperationField(JsonNode root, Response response) { - JsonNode dataNode = root.path("data"); + var dataNode = root.path("data"); if (!dataNode.isMissingNode() && dataNode.isObject()) { - Iterator names = dataNode.fieldNames(); + var names = dataNode.fieldNames(); if (names.hasNext()) { return names.next(); } @@ -114,8 +112,8 @@ private String resolveOperationField(JsonNode root, Response response) { if (response.request() != null && response.request().body() != null) { try { - JsonNode requestBody = mapper.readTree(response.request().body()); - String query = requestBody.path("query").asText(null); + var requestBody = mapper.readTree(response.request().body()); + var query = requestBody.path("query").asText(null); if (query != null) { return GraphqlContract.extractOperationField(query); } diff --git a/graphql/src/main/java/feign/graphql/GraphqlEncoder.java b/graphql/src/main/java/feign/graphql/GraphqlEncoder.java index a3d1aaa30a..391d8a5678 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlEncoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlEncoder.java @@ -36,17 +36,17 @@ public GraphqlEncoder(Encoder delegate, GraphqlContract contract) { @Override public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { - GraphqlContract.QueryMetadata meta = lookupMetadata(template); + var meta = lookupMetadata(template); if (meta == null) { delegate.encode(object, bodyType, template); return; } - Map graphqlBody = new LinkedHashMap<>(); + var graphqlBody = new LinkedHashMap(); graphqlBody.put("query", meta.query); if (object != null && meta.variableName != null) { - Map variables = new LinkedHashMap<>(); + var variables = new LinkedHashMap(); variables.put(meta.variableName, object); graphqlBody.put("variables", variables); } @@ -60,12 +60,12 @@ public void apply(RequestTemplate template) { return; } - GraphqlContract.QueryMetadata meta = lookupMetadata(template); + var meta = lookupMetadata(template); if (meta == null) { return; } - Map graphqlBody = new LinkedHashMap<>(); + var graphqlBody = new LinkedHashMap(); graphqlBody.put("query", meta.query); delegate.encode(graphqlBody, MAP_STRING_WILDCARD, template); From c495466446d823fcf852fd87d87037e124a78545 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 9 Feb 2026 15:31:07 -0300 Subject: [PATCH 364/615] prepare release 13.8 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 01dee937ff..b5fc2f41c9 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index 082abe0100..b1c86b5e61 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index d99666fbce..d1e7b26f10 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index fba385c4df..d5272597eb 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 6bbef5d9f0..7c30f06bab 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index b8f2705626..e2bd6383fc 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index b07493cdca..449b3f448c 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index c9c4bfc882..af558f357d 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index d9b5d2a81a..e42b01d49d 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 01b3be0eed..a7f182b134 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 62aef4c99b..3f8dd12e0e 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 85a7e4210d..5250a35d3c 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index fb646c21fa..754f0e428a 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 17b8bd66bd..db18707c02 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index 4f96d5320d..9ef173bf32 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 3c446afe1d..08b14173fa 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index b8cf5cada4..ed802d6a26 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index d736d9e7b7..38874a707d 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index d2a98601c7..75549b0e39 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 21f0775b46..7d0428f34a 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index c7a5604d84..bb64157d04 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index e3b9e47219..82141f913e 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 0cfc8976aa..c11a2b91c4 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index f615df00d0..6834de4737 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 9709dffb7d..d79b6f2849 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 475134fc2e..e54b3249dd 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 3a64c01612..91fa0024a1 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 5470fa747b..116a72edf2 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 9b1ec21ce1..38299e4377 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index dfee5d0a1c..3796e793b3 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index ac058a757e..91a10d0845 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index f07e902dea..740c196435 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index a5ae81ec1d..1c61fb50b4 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 3ef76e2a65..53b23930a9 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index c98d50beb6..a776c70a91 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 565d9cf80d..caa161af11 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 6d160bbb64..0ae80ec6df 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index eab4785c97..94d93e1cd1 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-okhttp diff --git a/pom.xml b/pom.xml index 671951ca2e..9045032c7b 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 2a490e9a57..3c3d7656da 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index fc3ca30ec6..6d3b0950b7 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 10b52bb149..6f5895df7a 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 7f2e335970..4e23d837d3 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 627b33be82..aa0aa4cc1a 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index e25715e0ab..815a6e2fd8 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index a441d7130f..b516632787 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 998527191b..3974261e77 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 6119cea9ab..cce30bdbfd 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.8-SNAPSHOT + 13.8 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 4627c60a23..82646fd4f0 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.8-SNAPSHOT + 13.8 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index f7941a4712..c479f48ffe 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.8-SNAPSHOT + 13.8 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index c3fd09e8c7..652fd02a37 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8-SNAPSHOT + 13.8 feign-vertx-parent From c5f5204317a533c1cc574b1a733eca8121b0e06d Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 9 Feb 2026 15:31:12 -0300 Subject: [PATCH 365/615] [ci skip] updating versions to next development iteration 13.9-SNAPSHOT --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index b5fc2f41c9..956352234b 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index b1c86b5e61..d5c7f6e2b0 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index d1e7b26f10..7c6d55af53 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index d5272597eb..0fc95a3c7f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 7c30f06bab..3e8136ed0f 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index e2bd6383fc..4b565dfbe3 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 449b3f448c..b3edf9ea08 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index af558f357d..6e1015105a 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index e42b01d49d..57ae5651ea 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index a7f182b134..c2114cf8ee 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 3f8dd12e0e..8e8527b07d 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 5250a35d3c..a3d4a7909e 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 754f0e428a..e52ba3a849 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index db18707c02..201cb2eeea 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index 9ef173bf32..d61aab4e1e 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 08b14173fa..0809ab4411 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index ed802d6a26..b8891b6dcc 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 38874a707d..2492db8dff 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 75549b0e39..e2f0208116 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 7d0428f34a..b06bd5726e 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index bb64157d04..31e627a44f 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 82141f913e..658ac87fb9 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index c11a2b91c4..edfb903318 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 6834de4737..a4e77043fe 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index d79b6f2849..b013b48ad3 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index e54b3249dd..f985cd8480 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 91fa0024a1..cf2c98d056 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 116a72edf2..8902ad462d 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 38299e4377..b519e4e34b 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 3796e793b3..c4b81479d6 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 91a10d0845..965ceba1e8 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 740c196435..4c42cfc845 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 1c61fb50b4..3eb9d8aad3 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 53b23930a9..da1699b3f4 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index a776c70a91..b855310091 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index caa161af11..43168ef31b 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 0ae80ec6df..f6e085b9b0 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 94d93e1cd1..104196cbaa 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index 9045032c7b..8774e2eb65 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 3c3d7656da..ae83753415 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 6d3b0950b7..3ab5649e04 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 6f5895df7a..62f89def80 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 4e23d837d3..45a8db4e32 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index aa0aa4cc1a..668423150e 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 815a6e2fd8..1c0c3f2a06 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index b516632787..8e2458a278 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 3974261e77..cdc9197492 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index cce30bdbfd..675a131505 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.8 + 13.9-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 82646fd4f0..97fd38adbc 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.8 + 13.9-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index c479f48ffe..d21120abce 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.8 + 13.9-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 652fd02a37..1966bee59c 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8 + 13.9-SNAPSHOT feign-vertx-parent From 3f884075d214e23557085478a236d5ac0349753d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 05:25:56 +0000 Subject: [PATCH 366/615] build(deps): Bump micrometer.version from 1.16.2 to 1.16.3 Bumps `micrometer.version` from 1.16.2 to 1.16.3. Updates `io.micrometer:micrometer-core` from 1.16.2 to 1.16.3 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.2...v1.16.3) Updates `io.micrometer:micrometer-test` from 1.16.2 to 1.16.3 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.2...v1.16.3) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.16.3 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-version: 1.16.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index b855310091..a3ea049211 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.16.2 + 1.16.3 From 3c68d606cd032c15c48ba02d8f3f465dfcbb0be6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 05:26:56 +0000 Subject: [PATCH 367/615] build(deps): Bump com.graphql-java:graphql-java from 22.4 to 25.0 Bumps [com.graphql-java:graphql-java](https://github.com/graphql-java/graphql-java) from 22.4 to 25.0. - [Release notes](https://github.com/graphql-java/graphql-java/releases) - [Commits](https://github.com/graphql-java/graphql-java/compare/v22.4...v25.0) --- updated-dependencies: - dependency-name: com.graphql-java:graphql-java dependency-version: '25.0' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8774e2eb65..e06ca5e1b7 100644 --- a/pom.xml +++ b/pom.xml @@ -214,7 +214,7 @@ 1.6.0 1.15.0 0.23.0 - 22.4 + 25.0 4.5.0 4.5.14 5.6 From cbad4d5d8f6ce077467e2337562ee8df4bf0391b Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 10 Feb 2026 09:22:43 -0300 Subject: [PATCH 368/615] Fix release deploy: single-thread deploy and javadoc compatibility Signed-off-by: Marvin Froeder --- .circleci/config.yml | 2 +- example-github-with-coroutine/pom.xml | 4 ++++ pom.xml | 9 ++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 598323cc97..79edbca721 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -99,7 +99,7 @@ commands: name: 'Deploy Core Modules Sonatype' command: | source "$HOME/.sdkman/bin/sdkman-init.sh" - ./mvnw -ntp -nsu -s .circleci/settings.xml -P release -pl -:feign-benchmark,-:feign-vertx4-test,-:feign-vertx5-test -DskipTests=true deploy + ./mvnw -ntp -nsu -T1 -s .circleci/settings.xml -P release -pl -:feign-benchmark,-:feign-vertx4-test,-:feign-vertx5-test -DskipTests=true deploy # our job defaults defaults: &defaults diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index b3edf9ea08..4595b18dc1 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -29,6 +29,10 @@ jar GitHub Example With Coroutine + + true + + io.github.openfeign diff --git a/pom.xml b/pom.xml index e06ca5e1b7..1185ec6f16 100644 --- a/pom.xml +++ b/pom.xml @@ -977,9 +977,6 @@ org.apache.maven.plugins maven-javadoc-plugin ${maven-javadoc-plugin.version} - - false - attach-javadocs @@ -987,6 +984,12 @@ jar package + + true + true + true + none + From e54e5f45f72a9aa68cbf88e12d530c22ea751440 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 05:26:50 +0000 Subject: [PATCH 369/615] build(deps): Bump reactor.version from 3.8.2 to 3.8.3 Bumps `reactor.version` from 3.8.2 to 3.8.3. Updates `io.projectreactor:reactor-core` from 3.8.2 to 3.8.3 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.2...v3.8.3) Updates `io.projectreactor:reactor-test` from 3.8.2 to 3.8.3 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.2...v3.8.3) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.8.3 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.8.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index ae83753415..202ef8d323 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.8.2 + 3.8.3 1.0.4 2.2.21 From 178603404822dda94e283ebc68def33c5dfa8b1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 05:26:43 +0000 Subject: [PATCH 370/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.26.0 to 3.27.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.26.0...v3.27.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.27.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1185ec6f16..a352b3727f 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 4.0.0 6.28.1 3.26.0 - 3.26.0 + 3.27.0 1.0 From a6758b98f28f0d9141fade96c880284ffc05be0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 05:28:09 +0000 Subject: [PATCH 371/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.28.1 to 6.29.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.28.1...v6.29.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.29.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1185ec6f16..560562c54f 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 3.2.0 1.2.8 4.0.0 - 6.28.1 + 6.29.0 3.26.0 3.26.0 1.0 From 068a65e142e3fa0247686b33a552f84008d8015f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 05:28:22 +0000 Subject: [PATCH 372/615] build(deps-dev): Bump com.gradle:develocity-maven-extension Bumps com.gradle:develocity-maven-extension from 2.3.3 to 2.3.4. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: 2.3.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index be94d013ac..7040f32333 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.3.3 + 2.3.4 com.gradle From 30a59bb6219f1aa91899ed0fe93f0a1f74dfb1c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 05:39:25 +0000 Subject: [PATCH 373/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.26.0 to 3.27.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.26.0...v3.27.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.27.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 021eef2636..839f89beb9 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 1.2.8 4.0.0 6.29.0 - 3.26.0 + 3.27.0 3.27.0 1.0 From d0a5e4f27693d05240822da61508fda15aa4f1a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 05:26:46 +0000 Subject: [PATCH 374/615] build(deps): Bump org.springframework:spring-web from 7.0.3 to 7.0.4 Bumps [org.springframework:spring-web](https://github.com/spring-projects/spring-framework) from 7.0.3 to 7.0.4. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.3...v7.0.4) --- updated-dependencies: - dependency-name: org.springframework:spring-web dependency-version: 7.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- spring/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 839f89beb9..9a3eaf8e22 100644 --- a/pom.xml +++ b/pom.xml @@ -243,7 +243,7 @@ 2025.1.1 5.0.1 7.0.3 - 7.0.3 + 7.0.4 2.3.23.Final 1.18.0 diff --git a/spring/pom.xml b/spring/pom.xml index 8e2458a278..3a14d762fd 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -31,7 +31,7 @@ 17 - 7.0.3 + 7.0.4 From 507eae7f35ad9b3d9521ddf770f8692cdabe0c3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 05:37:54 +0000 Subject: [PATCH 375/615] build(deps-dev): Bump org.springframework:spring-context Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 7.0.3 to 7.0.4. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.3...v7.0.4) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 7.0.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9a3eaf8e22..ed023e51e7 100644 --- a/pom.xml +++ b/pom.xml @@ -242,7 +242,7 @@ 3.0.2 2025.1.1 5.0.1 - 7.0.3 + 7.0.4 7.0.4 2.3.23.Final 1.18.0 From ff88368994da6fc45a6a87cdc6c22bb42300af13 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Feb 2026 05:32:34 +0000 Subject: [PATCH 376/615] build(deps): Bump org.junit:junit-bom from 6.0.2 to 6.0.3 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r6.0.2...r6.0.3) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ed023e51e7..3aded33d3b 100644 --- a/pom.xml +++ b/pom.xml @@ -169,7 +169,7 @@ 20251224 4.0.2 - 6.0.2 + 6.0.3 2.21.0 3.0.4 3.27.7 From c58728cafd37d93791101faa5b8bbd3b8379b231 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 05:28:48 +0000 Subject: [PATCH 377/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx4-test Bumps `vertx.version` from 4.5.24 to 4.5.25. Updates `io.vertx:vertx-junit5` from 4.5.24 to 4.5.25 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.24...4.5.25) Updates `io.vertx:vertx-web-client` from 4.5.24 to 4.5.25 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.24...4.5.25) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 4.5.25 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 4.5.25 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx4-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 97fd38adbc..a8984909d9 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 4.x. - 4.5.24 + 4.5.25 From 03265d0eebb06d4450bd55e19073a5082d235af9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 05:28:48 +0000 Subject: [PATCH 378/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx5-test Bumps `vertx.version` from 5.0.7 to 5.0.8. Updates `io.vertx:vertx-junit5` from 5.0.7 to 5.0.8 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/5.0.7...5.0.8) Updates `io.vertx:vertx-web-client` from 5.0.7 to 5.0.8 - [Commits](https://github.com/vert-x3/vertx-web/compare/5.0.7...5.0.8) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 5.0.8 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 5.0.8 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx5-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index d21120abce..487605f8a3 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.0.7 + 5.0.8 From a738dce2b3e362a21142285017ed4c6bbc768c61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 05:28:16 +0000 Subject: [PATCH 379/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.27.0 to 3.27.1. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.27.0...v3.27.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.27.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3aded33d3b..e5161bb0db 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 4.0.0 6.29.0 3.27.0 - 3.27.0 + 3.27.1 1.0 From 238c2803559d39fed416c16ab46a6df09b11d3db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 05:26:09 +0000 Subject: [PATCH 380/615] build(deps-dev): Bump org.springframework:spring-context Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 7.0.4 to 7.0.5. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.4...v7.0.5) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 7.0.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e5161bb0db..1853dac63c 100644 --- a/pom.xml +++ b/pom.xml @@ -242,7 +242,7 @@ 3.0.2 2025.1.1 5.0.1 - 7.0.4 + 7.0.5 7.0.4 2.3.23.Final 1.18.0 From ba28af031a2079ac393b5835ec9b1bc644589d5f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 05:37:30 +0000 Subject: [PATCH 381/615] build(deps): Bump org.springframework:spring-web from 7.0.4 to 7.0.5 Bumps [org.springframework:spring-web](https://github.com/spring-projects/spring-framework) from 7.0.4 to 7.0.5. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.4...v7.0.5) --- updated-dependencies: - dependency-name: org.springframework:spring-web dependency-version: 7.0.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- spring/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1853dac63c..9d78950150 100644 --- a/pom.xml +++ b/pom.xml @@ -243,7 +243,7 @@ 2025.1.1 5.0.1 7.0.5 - 7.0.4 + 7.0.5 2.3.23.Final 1.18.0 diff --git a/spring/pom.xml b/spring/pom.xml index 3a14d762fd..8094ab17f7 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -31,7 +31,7 @@ 17 - 7.0.4 + 7.0.5 From 05a3ffb7a8813c8d7179c552b97f21cae8f8cd45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 05:26:32 +0000 Subject: [PATCH 382/615] build(deps): Bump springboot.version from 4.0.2 to 4.0.3 Bumps `springboot.version` from 4.0.2 to 4.0.3. Updates `org.springframework.boot:spring-boot-starter-web` from 4.0.2 to 4.0.3 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.2...v4.0.3) Updates `org.springframework.boot:spring-boot-starter-test` from 4.0.2 to 4.0.3 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.2...v4.0.3) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-web dependency-version: 4.0.3 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.springframework.boot:spring-boot-starter-test dependency-version: 4.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9d78950150..54d5d71631 100644 --- a/pom.xml +++ b/pom.xml @@ -167,7 +167,7 @@ 1.15.2 2.0.17 20251224 - 4.0.2 + 4.0.3 6.0.3 2.21.0 From a5518245fc378cc2e26861e77daf67794e60817e Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 20 Feb 2026 12:52:32 -0300 Subject: [PATCH 383/615] Add BOM publish step to CircleCI release pipeline Signed-off-by: Marvin Froeder --- .circleci/config.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 79edbca721..87debe70b5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -100,6 +100,35 @@ commands: command: | source "$HOME/.sdkman/bin/sdkman-init.sh" ./mvnw -ntp -nsu -T1 -s .circleci/settings.xml -P release -pl -:feign-benchmark,-:feign-vertx4-test,-:feign-vertx5-test -DskipTests=true deploy + - run: + name: 'Publish BOM to Maven Central' + command: | + BOM_DIR=target/classes/feign-bom + BOM_POM=$BOM_DIR/pom.xml + if [ ! -f "$BOM_POM" ]; then + echo "BOM pom not found, skipping" + exit 0 + fi + BOM_VERSION=$(grep '' "$BOM_POM" | head -1 | sed 's/.*\(.*\)<\/version>.*/\1/') + STAGING_DIR=/tmp/bom-staging/io/github/openfeign/feign-bom/$BOM_VERSION + mkdir -p "$STAGING_DIR" + cp "$BOM_POM" "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom" + gpg --armor --detach-sign "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom" + md5sum "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom" | awk '{print $1}' > "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom.md5" + sha1sum "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom" | awk '{print $1}' > "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom.sha1" + sha256sum "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom" | awk '{print $1}' > "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom.sha256" + sha512sum "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom" | awk '{print $1}' > "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom.sha512" + (cd /tmp/bom-staging && zip -r /tmp/feign-bom-bundle.zip .) + TOKEN=$(echo -n "${CENTRAL_TOKEN_USERNAME}:${CENTRAL_TOKEN_PASSWORD}" | base64) + HTTP_CODE=$(curl -s -w "%{http_code}" -o /tmp/bom-upload-response.txt \ + -X POST "https://central.sonatype.com/api/v1/publisher/upload?name=feign-bom-${BOM_VERSION}&publishingType=AUTOMATIC" \ + -H "Authorization: Bearer $TOKEN" \ + -F "bundle=@/tmp/feign-bom-bundle.zip") + echo "BOM upload response: $(cat /tmp/bom-upload-response.txt) (HTTP $HTTP_CODE)" + if [ "$HTTP_CODE" != "201" ]; then + echo "BOM upload failed" + exit 1 + fi # our job defaults defaults: &defaults From 68d3701289b7839039cae1690cfbf2a1b2cac6db Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 20 Feb 2026 12:55:22 -0300 Subject: [PATCH 384/615] prepare release 13.8.1 Signed-off-by: Marvin Froeder --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 956352234b..2c15357428 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index d5c7f6e2b0..e4a368df75 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 7c6d55af53..ed5c27ae52 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 0fc95a3c7f..1816d727ae 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 3e8136ed0f..388505eda3 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 4b565dfbe3..570cb43fc1 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 4595b18dc1..6e251f441a 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 6e1015105a..20f2d3f855 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 57ae5651ea..ae0fc38fb1 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index c2114cf8ee..d83cc74160 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 8e8527b07d..14c74db1fa 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index a3d4a7909e..3076ad9499 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index e52ba3a849..def484f7bc 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 201cb2eeea..cbd257d1c0 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index d61aab4e1e..714241f4e1 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 0809ab4411..c39906f7c4 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index b8891b6dcc..bcef56cb1a 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 2492db8dff..25e0ce37d9 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index e2f0208116..cd49562bfe 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index b06bd5726e..b6174e0093 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 31e627a44f..78d2365912 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 658ac87fb9..53e1fde185 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index edfb903318..c7d40cb653 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index a4e77043fe..211852d7aa 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index b013b48ad3..9006a1e26f 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index f985cd8480..b2bd605982 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index cf2c98d056..8d34dec32f 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 8902ad462d..b6cac12861 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index b519e4e34b..4e25677271 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index c4b81479d6..3df6422f80 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 965ceba1e8..145d619d12 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 4c42cfc845..14967358bd 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 3eb9d8aad3..01697a753d 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index da1699b3f4..99b372e645 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index a3ea049211..f0ffc4adb7 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 43168ef31b..dfc2330bfe 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index f6e085b9b0..021948965f 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 104196cbaa..91cc0e024b 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-okhttp diff --git a/pom.xml b/pom.xml index 54d5d71631..a89d76fe22 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 202ef8d323..2598b1bc83 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 3ab5649e04..2cd334744e 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 62f89def80..68ee7e63d1 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 45a8db4e32..ac0c7c80be 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 668423150e..ad5551c028 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 1c0c3f2a06..50da7b0539 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 8094ab17f7..bea6ad5c56 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index cdc9197492..1b3eba1e22 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 675a131505..d69bb23990 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9-SNAPSHOT + 13.8.1 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index a8984909d9..233f021a8b 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9-SNAPSHOT + 13.8.1 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 487605f8a3..216240fbf0 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9-SNAPSHOT + 13.8.1 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 1966bee59c..891c30c69f 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.8.1 feign-vertx-parent From a849bb0ba4d035969d9018209f8069aa803125f2 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 20 Feb 2026 12:55:51 -0300 Subject: [PATCH 385/615] [ci skip] updating versions to next development iteration 13.9-SNAPSHOT Signed-off-by: Marvin Froeder --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 2c15357428..956352234b 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index e4a368df75..d5c7f6e2b0 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index ed5c27ae52..7c6d55af53 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 1816d727ae..0fc95a3c7f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 388505eda3..3e8136ed0f 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 570cb43fc1..4b565dfbe3 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 6e251f441a..4595b18dc1 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 20f2d3f855..6e1015105a 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index ae0fc38fb1..57ae5651ea 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index d83cc74160..c2114cf8ee 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 14c74db1fa..8e8527b07d 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 3076ad9499..a3d4a7909e 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index def484f7bc..e52ba3a849 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index cbd257d1c0..201cb2eeea 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index 714241f4e1..d61aab4e1e 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index c39906f7c4..0809ab4411 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index bcef56cb1a..b8891b6dcc 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 25e0ce37d9..2492db8dff 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index cd49562bfe..e2f0208116 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index b6174e0093..b06bd5726e 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 78d2365912..31e627a44f 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 53e1fde185..658ac87fb9 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index c7d40cb653..edfb903318 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 211852d7aa..a4e77043fe 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 9006a1e26f..b013b48ad3 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index b2bd605982..f985cd8480 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 8d34dec32f..cf2c98d056 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index b6cac12861..8902ad462d 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 4e25677271..b519e4e34b 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 3df6422f80..c4b81479d6 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 145d619d12..965ceba1e8 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 14967358bd..4c42cfc845 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 01697a753d..3eb9d8aad3 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 99b372e645..da1699b3f4 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index f0ffc4adb7..a3ea049211 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index dfc2330bfe..43168ef31b 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 021948965f..f6e085b9b0 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 91cc0e024b..104196cbaa 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index a89d76fe22..54d5d71631 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 2598b1bc83..202ef8d323 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 2cd334744e..3ab5649e04 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 68ee7e63d1..62f89def80 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index ac0c7c80be..45a8db4e32 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index ad5551c028..668423150e 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 50da7b0539..1c0c3f2a06 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index bea6ad5c56..8094ab17f7 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 1b3eba1e22..cdc9197492 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index d69bb23990..675a131505 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.8.1 + 13.9-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 233f021a8b..a8984909d9 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.8.1 + 13.9-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 216240fbf0..487605f8a3 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.8.1 + 13.9-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 891c30c69f..1966bee59c 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.8.1 + 13.9-SNAPSHOT feign-vertx-parent From cc28be99dce376fcd7589581935a9e53175b5202 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 20 Feb 2026 21:50:32 -0300 Subject: [PATCH 386/615] fix: use --serial for mvnd release deploy to prevent partial publishes Signed-off-by: Marvin Froeder --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 87debe70b5..2017bf865c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -99,7 +99,7 @@ commands: name: 'Deploy Core Modules Sonatype' command: | source "$HOME/.sdkman/bin/sdkman-init.sh" - ./mvnw -ntp -nsu -T1 -s .circleci/settings.xml -P release -pl -:feign-benchmark,-:feign-vertx4-test,-:feign-vertx5-test -DskipTests=true deploy + ./mvnw -ntp -nsu --serial -s .circleci/settings.xml -P release -pl -:feign-benchmark,-:feign-vertx4-test,-:feign-vertx5-test -DskipTests=true deploy - run: name: 'Publish BOM to Maven Central' command: | From e9d0ca010344c0a52f4725ba832ac40d4e17e429 Mon Sep 17 00:00:00 2001 From: Marvin Date: Sun, 22 Feb 2026 12:42:35 -0300 Subject: [PATCH 387/615] fix: unwrap single object from GraphQL array response (#3234) * fix: unwrap single object from GraphQL array response when return type is not a collection Signed-off-by: Marvin Froeder * feat: add Optional return type support and document array unwrapping in GraphqlDecoder Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder --- graphql/README.md | 27 ++++ .../java/feign/graphql/GraphqlDecoder.java | 57 +++++++ .../java/feign/graphql/GraphqlClientTest.java | 48 ++++++ .../feign/graphql/GraphqlDecoderTest.java | 149 ++++++++++++++++++ 4 files changed, 281 insertions(+) diff --git a/graphql/README.md b/graphql/README.md index 0f654915eb..272fd3383c 100644 --- a/graphql/README.md +++ b/graphql/README.md @@ -120,6 +120,33 @@ The processor maps `DateTime` fields to `java.time.Instant` in the generated rec public record Event(String id, String name, Instant startTime) {} ``` +## Single Result from Array Queries + +When a GraphQL query returns an array type (e.g. `[User!]`) but the Java method declares a single return type, the decoder automatically unwraps the first element: + +```java +@GraphqlQuery("query topUser($limit: Int!) { topUsers(limit: $limit) { id name email } }") +User topUser(int limit); +``` + +This is useful when using `limit: 1` to fetch a single result from a list query. If the array is empty, `null` is returned. + +## Optional Return Types + +Methods can return `Optional` to safely handle nullable results: + +```java +@GraphqlQuery("query getUser($id: String!) { getUser(id: $id) { id name email } }") +Optional findUser(String id); +``` + +Returns `Optional.empty()` when the data is null or missing, and `Optional.of(value)` otherwise. This also works with array unwrapping: + +```java +@GraphqlQuery("query topUser($limit: Int!) { topUsers(limit: $limit) { id name email } }") +Optional findTopUser(int limit); +``` + ## Disabling Type Generation If you provide your own model classes, disable automatic generation: diff --git a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java index 3560341054..b2833a0274 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java @@ -15,6 +15,7 @@ */ package feign.graphql; +import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import feign.Response; @@ -22,7 +23,9 @@ import feign.codec.Decoder; import java.io.BufferedReader; import java.io.IOException; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.Optional; public class GraphqlDecoder implements Decoder { @@ -48,6 +51,17 @@ public GraphqlDecoder(ObjectMapper mapper, Decoder delegate) { @Override public Object decode(Response response, Type type) throws IOException { + Type targetType = type; + boolean optional = isOptionalType(type); + if (optional) { + targetType = extractOptionalInnerType(type); + } + + var result = doDecode(response, targetType); + return optional ? Optional.ofNullable(result) : result; + } + + private Object doDecode(Response response, Type type) throws IOException { if (response.status() == 404 || response.status() == 204) { return Util.emptyValueOf(type); } @@ -85,6 +99,13 @@ public Object decode(Response response, Type type) throws IOException { return Util.emptyValueOf(type); } + if (operationData.isArray() && !isCollectionOrArrayType(type)) { + if (operationData.isEmpty()) { + return Util.emptyValueOf(type); + } + operationData = operationData.get(0); + } + if (delegate != null) { var dataBytes = mapper.writeValueAsBytes(operationData); var dataResponse = @@ -124,4 +145,40 @@ private String resolveOperationField(JsonNode root, Response response) { return "unknown"; } + + private boolean isOptionalType(Type type) { + if (type instanceof JavaType jt) { + return jt.getRawClass() == Optional.class; + } + if (type instanceof ParameterizedType pt && pt.getRawType() instanceof Class cls) { + return cls == Optional.class; + } + if (type instanceof Class cls) { + return cls == Optional.class; + } + return false; + } + + private Type extractOptionalInnerType(Type type) { + if (type instanceof JavaType jt) { + return jt.containedType(0); + } + if (type instanceof ParameterizedType pt) { + return pt.getActualTypeArguments()[0]; + } + return Object.class; + } + + private boolean isCollectionOrArrayType(Type type) { + if (type instanceof JavaType jt) { + return jt.isCollectionLikeType() || jt.isArrayType(); + } + if (type instanceof Class cls) { + return cls.isArray() || Iterable.class.isAssignableFrom(cls); + } + if (type instanceof ParameterizedType pt && pt.getRawType() instanceof Class cls) { + return Iterable.class.isAssignableFrom(cls); + } + return false; + } } diff --git a/graphql/src/test/java/feign/graphql/GraphqlClientTest.java b/graphql/src/test/java/feign/graphql/GraphqlClientTest.java index ce47c4e0fe..aa4d699561 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlClientTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlClientTest.java @@ -25,6 +25,7 @@ import feign.Param; import feign.jackson.JacksonEncoder; import java.util.List; +import java.util.Optional; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import org.junit.jupiter.api.AfterEach; @@ -71,6 +72,12 @@ interface TestApi { @GraphqlQuery("query getUser($id: String!) {" + " getUser(id: $id) { id name email } }") @Headers("Authorization: {auth}") User getUserWithAuth(@Param("auth") String auth, String id); + + @GraphqlQuery("query getUser($id: String!) {" + " getUser(id: $id) { id name email } }") + Optional findUser(String id); + + @GraphqlQuery("query topUser($limit: Int!) {" + " topUsers(limit: $limit) { id name email } }") + User topUser(int limit); } @BeforeEach @@ -172,6 +179,47 @@ void graphqlErrorsThrowException() { .hasMessageContaining("Something went wrong"); } + @Test + void singleResultFromArrayResponse() throws Exception { + server.enqueue( + new MockResponse() + .setBody( + "{\"data\":{\"topUsers\":[{\"id\":\"1\",\"name\":\"Alice\",\"email\":\"a@test.com\"}]}}") + .addHeader("Content-Type", "application/json")); + + var user = buildClient().topUser(1); + + assertThat(user.id).isEqualTo("1"); + assertThat(user.name).isEqualTo("Alice"); + } + + @Test + void optionalReturnType() throws Exception { + server.enqueue( + new MockResponse() + .setBody( + "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Bob\",\"email\":\"bob@test.com\"}}}") + .addHeader("Content-Type", "application/json")); + + var user = buildClient().findUser("1"); + + assertThat(user).isPresent(); + assertThat(user.get().id).isEqualTo("1"); + assertThat(user.get().name).isEqualTo("Bob"); + } + + @Test + void optionalReturnTypeEmptyWhenNull() throws Exception { + server.enqueue( + new MockResponse() + .setBody("{\"data\":{\"getUser\":null}}") + .addHeader("Content-Type", "application/json")); + + var user = buildClient().findUser("999"); + + assertThat(user).isEmpty(); + } + @Test void authHeaderPassedThrough() throws Exception { server.enqueue( diff --git a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java index 045d15cf3c..f482d2cbe9 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java @@ -23,9 +23,12 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.Test; class GraphqlDecoderTest { @@ -111,6 +114,53 @@ void returnsEmptyFor404() throws Exception { assertThat(result).isNull(); } + @Test + void unwrapsSingleObjectFromArray() throws Exception { + var json = "{\"data\":{\"ingestionStats\":[{\"id\":\"1\",\"name\":\"Alice\"}]}}"; + var response = buildResponse(json); + + var user = (User) decoder.decode(response, User.class); + + assertThat(user.id).isEqualTo("1"); + assertThat(user.name).isEqualTo("Alice"); + } + + @Test + void unwrapsFirstElementFromMultiElementArray() throws Exception { + var json = + "{\"data\":{\"ingestionStats\":[{\"id\":\"1\",\"name\":\"Alice\"},{\"id\":\"2\",\"name\":\"Bob\"}]}}"; + var response = buildResponse(json); + + var user = (User) decoder.decode(response, User.class); + + assertThat(user.id).isEqualTo("1"); + assertThat(user.name).isEqualTo("Alice"); + } + + @Test + void returnsNullForEmptyArrayWithSingleType() throws Exception { + var json = "{\"data\":{\"ingestionStats\":[]}}"; + var response = buildResponse(json); + + var result = decoder.decode(response, User.class); + assertThat(result).isNull(); + } + + @Test + void preservesArrayWhenReturnTypeIsList() throws Exception { + var json = + "{\"data\":{\"listUsers\":[{\"id\":\"1\",\"name\":\"Alice\"},{\"id\":\"2\",\"name\":\"Bob\"}]}}"; + var response = buildResponse(json); + + @SuppressWarnings("unchecked") + var users = + (List) + decoder.decode( + response, mapper.getTypeFactory().constructCollectionType(List.class, User.class)); + + assertThat(users).hasSize(2); + } + @Test void delegatesToCustomDecoder() throws Exception { var json = "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Alice\"}}}"; @@ -127,6 +177,86 @@ void delegatesToCustomDecoder() throws Exception { assertThat(user.name).isEqualTo("Alice"); } + @Test + void returnsOptionalWithValue() throws Exception { + var json = "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Alice\"}}}"; + var response = buildResponse(json); + + @SuppressWarnings("unchecked") + var result = (Optional) decoder.decode(response, optionalOf(User.class)); + + assertThat(result).isPresent(); + assertThat(result.get().id).isEqualTo("1"); + assertThat(result.get().name).isEqualTo("Alice"); + } + + @Test + void returnsOptionalEmptyForNullData() throws Exception { + var json = "{\"data\":{\"getUser\":null}}"; + var response = buildResponse(json); + + @SuppressWarnings("unchecked") + var result = (Optional) decoder.decode(response, optionalOf(User.class)); + + assertThat(result).isEmpty(); + } + + @Test + void returnsOptionalEmptyFor404() throws Exception { + var response = + Response.builder() + .status(404) + .reason("Not Found") + .headers(Collections.emptyMap()) + .request(buildRequest()) + .body(new byte[0]) + .build(); + + @SuppressWarnings("unchecked") + var result = (Optional) decoder.decode(response, optionalOf(User.class)); + + assertThat(result).isEmpty(); + } + + @Test + void unwrapsSingleObjectFromArrayIntoOptional() throws Exception { + var json = "{\"data\":{\"ingestionStats\":[{\"id\":\"1\",\"name\":\"Alice\"}]}}"; + var response = buildResponse(json); + + @SuppressWarnings("unchecked") + var result = (Optional) decoder.decode(response, optionalOf(User.class)); + + assertThat(result).isPresent(); + assertThat(result.get().id).isEqualTo("1"); + } + + @Test + void returnsOptionalEmptyForEmptyArray() throws Exception { + var json = "{\"data\":{\"ingestionStats\":[]}}"; + var response = buildResponse(json); + + @SuppressWarnings("unchecked") + var result = (Optional) decoder.decode(response, optionalOf(User.class)); + + assertThat(result).isEmpty(); + } + + @Test + void unwrapsSingleObjectFromArrayWithDelegate() throws Exception { + var json = "{\"data\":{\"ingestionStats\":[{\"id\":\"1\",\"name\":\"Alice\"}]}}"; + var customDecoder = + new GraphqlDecoder( + mapper, + (resp, type) -> + mapper.readValue(resp.body().asReader(resp.charset()), mapper.constructType(type))); + var response = buildResponse(json); + + var user = (User) customDecoder.decode(response, User.class); + + assertThat(user.id).isEqualTo("1"); + assertThat(user.name).isEqualTo("Alice"); + } + private Response buildResponse(String body) { return Response.builder() .status(200) @@ -145,4 +275,23 @@ private Request buildRequest() { Request.Body.empty(), null); } + + private static ParameterizedType optionalOf(Type inner) { + return new ParameterizedType() { + @Override + public Type[] getActualTypeArguments() { + return new Type[] {inner}; + } + + @Override + public Type getRawType() { + return Optional.class; + } + + @Override + public Type getOwnerType() { + return null; + } + }; + } } From 8f8be54364febcee522a254fdce1c46b2e0be6e5 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Sun, 22 Feb 2026 12:42:49 -0300 Subject: [PATCH 388/615] prepare release 13.9 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 956352234b..61f0346687 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index d5c7f6e2b0..da3d77deb4 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 7c6d55af53..d10df52c62 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 0fc95a3c7f..394f5d841c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 3e8136ed0f..47ecb32f34 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 4b565dfbe3..8374155214 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 4595b18dc1..892429dcbe 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 6e1015105a..5961bfee06 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 57ae5651ea..f02f0e0396 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index c2114cf8ee..ea19a659d8 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 8e8527b07d..7aa2aff489 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index a3d4a7909e..d2050cdd56 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index e52ba3a849..4c8f7ef86f 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 201cb2eeea..578a20b937 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index d61aab4e1e..590d3d9e80 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 0809ab4411..73644d997a 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index b8891b6dcc..b8a9f4fe89 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 2492db8dff..37eb5c90f4 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index e2f0208116..9758e17a2c 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index b06bd5726e..2e9fd1dfd3 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 31e627a44f..a0b1be0f0a 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 658ac87fb9..d84cd724b8 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index edfb903318..09380bb120 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index a4e77043fe..1b73a8990c 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index b013b48ad3..775323c243 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index f985cd8480..15276aa969 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index cf2c98d056..c4a4183185 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 8902ad462d..aec2649f57 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index b519e4e34b..cd6397d0a2 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index c4b81479d6..72dffbc38a 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 965ceba1e8..81de5aa9b2 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 4c42cfc845..a66331d35f 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 3eb9d8aad3..441782f273 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index da1699b3f4..438ac94c04 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index a3ea049211..90892ba471 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 43168ef31b..25e5697012 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index f6e085b9b0..876adb2d2c 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 104196cbaa..954b9c17ac 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-okhttp diff --git a/pom.xml b/pom.xml index 54d5d71631..ba41f3cb74 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 202ef8d323..2d7d5bdddb 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 3ab5649e04..9276167b30 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 62f89def80..ad8c43ecb8 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 45a8db4e32..41b9cb2d43 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 668423150e..58f2519385 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 1c0c3f2a06..b1317bdf7f 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 8094ab17f7..33d32fa25e 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index cdc9197492..3d30bc56ce 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 675a131505..61c747d775 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9-SNAPSHOT + 13.9 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index a8984909d9..0f225377d2 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9-SNAPSHOT + 13.9 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 487605f8a3..5ac1ed361a 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9-SNAPSHOT + 13.9 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 1966bee59c..b674d8456c 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.9 feign-vertx-parent From 6af14d5663412279849a48d0558f26720eb300d2 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Sun, 22 Feb 2026 12:43:02 -0300 Subject: [PATCH 389/615] [ci skip] updating versions to next development iteration 14.0-SNAPSHOT --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 61f0346687..3f572e0c19 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index da3d77deb4..c0f467f008 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index d10df52c62..cb3e58b7e9 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 394f5d841c..741719c7d9 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 47ecb32f34..912088d32b 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 8374155214..afab948176 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 892429dcbe..7c7893ac74 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 5961bfee06..2732bdb51a 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index f02f0e0396..47a8bb6a88 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index ea19a659d8..9955aac595 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 7aa2aff489..cb3b789caa 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index d2050cdd56..f27e9598bf 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 4c8f7ef86f..01452e6859 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 578a20b937..0687dcb39f 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index 590d3d9e80..22243aa87e 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 73644d997a..835a492cab 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index b8a9f4fe89..ae52a62421 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 37eb5c90f4..64df708e6b 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 9758e17a2c..6809fd5c4a 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 2e9fd1dfd3..7c56e57d46 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index a0b1be0f0a..1da25fbf94 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index d84cd724b8..1ac437bd3a 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 09380bb120..3b93aa720f 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 1b73a8990c..af09349ea7 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 775323c243..638772ff03 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 15276aa969..5aa380c842 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index c4a4183185..8e38845d0e 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index aec2649f57..831d5c82ed 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index cd6397d0a2..942f649dc2 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 72dffbc38a..94ce8c6697 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 81de5aa9b2..98221bfe3b 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index a66331d35f..3c887cfdc9 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 441782f273..139c8fbc94 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 438ac94c04..3f4a063ded 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 90892ba471..43b1bd61a4 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 25e5697012..428d52fdfa 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 876adb2d2c..ceb761718c 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 954b9c17ac..d894fc3a95 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index ba41f3cb74..d991a824e9 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 2d7d5bdddb..d948f53f83 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 9276167b30..cf302d5d9c 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index ad8c43ecb8..7f819d935b 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 41b9cb2d43..2cdc088672 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 58f2519385..402c9cc6d2 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index b1317bdf7f..44261a14f6 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 33d32fa25e..e558663d89 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 3d30bc56ce..9dfdb60a77 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 61c747d775..f5a4c34c29 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9 + 14.0-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 0f225377d2..9486c44845 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9 + 14.0-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 5ac1ed361a..0fa3dc2fe8 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9 + 14.0-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index b674d8456c..452b8a1f56 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9 + 14.0-SNAPSHOT feign-vertx-parent From f1200b9b5dae8fe9c9d7dabf92807b68341911c1 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Sun, 22 Feb 2026 13:24:32 -0300 Subject: [PATCH 390/615] fix: exclude example modules from release deploy Signed-off-by: Marvin Froeder --- .circleci/config.yml | 3 ++- apt-test-generator/pom.xml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2017bf865c..e901e0a60d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -97,9 +97,10 @@ commands: steps: - run: name: 'Deploy Core Modules Sonatype' + no_output_timeout: 30m command: | source "$HOME/.sdkman/bin/sdkman-init.sh" - ./mvnw -ntp -nsu --serial -s .circleci/settings.xml -P release -pl -:feign-benchmark,-:feign-vertx4-test,-:feign-vertx5-test -DskipTests=true deploy + ./mvnw -ntp -nsu --serial -s .circleci/settings.xml -P release -pl -:feign-benchmark,-:feign-vertx4-test,-:feign-vertx5-test,-:feign-example-github,-:feign-example-github-with-coroutine,-:feign-example-wikipedia,-:feign-example-wikipedia-with-springboot -DskipTests=true deploy - run: name: 'Publish BOM to Maven Central' command: | diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index c0f467f008..9d48e6dea9 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -46,6 +46,7 @@ io.github.openfeign feign-example-github ${project.version} + test From e025271fe3ce7817caeb86c96300f5e4ae2b57fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 05:33:28 +0000 Subject: [PATCH 391/615] build(deps): Bump maven-surefire-plugin.version from 3.5.4 to 3.5.5 Bumps `maven-surefire-plugin.version` from 3.5.4 to 3.5.5. Updates `org.apache.maven.plugins:maven-surefire-plugin` from 3.5.4 to 3.5.5 - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.4...surefire-3.5.5) Updates `org.apache.maven.plugins:maven-failsafe-plugin` from 3.5.4 to 3.5.5 - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.4...surefire-3.5.5) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-version: 3.5.5 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-version: 3.5.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d991a824e9..5d1c82b472 100644 --- a/pom.xml +++ b/pom.xml @@ -188,7 +188,7 @@ 6.0.0 0.1.1 0.10.0 - 3.5.4 + 3.5.5 0.230.2 file://${project.basedir}/src/config/bom.xml 2.2.1 From 8c6bec2f2d9db61647fa795f9f9c7b53752abe9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 05:34:26 +0000 Subject: [PATCH 392/615] build(deps): Bump jackson.version from 2.21.0 to 2.21.1 Bumps `jackson.version` from 2.21.0 to 2.21.1. Updates `com.fasterxml.jackson:jackson-bom` from 2.21.0 to 2.21.1 - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.21.0...jackson-bom-2.21.1) Updates `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider` from 2.21.0 to 2.21.1 --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.21.1 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-version: 2.21.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d991a824e9..f5610c59b0 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 4.0.3 6.0.3 - 2.21.0 + 2.21.1 3.0.4 3.27.7 5.21.0 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index f5a4c34c29..b293f6d685 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -31,7 +31,7 @@ 11 - 2.21.0 + 2.21.1 From 290a06162c427ea2f17ec1b30992e85e17ad07df Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 23 Feb 2026 07:45:52 -0300 Subject: [PATCH 393/615] Next development version Signed-off-by: Marvin Froeder --- .gitignore | 1 + annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 3 ++- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 14 +++++++++++++- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 52 files changed, 65 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index 3302792f89..6b1a07cf66 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ Thumbs.db /target **/test-output **/target +**/m2e-target **/bin build */build diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 3f572e0c19..956352234b 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index 9d48e6dea9..d10104ae39 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index cb3e58b7e9..7c6d55af53 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 741719c7d9..0fc95a3c7f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 912088d32b..3e8136ed0f 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index afab948176..4b565dfbe3 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 7c7893ac74..4595b18dc1 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 2732bdb51a..6e1015105a 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 47a8bb6a88..c6ae943e1d 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-example-wikipedia-with-springboot @@ -84,6 +84,7 @@ org.springframework.boot spring-boot-maven-plugin + ${springboot.version} example.wikipedia.WikipediaApplication ZIP diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 9955aac595..c2114cf8ee 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index cb3b789caa..8e8527b07d 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index f27e9598bf..a3d4a7909e 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 01452e6859..e52ba3a849 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 0687dcb39f..201cb2eeea 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index 22243aa87e..d61aab4e1e 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 835a492cab..0809ab4411 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index ae52a62421..b8891b6dcc 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 64df708e6b..2492db8dff 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 6809fd5c4a..e2f0208116 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 7c56e57d46..b06bd5726e 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 1da25fbf94..31e627a44f 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 1ac437bd3a..658ac87fb9 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 3b93aa720f..edfb903318 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index af09349ea7..a4e77043fe 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 638772ff03..b013b48ad3 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 5aa380c842..f985cd8480 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 8e38845d0e..cf2c98d056 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 831d5c82ed..8902ad462d 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 942f649dc2..b519e4e34b 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 94ce8c6697..c4b81479d6 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 98221bfe3b..965ceba1e8 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 3c887cfdc9..4c42cfc845 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 139c8fbc94..3eb9d8aad3 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 3f4a063ded..da1699b3f4 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 43b1bd61a4..a3ea049211 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 428d52fdfa..43168ef31b 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index ceb761718c..f6e085b9b0 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index d894fc3a95..104196cbaa 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index d991a824e9..923597ae4e 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT pom Feign (Parent) @@ -1120,6 +1120,18 @@ + + m2e + + + m2e.version + + + + ${project.basedir}/m2e-target + + + toolchain diff --git a/reactive/pom.xml b/reactive/pom.xml index d948f53f83..202ef8d323 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index cf302d5d9c..3ab5649e04 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 7f819d935b..62f89def80 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 2cdc088672..45a8db4e32 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 402c9cc6d2..668423150e 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 44261a14f6..1c0c3f2a06 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index e558663d89..8094ab17f7 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 9dfdb60a77..cdc9197492 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index f5a4c34c29..675a131505 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 9486c44845..a8984909d9 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 0fa3dc2fe8..487605f8a3 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 452b8a1f56..1966bee59c 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 14.0-SNAPSHOT + 13.9-SNAPSHOT feign-vertx-parent From 00d504c4d8a3699e41701f02bceacf63e64842bc Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 23 Feb 2026 07:51:36 -0300 Subject: [PATCH 394/615] fix: suppress JDK 25 Unsafe and Develocity build cache warnings Signed-off-by: Marvin Froeder --- .mvn/develocity.xml | 2 +- .mvn/jvm.config | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.mvn/develocity.xml b/.mvn/develocity.xml index 4f9fdf42dc..7c4c992d8e 100644 --- a/.mvn/develocity.xml +++ b/.mvn/develocity.xml @@ -33,7 +33,7 @@ - true + #{isTrue(env['CI'])} false diff --git a/.mvn/jvm.config b/.mvn/jvm.config index cfbd68a5f5..32db52fb95 100644 --- a/.mvn/jvm.config +++ b/.mvn/jvm.config @@ -1,3 +1,4 @@ +--sun-misc-unsafe-memory-access=allow --add-opens jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED From 0d063787f7af0d33edaf41adcd04013da0179a03 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 23 Feb 2026 07:52:20 -0300 Subject: [PATCH 395/615] Next development version 13.10-SNAPSHOT Signed-off-by: Marvin Froeder --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 956352234b..2d8f3c26f7 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index d10104ae39..dd6cb51502 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 7c6d55af53..dde47f4b40 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 0fc95a3c7f..d653233e6f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 3e8136ed0f..7155c1d438 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 4b565dfbe3..6880e543ed 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 4595b18dc1..63cb280898 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 6e1015105a..577e429644 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index c6ae943e1d..d2f2b27e78 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index c2114cf8ee..10085b77e1 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 8e8527b07d..10b8365c0d 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index a3d4a7909e..f6b94cbb21 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index e52ba3a849..d839964803 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 201cb2eeea..55a72207f7 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index d61aab4e1e..e8f23c2232 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 0809ab4411..cdf87bc341 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index b8891b6dcc..20cbe814d1 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 2492db8dff..00b1e67d35 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index e2f0208116..3d7321f28b 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index b06bd5726e..085e5d36ce 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 31e627a44f..0eb2b99863 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 658ac87fb9..e37e24df14 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index edfb903318..28da8e722a 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index a4e77043fe..398f3391ff 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index b013b48ad3..3864ca1c61 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index f985cd8480..47300b18ab 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index cf2c98d056..3987b7fe82 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 8902ad462d..d5e6e68257 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index b519e4e34b..3f827cb095 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index c4b81479d6..e121974e9f 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 965ceba1e8..7ed79f6943 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 4c42cfc845..9dc9b921b0 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 3eb9d8aad3..ab0112f806 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index da1699b3f4..7f0c7317ad 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index a3ea049211..7b2b677b24 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 43168ef31b..6ecf4f3da2 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index f6e085b9b0..2245c7583a 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 104196cbaa..3a092d194c 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index 923597ae4e..c2b0d4c1ad 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 202ef8d323..ee1e2add7c 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 3ab5649e04..2b5cb5b1d6 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 62f89def80..66ed6c90c3 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 45a8db4e32..673ee625d0 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 668423150e..39cf7266d1 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 1c0c3f2a06..14208a1579 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 8094ab17f7..8856f0fde3 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index cdc9197492..d3abe020bc 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 675a131505..c48c2d0418 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index a8984909d9..3d5bb5d8b3 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 487605f8a3..0625cfeae9 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 1966bee59c..87a914f193 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9-SNAPSHOT + 13.10-SNAPSHOT feign-vertx-parent From c791a0c36756acad09d18ef66189c924353663d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 05:25:11 +0000 Subject: [PATCH 396/615] build(deps): Bump tools.jackson:jackson-bom from 3.0.4 to 3.1.0 Bumps [tools.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 3.0.4 to 3.1.0. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-3.0.4...jackson-bom-3.1.0) --- updated-dependencies: - dependency-name: tools.jackson:jackson-bom dependency-version: 3.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2012344039..f1b0d7c7f9 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 6.0.3 2.21.1 - 3.0.4 + 3.1.0 3.27.7 5.21.0 2.0.61.android8 From 5bada89ff25ee7b0a9e1fdbabfeb7b30dab89dd0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 05:26:25 +0000 Subject: [PATCH 397/615] build(deps): Bump jakarta.xml.ws:jakarta.xml.ws-api from 4.0.2 to 4.0.3 Bumps [jakarta.xml.ws:jakarta.xml.ws-api](https://github.com/jakartaee/jax-ws-api) from 4.0.2 to 4.0.3. - [Release notes](https://github.com/jakartaee/jax-ws-api/releases) - [Commits](https://github.com/jakartaee/jax-ws-api/compare/4.0.2...4.0.3) --- updated-dependencies: - dependency-name: jakarta.xml.ws:jakarta.xml.ws-api dependency-version: 4.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2012344039..f0d2686ab5 100644 --- a/pom.xml +++ b/pom.xml @@ -224,7 +224,7 @@ 4.0.0 4.0.5 3.0.2 - 4.0.2 + 4.0.3 2.1.1 2.3.1 2.3.9 From 8176b9f5cca57383469efb80475d8901c463826f Mon Sep 17 00:00:00 2001 From: Marvin Date: Wed, 25 Feb 2026 21:24:11 -0300 Subject: [PATCH 398/615] feat: extract JsonDecoder interface to decouple graphql from Jackson (#3240) Signed-off-by: Marvin Froeder --- .../main/java/feign/codec/JsonDecoder.java | 26 ++++ .../feign/fastjson2/Fastjson2Decoder.java | 12 +- graphql/README.md | 21 +++- graphql/pom.xml | 5 - .../java/feign/graphql/GraphqlDecoder.java | 111 +++++++----------- .../java/feign/graphql/GraphqlClientTest.java | 3 +- .../feign/graphql/GraphqlDecoderTest.java | 64 ++++------ .../src/main/java/feign/gson/GsonDecoder.java | 8 +- .../feign/jackson/jr/JacksonJrDecoder.java | 28 ++++- .../java/feign/jackson/JacksonDecoder.java | 8 +- .../java/feign/jackson3/Jackson3Decoder.java | 8 +- .../src/main/java/feign/json/JsonDecoder.java | 26 +++- .../main/java/feign/moshi/MoshiDecoder.java | 9 +- 13 files changed, 202 insertions(+), 127 deletions(-) create mode 100644 core/src/main/java/feign/codec/JsonDecoder.java diff --git a/core/src/main/java/feign/codec/JsonDecoder.java b/core/src/main/java/feign/codec/JsonDecoder.java new file mode 100644 index 0000000000..5a51af5506 --- /dev/null +++ b/core/src/main/java/feign/codec/JsonDecoder.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.codec; + +import feign.Experimental; +import java.io.IOException; +import java.lang.reflect.Type; + +@Experimental +public interface JsonDecoder extends Decoder { + + Object convert(Object object, Type type) throws IOException; +} diff --git a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Decoder.java b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Decoder.java index fe8fa07338..80b1ada8d7 100644 --- a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Decoder.java +++ b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Decoder.java @@ -19,11 +19,13 @@ import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONException; +import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONReader; import feign.FeignException; import feign.Response; import feign.Util; import feign.codec.Decoder; +import feign.codec.JsonDecoder; import java.io.IOException; import java.io.Reader; import java.lang.reflect.Type; @@ -31,7 +33,7 @@ /** * @author changjin wei(魏昌进) */ -public class Fastjson2Decoder implements Decoder { +public class Fastjson2Decoder implements Decoder, JsonDecoder { private final JSONReader.Feature[] features; @@ -59,4 +61,12 @@ public Object decode(Response response, Type type) throws IOException, FeignExce ensureClosed(reader); } } + + @Override + public Object convert(Object object, Type type) { + if (object instanceof JSONObject) { + return ((JSONObject) object).to(type); + } + return JSON.parseObject(JSON.toJSONString(object), type); + } } diff --git a/graphql/README.md b/graphql/README.md index 272fd3383c..036540e33a 100644 --- a/graphql/README.md +++ b/graphql/README.md @@ -57,18 +57,35 @@ The annotation processor generates a Java record for `User` at compile time: public record User(String id, String name, String email) {} ``` -Build the client with `GraphqlContract`, `GraphqlEncoder`, and `GraphqlDecoder`: +Build the client with `GraphqlContract`, `GraphqlEncoder`, and `GraphqlDecoder`. The `GraphqlDecoder` takes any `JsonDecoder` — all existing Feign decoders implement it: ```java +// Using Jackson UserApi api = Feign.builder() .contract(new GraphqlContract()) .encoder(new GraphqlEncoder(new JacksonEncoder())) - .decoder(new GraphqlDecoder()) + .decoder(new GraphqlDecoder(new JacksonDecoder())) .target(UserApi.class, "https://api.example.com/graphql"); User user = api.getUser("123"); ``` +Any JSON decoder works the same way: + +```java +// Gson +new GraphqlDecoder(new GsonDecoder()) + +// Moshi +new GraphqlDecoder(new MoshiDecoder()) + +// Jackson 3 +new GraphqlDecoder(new Jackson3Decoder()) + +// Fastjson2 +new GraphqlDecoder(new Fastjson2Decoder()) +``` + ## Mutations with Variables Methods with parameters are sent as GraphQL variables: diff --git a/graphql/pom.xml b/graphql/pom.xml index cdf87bc341..f5f770103a 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -39,11 +39,6 @@ feign-core - - com.fasterxml.jackson.core - jackson-databind - - ${project.groupId} feign-core diff --git a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java index b2833a0274..4a430a80e5 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java @@ -15,38 +15,24 @@ */ package feign.graphql; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import feign.Response; import feign.Util; import feign.codec.Decoder; -import java.io.BufferedReader; +import feign.codec.JsonDecoder; import java.io.IOException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.Optional; public class GraphqlDecoder implements Decoder { - private final ObjectMapper mapper; - private final Decoder delegate; + private final JsonDecoder jsonDecoder; - public GraphqlDecoder() { - this(new ObjectMapper(), null); - } - - public GraphqlDecoder(ObjectMapper mapper) { - this(mapper, null); - } - - public GraphqlDecoder(Decoder delegate) { - this(new ObjectMapper(), delegate); - } - - public GraphqlDecoder(ObjectMapper mapper, Decoder delegate) { - this.mapper = mapper; - this.delegate = delegate; + public GraphqlDecoder(JsonDecoder jsonDecoder) { + this.jsonDecoder = jsonDecoder; } @Override @@ -61,6 +47,7 @@ public Object decode(Response response, Type type) throws IOException { return optional ? Optional.ofNullable(result) : result; } + @SuppressWarnings("unchecked") private Object doDecode(Response response, Type type) throws IOException { if (response.status() == 404 || response.status() == 204) { return Util.emptyValueOf(type); @@ -69,63 +56,51 @@ private Object doDecode(Response response, Type type) throws IOException { return null; } - var reader = response.body().asReader(response.charset()); - if (!reader.markSupported()) { - reader = new BufferedReader(reader, 1); + var root = (Map) jsonDecoder.decode(response, Map.class); + if (root == null) { + return Util.emptyValueOf(type); } - var root = mapper.readTree(reader); - - var errorsNode = root.path("errors"); - if (!errorsNode.isMissingNode() && errorsNode.isArray() && !errorsNode.isEmpty()) { + var errors = root.get("errors"); + if (errors instanceof List errorList && !errorList.isEmpty()) { var operationField = resolveOperationField(root, response); throw new GraphqlErrorException( - response.status(), operationField, errorsNode.toString(), response.request()); + response.status(), operationField, errors.toString(), response.request()); } - var dataNode = root.path("data"); - if (dataNode.isMissingNode() || dataNode.isNull() || !dataNode.isObject()) { + var data = root.get("data"); + if (!(data instanceof Map)) { return Util.emptyValueOf(type); } - var fieldNames = dataNode.fieldNames(); + var dataMap = (Map) data; + var fieldNames = dataMap.keySet().iterator(); if (!fieldNames.hasNext()) { return Util.emptyValueOf(type); } var firstField = fieldNames.next(); - var operationData = dataNode.get(firstField); - if (operationData == null || operationData.isNull()) { + var operationData = dataMap.get(firstField); + if (operationData == null) { return Util.emptyValueOf(type); } - if (operationData.isArray() && !isCollectionOrArrayType(type)) { - if (operationData.isEmpty()) { + if (operationData instanceof List list && !isCollectionOrArrayType(type)) { + if (list.isEmpty()) { return Util.emptyValueOf(type); } - operationData = operationData.get(0); - } - - if (delegate != null) { - var dataBytes = mapper.writeValueAsBytes(operationData); - var dataResponse = - Response.builder() - .status(response.status()) - .reason(response.reason()) - .headers(response.headers()) - .request(response.request()) - .body(dataBytes) - .build(); - return delegate.decode(dataResponse, type); + operationData = list.get(0); } - return mapper.readValue(mapper.treeAsTokens(operationData), mapper.constructType(type)); + return jsonDecoder.convert(operationData, type); } - private String resolveOperationField(JsonNode root, Response response) { - var dataNode = root.path("data"); - if (!dataNode.isMissingNode() && dataNode.isObject()) { - var names = dataNode.fieldNames(); + @SuppressWarnings("unchecked") + private String resolveOperationField(Map root, Response response) { + var data = root.get("data"); + if (data instanceof Map) { + var dataMap = (Map) data; + var names = dataMap.keySet().iterator(); if (names.hasNext()) { return names.next(); } @@ -133,10 +108,19 @@ private String resolveOperationField(JsonNode root, Response response) { if (response.request() != null && response.request().body() != null) { try { - var requestBody = mapper.readTree(response.request().body()); - var query = requestBody.path("query").asText(null); - if (query != null) { - return GraphqlContract.extractOperationField(query); + var fakeResponse = + Response.builder() + .status(200) + .headers(Collections.emptyMap()) + .request(response.request()) + .body(response.request().body()) + .build(); + var requestBody = (Map) jsonDecoder.decode(fakeResponse, Map.class); + if (requestBody != null) { + var query = requestBody.get("query"); + if (query instanceof String queryStr) { + return GraphqlContract.extractOperationField(queryStr); + } } } catch (Exception e) { // ignore parsing errors @@ -147,9 +131,6 @@ private String resolveOperationField(JsonNode root, Response response) { } private boolean isOptionalType(Type type) { - if (type instanceof JavaType jt) { - return jt.getRawClass() == Optional.class; - } if (type instanceof ParameterizedType pt && pt.getRawType() instanceof Class cls) { return cls == Optional.class; } @@ -160,9 +141,6 @@ private boolean isOptionalType(Type type) { } private Type extractOptionalInnerType(Type type) { - if (type instanceof JavaType jt) { - return jt.containedType(0); - } if (type instanceof ParameterizedType pt) { return pt.getActualTypeArguments()[0]; } @@ -170,9 +148,6 @@ private Type extractOptionalInnerType(Type type) { } private boolean isCollectionOrArrayType(Type type) { - if (type instanceof JavaType jt) { - return jt.isCollectionLikeType() || jt.isArrayType(); - } if (type instanceof Class cls) { return cls.isArray() || Iterable.class.isAssignableFrom(cls); } diff --git a/graphql/src/test/java/feign/graphql/GraphqlClientTest.java b/graphql/src/test/java/feign/graphql/GraphqlClientTest.java index aa4d699561..21a40eb489 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlClientTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlClientTest.java @@ -23,6 +23,7 @@ import feign.Feign; import feign.Headers; import feign.Param; +import feign.jackson.JacksonDecoder; import feign.jackson.JacksonEncoder; import java.util.List; import java.util.Optional; @@ -97,7 +98,7 @@ private TestApi buildClient() { return Feign.builder() .contract(contract) .encoder(graphqlEncoder) - .decoder(new GraphqlDecoder(mapper)) + .decoder(new GraphqlDecoder(new JacksonDecoder(mapper))) .requestInterceptor(graphqlEncoder) .target(TestApi.class, server.url("/graphql").toString()); } diff --git a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java index f482d2cbe9..97b289edd3 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java @@ -23,6 +23,7 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; +import feign.jackson.JacksonDecoder; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; @@ -35,7 +36,7 @@ class GraphqlDecoderTest { private final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - private final GraphqlDecoder decoder = new GraphqlDecoder(mapper); + private final GraphqlDecoder decoder = new GraphqlDecoder(new JacksonDecoder(mapper)); public static class User { public String id; @@ -60,10 +61,7 @@ void decodesListResponse() throws Exception { var response = buildResponse(json); @SuppressWarnings("unchecked") - var users = - (List) - decoder.decode( - response, mapper.getTypeFactory().constructCollectionType(List.class, User.class)); + var users = (List) decoder.decode(response, parameterizedType(List.class, User.class)); assertThat(users).hasSize(2); assertThat(users.getFirst().name).isEqualTo("Alice"); @@ -153,30 +151,11 @@ void preservesArrayWhenReturnTypeIsList() throws Exception { var response = buildResponse(json); @SuppressWarnings("unchecked") - var users = - (List) - decoder.decode( - response, mapper.getTypeFactory().constructCollectionType(List.class, User.class)); + var users = (List) decoder.decode(response, parameterizedType(List.class, User.class)); assertThat(users).hasSize(2); } - @Test - void delegatesToCustomDecoder() throws Exception { - var json = "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Alice\"}}}"; - var customDecoder = - new GraphqlDecoder( - mapper, - (resp, type) -> - mapper.readValue(resp.body().asReader(resp.charset()), mapper.constructType(type))); - var response = buildResponse(json); - - var user = (User) customDecoder.decode(response, User.class); - - assertThat(user.id).isEqualTo("1"); - assertThat(user.name).isEqualTo("Alice"); - } - @Test void returnsOptionalWithValue() throws Exception { var json = "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Alice\"}}}"; @@ -241,22 +220,6 @@ void returnsOptionalEmptyForEmptyArray() throws Exception { assertThat(result).isEmpty(); } - @Test - void unwrapsSingleObjectFromArrayWithDelegate() throws Exception { - var json = "{\"data\":{\"ingestionStats\":[{\"id\":\"1\",\"name\":\"Alice\"}]}}"; - var customDecoder = - new GraphqlDecoder( - mapper, - (resp, type) -> - mapper.readValue(resp.body().asReader(resp.charset()), mapper.constructType(type))); - var response = buildResponse(json); - - var user = (User) customDecoder.decode(response, User.class); - - assertThat(user.id).isEqualTo("1"); - assertThat(user.name).isEqualTo("Alice"); - } - private Response buildResponse(String body) { return Response.builder() .status(200) @@ -294,4 +257,23 @@ public Type getOwnerType() { } }; } + + private static ParameterizedType parameterizedType(Type raw, Type... args) { + return new ParameterizedType() { + @Override + public Type[] getActualTypeArguments() { + return args; + } + + @Override + public Type getRawType() { + return raw; + } + + @Override + public Type getOwnerType() { + return null; + } + }; + } } diff --git a/gson/src/main/java/feign/gson/GsonDecoder.java b/gson/src/main/java/feign/gson/GsonDecoder.java index 90d4560baf..699c1d48ca 100644 --- a/gson/src/main/java/feign/gson/GsonDecoder.java +++ b/gson/src/main/java/feign/gson/GsonDecoder.java @@ -24,12 +24,13 @@ import feign.Response; import feign.Util; import feign.codec.Decoder; +import feign.codec.JsonDecoder; import java.io.IOException; import java.io.Reader; import java.lang.reflect.Type; import java.util.Collections; -public class GsonDecoder implements Decoder { +public class GsonDecoder implements Decoder, JsonDecoder { private final Gson gson; @@ -61,4 +62,9 @@ public Object decode(Response response, Type type) throws IOException { ensureClosed(reader); } } + + @Override + public Object convert(Object object, Type type) { + return gson.fromJson(gson.toJsonTree(object), type); + } } diff --git a/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrDecoder.java b/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrDecoder.java index fced9ba2f8..3edb1f8dda 100644 --- a/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrDecoder.java +++ b/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrDecoder.java @@ -22,6 +22,7 @@ import feign.Util; import feign.codec.DecodeException; import feign.codec.Decoder; +import feign.codec.JsonDecoder; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; @@ -30,8 +31,10 @@ import java.util.List; import java.util.Map; -/** A {@link Decoder} that uses Jackson Jr to convert objects to String or byte representation. */ -public class JacksonJrDecoder extends JacksonJrMapper implements Decoder { +/** + * A {@link JsonDecoder} that uses Jackson Jr to convert objects to String or byte representation. + */ +public class JacksonJrDecoder extends JacksonJrMapper implements Decoder, JsonDecoder { @FunctionalInterface protected interface Transformer { @@ -110,4 +113,25 @@ protected Transformer findTransformer(Response response, Type type) { } throw new DecodeException(500, "Cannot decode type: " + type.getTypeName(), response.request()); } + + @Override + public Object convert(Object object, Type type) throws IOException { + String json = mapper.asString(object); + if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) type; + Type rawType = pt.getRawType(); + Type[] args = pt.getActualTypeArguments(); + if (rawType.equals(List.class)) { + return mapper.listOfFrom((Class) args[0], json); + } + if (rawType.equals(Map.class)) { + return mapper.mapOfFrom((Class) args[1], json); + } + type = rawType; + } + if (type instanceof Class) { + return mapper.beanFrom((Class) type, json); + } + throw new IOException("Cannot convert to type: " + type.getTypeName()); + } } diff --git a/jackson/src/main/java/feign/jackson/JacksonDecoder.java b/jackson/src/main/java/feign/jackson/JacksonDecoder.java index e3bf26ce24..370f745dc7 100644 --- a/jackson/src/main/java/feign/jackson/JacksonDecoder.java +++ b/jackson/src/main/java/feign/jackson/JacksonDecoder.java @@ -22,13 +22,14 @@ import feign.Response; import feign.Util; import feign.codec.Decoder; +import feign.codec.JsonDecoder; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.lang.reflect.Type; import java.util.Collections; -public class JacksonDecoder implements Decoder { +public class JacksonDecoder implements Decoder, JsonDecoder { private final ObjectMapper mapper; @@ -70,4 +71,9 @@ public Object decode(Response response, Type type) throws IOException { throw e; } } + + @Override + public Object convert(Object object, Type type) { + return mapper.convertValue(object, mapper.constructType(type)); + } } diff --git a/jackson3/src/main/java/feign/jackson3/Jackson3Decoder.java b/jackson3/src/main/java/feign/jackson3/Jackson3Decoder.java index 723f0b146f..5726d582bd 100644 --- a/jackson3/src/main/java/feign/jackson3/Jackson3Decoder.java +++ b/jackson3/src/main/java/feign/jackson3/Jackson3Decoder.java @@ -18,6 +18,7 @@ import feign.Response; import feign.Util; import feign.codec.Decoder; +import feign.codec.JsonDecoder; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; @@ -28,7 +29,7 @@ import tools.jackson.databind.JacksonModule; import tools.jackson.databind.json.JsonMapper; -public class Jackson3Decoder implements Decoder { +public class Jackson3Decoder implements Decoder, JsonDecoder { private final JsonMapper mapper; @@ -71,4 +72,9 @@ public Object decode(Response response, Type type) throws IOException { throw e; } } + + @Override + public Object convert(Object object, Type type) { + return mapper.convertValue(object, mapper.constructType(type)); + } } diff --git a/json/src/main/java/feign/json/JsonDecoder.java b/json/src/main/java/feign/json/JsonDecoder.java index bd60a6fd0c..edf7fd80f0 100644 --- a/json/src/main/java/feign/json/JsonDecoder.java +++ b/json/src/main/java/feign/json/JsonDecoder.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.Reader; import java.lang.reflect.Type; +import java.util.Map; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -52,12 +53,13 @@ * System.out.println(contributors.getJSONObject(0).getString("login")); * */ -public class JsonDecoder implements Decoder { +public class JsonDecoder implements Decoder, feign.codec.JsonDecoder { @Override public Object decode(Response response, Type type) throws IOException, DecodeException { if (response.status() == 404 || response.status() == 204) - if (JSONObject.class.isAssignableFrom((Class) type)) return new JSONObject(); + if (Map.class.equals(type)) return null; + else if (JSONObject.class.isAssignableFrom((Class) type)) return new JSONObject(); else if (JSONArray.class.isAssignableFrom((Class) type)) return new JSONArray(); else if (String.class.equals(type)) return null; else @@ -86,7 +88,8 @@ public Object decode(Response response, Type type) throws IOException, DecodeExc private Object decodeBody(Response response, Type type, Reader reader) throws IOException { if (String.class.equals(type)) return Util.toString(reader); JSONTokener tokenizer = new JSONTokener(reader); - if (JSONObject.class.isAssignableFrom((Class) type)) return new JSONObject(tokenizer); + if (Map.class.equals(type)) return new JSONObject(tokenizer).toMap(); + else if (JSONObject.class.isAssignableFrom((Class) type)) return new JSONObject(tokenizer); else if (JSONArray.class.isAssignableFrom((Class) type)) return new JSONArray(tokenizer); else throw new DecodeException( @@ -94,4 +97,21 @@ private Object decodeBody(Response response, Type type, Reader reader) throws IO format("%s is not a type supported by this decoder.", type), response.request()); } + + @Override + public Object convert(Object object, Type type) throws IOException { + if (type instanceof Class) { + Class cls = (Class) type; + if (cls == JSONObject.class && object instanceof Map) { + return new JSONObject((Map) object); + } + if (cls == String.class) { + return object.toString(); + } + } + if (object instanceof Map) { + return new JSONObject((Map) object); + } + throw new IOException(type.getTypeName() + " is not a type supported by this decoder."); + } } diff --git a/moshi/src/main/java/feign/moshi/MoshiDecoder.java b/moshi/src/main/java/feign/moshi/MoshiDecoder.java index 02d508609b..ac08ee96a4 100644 --- a/moshi/src/main/java/feign/moshi/MoshiDecoder.java +++ b/moshi/src/main/java/feign/moshi/MoshiDecoder.java @@ -21,12 +21,13 @@ import feign.Response; import feign.Util; import feign.codec.Decoder; +import feign.codec.JsonDecoder; import java.io.IOException; import java.lang.reflect.Type; import okio.BufferedSource; import okio.Okio; -public class MoshiDecoder implements Decoder { +public class MoshiDecoder implements Decoder, JsonDecoder { private final Moshi moshi; public MoshiDecoder(Moshi moshi) { @@ -60,4 +61,10 @@ public Object decode(Response response, Type type) throws IOException { throw e; } } + + @Override + public Object convert(Object object, Type type) throws IOException { + JsonAdapter adapter = moshi.adapter(type); + return adapter.fromJsonValue(object); + } } From 916664416238f00a636898d3c7b2e17627839b0f Mon Sep 17 00:00:00 2001 From: Marvin Date: Wed, 25 Feb 2026 21:24:37 -0300 Subject: [PATCH 399/615] refactor: extract inner Default classes to standalone top-level classes (#3237) Signed-off-by: Marvin Froeder --- .../feign/error/AnnotationErrorDecoder.java | 6 +- ...ErrorDecoderExceptionConstructorsTest.java | 6 +- .../benchmark/RealRequestBenchmarks.java | 4 +- .../WhatShouldWeCacheBenchmarks.java | 5 +- core/src/main/java/feign/AsyncClient.java | 35 +-- core/src/main/java/feign/AsyncFeign.java | 4 +- core/src/main/java/feign/BaseBuilder.java | 15 +- core/src/main/java/feign/Client.java | 214 +--------------- core/src/main/java/feign/Contract.java | 134 +--------- .../main/java/feign/DefaultAsyncClient.java | 56 ++++ core/src/main/java/feign/DefaultClient.java | 240 ++++++++++++++++++ core/src/main/java/feign/DefaultContract.java | 153 +++++++++++ .../DefaultInvocationHandlerFactory.java | 28 ++ .../java/feign/DefaultQueryMapEncoder.java | 24 ++ core/src/main/java/feign/DefaultRetryer.java | 86 +++++++ core/src/main/java/feign/Feign.java | 2 +- .../java/feign/InvocationHandlerFactory.java | 12 +- core/src/main/java/feign/QueryMapEncoder.java | 8 +- core/src/main/java/feign/Retryer.java | 69 +---- core/src/main/java/feign/codec/Decoder.java | 19 +- .../main/java/feign/codec/DefaultDecoder.java | 34 +++ .../main/java/feign/codec/DefaultEncoder.java | 36 +++ .../java/feign/codec/DefaultErrorDecoder.java | 68 +++++ core/src/main/java/feign/codec/Encoder.java | 22 +- .../main/java/feign/codec/ErrorDecoder.java | 47 +--- core/src/test/java/feign/AsyncFeignTest.java | 19 +- core/src/test/java/feign/CapabilityTest.java | 4 +- core/src/test/java/feign/ClientTest.java | 4 +- .../ContractWithRuntimeInjectionTest.java | 2 +- .../feign/DefaultContractInheritanceTest.java | 2 +- .../test/java/feign/DefaultContractTest.java | 4 +- .../src/test/java/feign/FeignBuilderTest.java | 2 +- core/src/test/java/feign/FeignTest.java | 15 +- .../test/java/feign/FeignUnderAsyncTest.java | 13 +- .../feign/MethodMetadataPresenceTest.java | 10 +- core/src/test/java/feign/RetryerTest.java | 9 +- .../java/feign/client/DefaultClientTest.java | 5 +- .../java/feign/codec/DefaultDecoderTest.java | 2 +- .../java/feign/codec/DefaultEncoderTest.java | 2 +- .../DefaultErrorDecoderHttpErrorTest.java | 2 +- .../feign/codec/DefaultErrorDecoderTest.java | 4 +- .../feign/optionals/OptionalDecoderTests.java | 10 +- .../main/java/example/github/GitHubExample.kt | 3 +- .../java/example/github/GitHubExample.java | 3 +- .../feign/form/spring/SpringFormEncoder.java | 3 +- .../src/main/java/feign/form/FormEncoder.java | 3 +- .../java/feign/graphql/GraphqlContract.java | 4 +- .../feign/hc5/AsyncApacheHttp5ClientTest.java | 15 +- .../main/java/feign/hystrix/HystrixFeign.java | 3 +- .../test/Http2ClientAsyncTest.java | 17 +- .../java/feign/kotlin/CoroutineFeign.java | 7 +- .../kotlin/feign/kotlin/CoroutineFeignTest.kt | 3 +- .../feign/okhttp/OkHttpClientAsyncTest.java | 17 +- .../java/feign/reactive/ReactiveFeign.java | 3 +- .../ReactiveDelegatingContractTest.java | 9 +- .../ReactiveFeignIntegrationTest.java | 16 +- .../main/java/feign/ribbon/RibbonClient.java | 5 +- .../java/feign/ribbon/RibbonClientTest.java | 3 +- .../java/feign/soap/SOAPErrorDecoder.java | 3 +- .../java/feign/soap/SOAPErrorDecoder.java | 3 +- .../src/main/java/feign/VertxFeign.java | 13 +- .../test/java/feign/vertx/RetryingTest.java | 4 +- .../test/java/feign/vertx/RetryingTest.java | 4 +- 63 files changed, 943 insertions(+), 634 deletions(-) create mode 100644 core/src/main/java/feign/DefaultAsyncClient.java create mode 100644 core/src/main/java/feign/DefaultClient.java create mode 100644 core/src/main/java/feign/DefaultContract.java create mode 100644 core/src/main/java/feign/DefaultInvocationHandlerFactory.java create mode 100644 core/src/main/java/feign/DefaultQueryMapEncoder.java create mode 100644 core/src/main/java/feign/DefaultRetryer.java create mode 100644 core/src/main/java/feign/codec/DefaultDecoder.java create mode 100644 core/src/main/java/feign/codec/DefaultEncoder.java create mode 100644 core/src/main/java/feign/codec/DefaultErrorDecoder.java diff --git a/annotation-error-decoder/src/main/java/feign/error/AnnotationErrorDecoder.java b/annotation-error-decoder/src/main/java/feign/error/AnnotationErrorDecoder.java index 35e5969eff..20f2af10f7 100644 --- a/annotation-error-decoder/src/main/java/feign/error/AnnotationErrorDecoder.java +++ b/annotation-error-decoder/src/main/java/feign/error/AnnotationErrorDecoder.java @@ -19,6 +19,8 @@ import feign.Response; import feign.codec.Decoder; +import feign.codec.DefaultDecoder; +import feign.codec.DefaultErrorDecoder; import feign.codec.ErrorDecoder; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; @@ -52,8 +54,8 @@ public static AnnotationErrorDecoder.Builder builderFor(Class apiType) { public static class Builder { private final Class apiType; - private ErrorDecoder defaultDecoder = new ErrorDecoder.Default(); - private Decoder responseBodyDecoder = new Decoder.Default(); + private ErrorDecoder defaultDecoder = new DefaultErrorDecoder(); + private Decoder responseBodyDecoder = new DefaultDecoder(); public Builder(Class apiType) { this.apiType = apiType; diff --git a/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java b/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java index 94ec29ca0a..9728a46f5e 100644 --- a/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java +++ b/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java @@ -18,7 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; import feign.Request; -import feign.codec.Decoder; +import feign.codec.DefaultDecoder; import feign.error.AnnotationErrorDecoderExceptionConstructorsTest.TestClientInterfaceWithDifferentExceptionConstructors; import feign.error.AnnotationErrorDecoderExceptionConstructorsTest.TestClientInterfaceWithDifferentExceptionConstructors.DeclaredDefaultConstructorException; import feign.error.AnnotationErrorDecoderExceptionConstructorsTest.TestClientInterfaceWithDifferentExceptionConstructors.DeclaredDefaultConstructorWithOtherConstructorsException; @@ -232,7 +232,7 @@ void test( AnnotationErrorDecoder decoder = AnnotationErrorDecoder.builderFor( TestClientInterfaceWithDifferentExceptionConstructors.class) - .withResponseBodyDecoder(new OptionalDecoder(new Decoder.Default())) + .withResponseBodyDecoder(new OptionalDecoder(new DefaultDecoder())) .build(); Exception genericException = @@ -268,7 +268,7 @@ void ifExceptionIsNotInTheList( AnnotationErrorDecoder decoder = AnnotationErrorDecoder.builderFor( TestClientInterfaceWithDifferentExceptionConstructors.class) - .withResponseBodyDecoder(new OptionalDecoder(new Decoder.Default())) + .withResponseBodyDecoder(new OptionalDecoder(new DefaultDecoder())) .build(); Exception genericException = diff --git a/benchmark/src/main/java/feign/benchmark/RealRequestBenchmarks.java b/benchmark/src/main/java/feign/benchmark/RealRequestBenchmarks.java index c53427e082..052570f1b2 100644 --- a/benchmark/src/main/java/feign/benchmark/RealRequestBenchmarks.java +++ b/benchmark/src/main/java/feign/benchmark/RealRequestBenchmarks.java @@ -15,11 +15,11 @@ */ package feign.benchmark; +import feign.DefaultRetryer; import feign.Feign; import feign.Logger; import feign.Logger.Level; import feign.Response; -import feign.Retryer; import io.netty.buffer.ByteBuf; import io.reactivex.netty.protocol.http.server.HttpServer; import java.io.IOException; @@ -63,7 +63,7 @@ public void setup() { .client(new feign.okhttp.OkHttpClient(client)) .logLevel(Level.NONE) .logger(new Logger.ErrorLogger()) - .retryer(new Retryer.Default()) + .retryer(new DefaultRetryer()) .target(FeignTestInterface.class, "http://localhost:" + SERVER_PORT); queryRequest = new Request.Builder() diff --git a/benchmark/src/main/java/feign/benchmark/WhatShouldWeCacheBenchmarks.java b/benchmark/src/main/java/feign/benchmark/WhatShouldWeCacheBenchmarks.java index 3ff35a2a02..cd6002c1e2 100644 --- a/benchmark/src/main/java/feign/benchmark/WhatShouldWeCacheBenchmarks.java +++ b/benchmark/src/main/java/feign/benchmark/WhatShouldWeCacheBenchmarks.java @@ -17,6 +17,7 @@ import feign.Client; import feign.Contract; +import feign.DefaultContract; import feign.Feign; import feign.MethodMetadata; import feign.Response; @@ -53,11 +54,11 @@ public class WhatShouldWeCacheBenchmarks { @Setup public void setup() { - feignContract = new Contract.Default(); + feignContract = new DefaultContract(); cachedContact = new Contract() { private final List cached = - new Default().parseAndValidateMetadata(FeignTestInterface.class); + new DefaultContract().parseAndValidateMetadata(FeignTestInterface.class); public List parseAndValidateMetadata(Class declaring) { return cached; diff --git a/core/src/main/java/feign/AsyncClient.java b/core/src/main/java/feign/AsyncClient.java index fba30003ac..d724f13895 100644 --- a/core/src/main/java/feign/AsyncClient.java +++ b/core/src/main/java/feign/AsyncClient.java @@ -19,7 +19,6 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; /** Submits HTTP {@link Request requests} asynchronously, with an optional context. */ @Experimental @@ -40,36 +39,14 @@ public interface AsyncClient { */ CompletableFuture execute(Request request, Options options, Optional requestContext); - class Default implements AsyncClient { - - private final Client client; - private final ExecutorService executorService; + /** + * @deprecated use {@link DefaultAsyncClient} instead. + */ + @Deprecated + class Default extends DefaultAsyncClient { public Default(Client client, ExecutorService executorService) { - this.client = client; - this.executorService = executorService; - } - - @Override - public CompletableFuture execute( - Request request, Options options, Optional requestContext) { - final CompletableFuture result = new CompletableFuture<>(); - final Future future = - executorService.submit( - () -> { - try { - result.complete(client.execute(request, options)); - } catch (final Exception e) { - result.completeExceptionally(e); - } - }); - result.whenComplete( - (response, throwable) -> { - if (result.isCancelled()) { - future.cancel(true); - } - }); - return result; + super(client, executorService); } } diff --git a/core/src/main/java/feign/AsyncFeign.java b/core/src/main/java/feign/AsyncFeign.java index 9557403330..67948dd46e 100644 --- a/core/src/main/java/feign/AsyncFeign.java +++ b/core/src/main/java/feign/AsyncFeign.java @@ -70,8 +70,8 @@ public static class AsyncBuilder extends BaseBuilder, AsyncFe private AsyncContextSupplier defaultContextSupplier = () -> null; private AsyncClient client = - new AsyncClient.Default<>( - new Client.Default(null, null), LazyInitializedExecutorService.instance); + new DefaultAsyncClient<>( + new DefaultClient(null, null), LazyInitializedExecutorService.instance); private MethodInfoResolver methodInfoResolver = MethodInfo::new; @Deprecated diff --git a/core/src/main/java/feign/BaseBuilder.java b/core/src/main/java/feign/BaseBuilder.java index d2549e0a7b..5456bcb374 100644 --- a/core/src/main/java/feign/BaseBuilder.java +++ b/core/src/main/java/feign/BaseBuilder.java @@ -21,6 +21,9 @@ import feign.Logger.NoOpLogger; import feign.Request.Options; import feign.codec.Decoder; +import feign.codec.DefaultDecoder; +import feign.codec.DefaultEncoder; +import feign.codec.DefaultErrorDecoder; import feign.codec.Encoder; import feign.codec.ErrorDecoder; import java.lang.reflect.Field; @@ -38,18 +41,18 @@ public abstract class BaseBuilder, T> implements Clo protected final List requestInterceptors = new ArrayList<>(); protected final List responseInterceptors = new ArrayList<>(); protected Logger.Level logLevel = Logger.Level.NONE; - protected Contract contract = new Contract.Default(); - protected Retryer retryer = new Retryer.Default(); + protected Contract contract = new DefaultContract(); + protected Retryer retryer = new DefaultRetryer(); protected Logger logger = new NoOpLogger(); - protected Encoder encoder = new Encoder.Default(); - protected Decoder decoder = new Decoder.Default(); + protected Encoder encoder = new DefaultEncoder(); + protected Decoder decoder = new DefaultDecoder(); protected boolean closeAfterDecode = true; protected boolean decodeVoid = false; protected QueryMapEncoder queryMapEncoder = QueryMap.MapEncoder.FIELD.instance(); - protected ErrorDecoder errorDecoder = new ErrorDecoder.Default(); + protected ErrorDecoder errorDecoder = new DefaultErrorDecoder(); protected Options options = new Options(); protected InvocationHandlerFactory invocationHandlerFactory = - new InvocationHandlerFactory.Default(); + new DefaultInvocationHandlerFactory(); protected boolean dismiss404; protected ExceptionPropagationPolicy propagationPolicy = NONE; protected List capabilities = new ArrayList<>(); diff --git a/core/src/main/java/feign/Client.java b/core/src/main/java/feign/Client.java index 3c3d048c29..939f305a61 100644 --- a/core/src/main/java/feign/Client.java +++ b/core/src/main/java/feign/Client.java @@ -15,36 +15,18 @@ */ package feign; -import static feign.Util.ACCEPT_ENCODING; -import static feign.Util.CONTENT_ENCODING; -import static feign.Util.CONTENT_LENGTH; -import static feign.Util.ENCODING_DEFLATE; -import static feign.Util.ENCODING_GZIP; import static feign.Util.checkArgument; import static feign.Util.checkNotNull; import static feign.Util.isNotBlank; -import static java.lang.String.CASE_INSENSITIVE_ORDER; -import static java.lang.String.format; import feign.Request.Options; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.Proxy; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Base64; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; -import java.util.zip.InflaterInputStream; import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSocketFactory; /** Submits HTTP {@link Request requests}. Implementations are expected to be thread-safe. */ @@ -60,206 +42,26 @@ public interface Client { */ Response execute(Request request, Options options) throws IOException; - class Default implements Client { - - private final SSLSocketFactory sslContextFactory; - private final HostnameVerifier hostnameVerifier; - - /** - * Disable the request body internal buffering for {@code HttpURLConnection}. - * - * @see HttpURLConnection#setFixedLengthStreamingMode(int) - * @see HttpURLConnection#setFixedLengthStreamingMode(long) - * @see HttpURLConnection#setChunkedStreamingMode(int) - */ - private final boolean disableRequestBuffering; + /** + * @deprecated use {@link DefaultClient} instead. + */ + @Deprecated + class Default extends DefaultClient { - /** - * Create a new client, which disable request buffering by default. - * - * @param sslContextFactory SSLSocketFactory for secure https URL connections. - * @param hostnameVerifier the host name verifier. - */ public Default(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) { - this.sslContextFactory = sslContextFactory; - this.hostnameVerifier = hostnameVerifier; - this.disableRequestBuffering = true; + super(sslContextFactory, hostnameVerifier); } - /** - * Create a new client. - * - * @param sslContextFactory SSLSocketFactory for secure https URL connections. - * @param hostnameVerifier the host name verifier. - * @param disableRequestBuffering Disable the request body internal buffering for {@code - * HttpURLConnection}. - */ public Default( SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier, boolean disableRequestBuffering) { - super(); - this.sslContextFactory = sslContextFactory; - this.hostnameVerifier = hostnameVerifier; - this.disableRequestBuffering = disableRequestBuffering; - } - - @Override - public Response execute(Request request, Options options) throws IOException { - HttpURLConnection connection = convertAndSend(request, options); - return convertResponse(connection, request); - } - - Response convertResponse(HttpURLConnection connection, Request request) throws IOException { - int status = connection.getResponseCode(); - String reason = connection.getResponseMessage(); - - if (status < 0) { - throw new IOException( - format( - "Invalid status(%s) executing %s %s", - status, connection.getRequestMethod(), connection.getURL())); - } - - Map> headers = new TreeMap<>(CASE_INSENSITIVE_ORDER); - for (Map.Entry> field : connection.getHeaderFields().entrySet()) { - // response message - if (field.getKey() != null) { - headers.put(field.getKey(), field.getValue()); - } - } - - Integer length = connection.getContentLength(); - if (length == -1) { - length = null; - } - InputStream stream; - if (status >= 400) { - stream = connection.getErrorStream(); - } else { - stream = connection.getInputStream(); - } - if (stream != null && this.isGzip(headers.get(CONTENT_ENCODING))) { - stream = new GZIPInputStream(stream); - } else if (stream != null && this.isDeflate(headers.get(CONTENT_ENCODING))) { - stream = new InflaterInputStream(stream); - } - return Response.builder() - .status(status) - .reason(reason) - .headers(headers) - .request(request) - .body(stream, length) - .build(); - } - - public HttpURLConnection getConnection(final URL url) throws IOException { - return (HttpURLConnection) url.openConnection(); - } - - HttpURLConnection convertAndSend(Request request, Options options) throws IOException { - final URL url = new URL(request.url()); - final HttpURLConnection connection = this.getConnection(url); - if (connection instanceof HttpsURLConnection) { - HttpsURLConnection sslCon = (HttpsURLConnection) connection; - if (sslContextFactory != null) { - sslCon.setSSLSocketFactory(sslContextFactory); - } - if (hostnameVerifier != null) { - sslCon.setHostnameVerifier(hostnameVerifier); - } - } - connection.setConnectTimeout(options.connectTimeoutMillis()); - connection.setReadTimeout(options.readTimeoutMillis()); - connection.setAllowUserInteraction(false); - connection.setInstanceFollowRedirects(options.isFollowRedirects()); - connection.setRequestMethod(request.httpMethod().name()); - - Collection contentEncodingValues = request.headers().get(CONTENT_ENCODING); - boolean gzipEncodedRequest = this.isGzip(contentEncodingValues); - boolean deflateEncodedRequest = this.isDeflate(contentEncodingValues); - - boolean hasAcceptHeader = false; - Integer contentLength = null; - for (String field : request.headers().keySet()) { - if (field.equalsIgnoreCase("Accept")) { - hasAcceptHeader = true; - } - for (String value : request.headers().get(field)) { - if (field.equals(CONTENT_LENGTH)) { - if (!gzipEncodedRequest && !deflateEncodedRequest) { - contentLength = Integer.valueOf(value); - connection.addRequestProperty(field, value); - } - } - // Avoid add "Accept-encoding" twice or more when "compression" option is enabled - else if (field.equals(ACCEPT_ENCODING)) { - connection.addRequestProperty(field, String.join(", ", request.headers().get(field))); - break; - } else { - connection.addRequestProperty(field, value); - } - } - } - // Some servers choke on the default accept string. - if (!hasAcceptHeader) { - connection.addRequestProperty("Accept", "*/*"); - } - - byte[] body = request.body(); - - if (body != null) { - /* - * Ignore disableRequestBuffering flag if the empty body was set, to ensure that internal - * retry logic applies to such requests. - */ - if (disableRequestBuffering) { - if (contentLength != null) { - connection.setFixedLengthStreamingMode(contentLength); - } else { - connection.setChunkedStreamingMode(8196); - } - } - connection.setDoOutput(true); - OutputStream out = connection.getOutputStream(); - if (gzipEncodedRequest) { - out = new GZIPOutputStream(out); - } else if (deflateEncodedRequest) { - out = new DeflaterOutputStream(out); - } - try { - out.write(body); - } finally { - try { - out.close(); - } catch (IOException suppressed) { // NOPMD - } - } - } - - if (body == null && request.httpMethod().isWithBody()) { - // To use this Header, set 'sun.net.http.allowRestrictedHeaders' property true. - connection.addRequestProperty("Content-Length", "0"); - } - - return connection; - } - - private boolean isGzip(Collection contentEncodingValues) { - return contentEncodingValues != null - && !contentEncodingValues.isEmpty() - && contentEncodingValues.contains(ENCODING_GZIP); - } - - private boolean isDeflate(Collection contentEncodingValues) { - return contentEncodingValues != null - && !contentEncodingValues.isEmpty() - && contentEncodingValues.contains(ENCODING_DEFLATE); + super(sslContextFactory, hostnameVerifier, disableRequestBuffering); } } /** Client that supports a {@link java.net.Proxy}. */ - class Proxied extends Default { + class Proxied extends DefaultClient { public static final String PROXY_AUTHORIZATION = "Proxy-Authorization"; private final Proxy proxy; diff --git a/core/src/main/java/feign/Contract.java b/core/src/main/java/feign/Contract.java index e014121a36..516272f45a 100644 --- a/core/src/main/java/feign/Contract.java +++ b/core/src/main/java/feign/Contract.java @@ -16,13 +16,10 @@ package feign; import static feign.Util.checkState; -import static feign.Util.emptyToNull; -import feign.Request.HttpMethod; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.net.URI; @@ -31,8 +28,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** Defines what annotations and values are valid on interfaces. */ public interface Contract { @@ -251,128 +246,9 @@ protected void nameParam(MethodMetadata data, String name, int i) { } } - class Default extends DeclarativeContract { - - static final Pattern REQUEST_LINE_PATTERN = Pattern.compile("^([A-Z]+)[ ]*(.*)$"); - - public Default() { - super.registerClassAnnotation( - Headers.class, - (header, data) -> { - final String[] headersOnType = header.value(); - checkState( - headersOnType.length > 0, - "Headers annotation was empty on type %s.", - data.configKey()); - final Map> headers = toMap(headersOnType); - headers.putAll(data.template().headers()); - data.template().headers(null); // to clear - data.template().headers(headers); - }); - super.registerMethodAnnotation( - RequestLine.class, - (ann, data) -> { - final String requestLine = ann.value(); - checkState( - emptyToNull(requestLine) != null, - "RequestLine annotation was empty on method %s.", - data.configKey()); - - final Matcher requestLineMatcher = REQUEST_LINE_PATTERN.matcher(requestLine); - if (!requestLineMatcher.find()) { - throw new IllegalStateException( - String.format( - "RequestLine annotation didn't start with an HTTP verb on method %s", - data.configKey())); - } else { - data.template().method(HttpMethod.valueOf(requestLineMatcher.group(1))); - data.template().uri(requestLineMatcher.group(2)); - } - data.template().decodeSlash(ann.decodeSlash()); - data.template().collectionFormat(ann.collectionFormat()); - }); - super.registerMethodAnnotation( - Body.class, - (ann, data) -> { - final String body = ann.value(); - checkState( - emptyToNull(body) != null, - "Body annotation was empty on method %s.", - data.configKey()); - if (body.indexOf('{') == -1) { - data.template().body(body); - } else { - data.template().bodyTemplate(body); - } - }); - super.registerMethodAnnotation( - Headers.class, - (header, data) -> { - final String[] headersOnMethod = header.value(); - checkState( - headersOnMethod.length > 0, - "Headers annotation was empty on method %s.", - data.configKey()); - data.template().headers(toMap(headersOnMethod)); - }); - super.registerParameterAnnotation( - Param.class, - (paramAnnotation, data, paramIndex) -> { - final String annotationName = paramAnnotation.value(); - final Parameter parameter = data.method().getParameters()[paramIndex]; - final String name; - if (emptyToNull(annotationName) == null && parameter.isNamePresent()) { - name = parameter.getName(); - } else { - name = annotationName; - } - checkState( - emptyToNull(name) != null, - "Param annotation was empty on param %s.\nHint: %s", - paramIndex, - "Prefer using @Param(value=\"name\"), or compile your code with the -parameters flag.\n" - + "If the value is missing, Feign attempts to retrieve the parameter name from bytecode, " - + "which only works if the class was compiled with the -parameters flag."); - nameParam(data, name, paramIndex); - final Class expander = paramAnnotation.expander(); - if (expander != Param.ToStringExpander.class) { - data.indexToExpanderClass().put(paramIndex, expander); - } - if (!data.template().hasRequestVariable(name)) { - data.formParams().add(name); - } - }); - super.registerParameterAnnotation( - QueryMap.class, - (queryMap, data, paramIndex) -> { - checkState( - data.queryMapIndex() == null, - "QueryMap annotation was present on multiple parameters."); - data.queryMapIndex(paramIndex); - data.queryMapEncoder(queryMap.mapEncoder().instance()); - }); - super.registerParameterAnnotation( - HeaderMap.class, - (queryMap, data, paramIndex) -> { - checkState( - data.headerMapIndex() == null, - "HeaderMap annotation was present on multiple parameters."); - data.headerMapIndex(paramIndex); - }); - } - - private static Map> toMap(String[] input) { - final Map> result = - new LinkedHashMap>(input.length); - for (final String header : input) { - final int colon = header.indexOf(':'); - final String name = header.substring(0, colon); - if (!result.containsKey(name)) { - result.put(name, new ArrayList(1)); - } - result.get(name).add(header.substring(colon + 1).trim()); - } - return result; - } - } + /** + * @deprecated use {@link DefaultContract} instead. + */ + @Deprecated + class Default extends DefaultContract {} } diff --git a/core/src/main/java/feign/DefaultAsyncClient.java b/core/src/main/java/feign/DefaultAsyncClient.java new file mode 100644 index 0000000000..4df0d22911 --- /dev/null +++ b/core/src/main/java/feign/DefaultAsyncClient.java @@ -0,0 +1,56 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import feign.Request.Options; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + +@Experimental +public class DefaultAsyncClient implements AsyncClient { + + private final Client client; + private final ExecutorService executorService; + + public DefaultAsyncClient(Client client, ExecutorService executorService) { + this.client = client; + this.executorService = executorService; + } + + @Override + public CompletableFuture execute( + Request request, Options options, Optional requestContext) { + final CompletableFuture result = new CompletableFuture<>(); + final Future future = + executorService.submit( + () -> { + try { + result.complete(client.execute(request, options)); + } catch (final Exception e) { + result.completeExceptionally(e); + } + }); + result.whenComplete( + (response, throwable) -> { + if (result.isCancelled()) { + future.cancel(true); + } + }); + return result; + } +} diff --git a/core/src/main/java/feign/DefaultClient.java b/core/src/main/java/feign/DefaultClient.java new file mode 100644 index 0000000000..d8e02fb4ad --- /dev/null +++ b/core/src/main/java/feign/DefaultClient.java @@ -0,0 +1,240 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import static feign.Util.ACCEPT_ENCODING; +import static feign.Util.CONTENT_ENCODING; +import static feign.Util.CONTENT_LENGTH; +import static feign.Util.ENCODING_DEFLATE; +import static feign.Util.ENCODING_GZIP; +import static java.lang.String.CASE_INSENSITIVE_ORDER; +import static java.lang.String.format; + +import feign.Request.Options; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; +import java.util.zip.InflaterInputStream; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; + +public class DefaultClient implements Client { + + private final SSLSocketFactory sslContextFactory; + private final HostnameVerifier hostnameVerifier; + + /** + * Disable the request body internal buffering for {@code HttpURLConnection}. + * + * @see HttpURLConnection#setFixedLengthStreamingMode(int) + * @see HttpURLConnection#setFixedLengthStreamingMode(long) + * @see HttpURLConnection#setChunkedStreamingMode(int) + */ + private final boolean disableRequestBuffering; + + /** + * Create a new client, which disable request buffering by default. + * + * @param sslContextFactory SSLSocketFactory for secure https URL connections. + * @param hostnameVerifier the host name verifier. + */ + public DefaultClient(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) { + this.sslContextFactory = sslContextFactory; + this.hostnameVerifier = hostnameVerifier; + this.disableRequestBuffering = true; + } + + /** + * Create a new client. + * + * @param sslContextFactory SSLSocketFactory for secure https URL connections. + * @param hostnameVerifier the host name verifier. + * @param disableRequestBuffering Disable the request body internal buffering for {@code + * HttpURLConnection}. + */ + public DefaultClient( + SSLSocketFactory sslContextFactory, + HostnameVerifier hostnameVerifier, + boolean disableRequestBuffering) { + super(); + this.sslContextFactory = sslContextFactory; + this.hostnameVerifier = hostnameVerifier; + this.disableRequestBuffering = disableRequestBuffering; + } + + @Override + public Response execute(Request request, Options options) throws IOException { + HttpURLConnection connection = convertAndSend(request, options); + return convertResponse(connection, request); + } + + Response convertResponse(HttpURLConnection connection, Request request) throws IOException { + int status = connection.getResponseCode(); + String reason = connection.getResponseMessage(); + + if (status < 0) { + throw new IOException( + format( + "Invalid status(%s) executing %s %s", + status, connection.getRequestMethod(), connection.getURL())); + } + + Map> headers = new TreeMap<>(CASE_INSENSITIVE_ORDER); + for (Map.Entry> field : connection.getHeaderFields().entrySet()) { + // response message + if (field.getKey() != null) { + headers.put(field.getKey(), field.getValue()); + } + } + + Integer length = connection.getContentLength(); + if (length == -1) { + length = null; + } + InputStream stream; + if (status >= 400) { + stream = connection.getErrorStream(); + } else { + stream = connection.getInputStream(); + } + if (stream != null && this.isGzip(headers.get(CONTENT_ENCODING))) { + stream = new GZIPInputStream(stream); + } else if (stream != null && this.isDeflate(headers.get(CONTENT_ENCODING))) { + stream = new InflaterInputStream(stream); + } + return Response.builder() + .status(status) + .reason(reason) + .headers(headers) + .request(request) + .body(stream, length) + .build(); + } + + public HttpURLConnection getConnection(final URL url) throws IOException { + return (HttpURLConnection) url.openConnection(); + } + + HttpURLConnection convertAndSend(Request request, Options options) throws IOException { + final URL url = new URL(request.url()); + final HttpURLConnection connection = this.getConnection(url); + if (connection instanceof HttpsURLConnection) { + HttpsURLConnection sslCon = (HttpsURLConnection) connection; + if (sslContextFactory != null) { + sslCon.setSSLSocketFactory(sslContextFactory); + } + if (hostnameVerifier != null) { + sslCon.setHostnameVerifier(hostnameVerifier); + } + } + connection.setConnectTimeout(options.connectTimeoutMillis()); + connection.setReadTimeout(options.readTimeoutMillis()); + connection.setAllowUserInteraction(false); + connection.setInstanceFollowRedirects(options.isFollowRedirects()); + connection.setRequestMethod(request.httpMethod().name()); + + Collection contentEncodingValues = request.headers().get(CONTENT_ENCODING); + boolean gzipEncodedRequest = this.isGzip(contentEncodingValues); + boolean deflateEncodedRequest = this.isDeflate(contentEncodingValues); + + boolean hasAcceptHeader = false; + Integer contentLength = null; + for (String field : request.headers().keySet()) { + if (field.equalsIgnoreCase("Accept")) { + hasAcceptHeader = true; + } + for (String value : request.headers().get(field)) { + if (field.equals(CONTENT_LENGTH)) { + if (!gzipEncodedRequest && !deflateEncodedRequest) { + contentLength = Integer.valueOf(value); + connection.addRequestProperty(field, value); + } + } + // Avoid add "Accept-encoding" twice or more when "compression" option is enabled + else if (field.equals(ACCEPT_ENCODING)) { + connection.addRequestProperty(field, String.join(", ", request.headers().get(field))); + break; + } else { + connection.addRequestProperty(field, value); + } + } + } + // Some servers choke on the default accept string. + if (!hasAcceptHeader) { + connection.addRequestProperty("Accept", "*/*"); + } + + byte[] body = request.body(); + + if (body != null) { + /* + * Ignore disableRequestBuffering flag if the empty body was set, to ensure that internal + * retry logic applies to such requests. + */ + if (disableRequestBuffering) { + if (contentLength != null) { + connection.setFixedLengthStreamingMode(contentLength); + } else { + connection.setChunkedStreamingMode(8196); + } + } + connection.setDoOutput(true); + OutputStream out = connection.getOutputStream(); + if (gzipEncodedRequest) { + out = new GZIPOutputStream(out); + } else if (deflateEncodedRequest) { + out = new DeflaterOutputStream(out); + } + try { + out.write(body); + } finally { + try { + out.close(); + } catch (IOException suppressed) { // NOPMD + } + } + } + + if (body == null && request.httpMethod().isWithBody()) { + // To use this Header, set 'sun.net.http.allowRestrictedHeaders' property true. + connection.addRequestProperty("Content-Length", "0"); + } + + return connection; + } + + private boolean isGzip(Collection contentEncodingValues) { + return contentEncodingValues != null + && !contentEncodingValues.isEmpty() + && contentEncodingValues.contains(ENCODING_GZIP); + } + + private boolean isDeflate(Collection contentEncodingValues) { + return contentEncodingValues != null + && !contentEncodingValues.isEmpty() + && contentEncodingValues.contains(ENCODING_DEFLATE); + } +} diff --git a/core/src/main/java/feign/DefaultContract.java b/core/src/main/java/feign/DefaultContract.java new file mode 100644 index 0000000000..79edadde82 --- /dev/null +++ b/core/src/main/java/feign/DefaultContract.java @@ -0,0 +1,153 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import static feign.Util.checkState; +import static feign.Util.emptyToNull; + +import feign.Request.HttpMethod; +import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DefaultContract extends DeclarativeContract { + + static final Pattern REQUEST_LINE_PATTERN = Pattern.compile("^([A-Z]+)[ ]*(.*)$"); + + public DefaultContract() { + super.registerClassAnnotation( + Headers.class, + (header, data) -> { + final String[] headersOnType = header.value(); + checkState( + headersOnType.length > 0, + "Headers annotation was empty on type %s.", + data.configKey()); + final Map> headers = toMap(headersOnType); + headers.putAll(data.template().headers()); + data.template().headers(null); // to clear + data.template().headers(headers); + }); + super.registerMethodAnnotation( + RequestLine.class, + (ann, data) -> { + final String requestLine = ann.value(); + checkState( + emptyToNull(requestLine) != null, + "RequestLine annotation was empty on method %s.", + data.configKey()); + + final Matcher requestLineMatcher = REQUEST_LINE_PATTERN.matcher(requestLine); + if (!requestLineMatcher.find()) { + throw new IllegalStateException( + String.format( + "RequestLine annotation didn't start with an HTTP verb on method %s", + data.configKey())); + } else { + data.template().method(HttpMethod.valueOf(requestLineMatcher.group(1))); + data.template().uri(requestLineMatcher.group(2)); + } + data.template().decodeSlash(ann.decodeSlash()); + data.template().collectionFormat(ann.collectionFormat()); + }); + super.registerMethodAnnotation( + Body.class, + (ann, data) -> { + final String body = ann.value(); + checkState( + emptyToNull(body) != null, + "Body annotation was empty on method %s.", + data.configKey()); + if (body.indexOf('{') == -1) { + data.template().body(body); + } else { + data.template().bodyTemplate(body); + } + }); + super.registerMethodAnnotation( + Headers.class, + (header, data) -> { + final String[] headersOnMethod = header.value(); + checkState( + headersOnMethod.length > 0, + "Headers annotation was empty on method %s.", + data.configKey()); + data.template().headers(toMap(headersOnMethod)); + }); + super.registerParameterAnnotation( + Param.class, + (paramAnnotation, data, paramIndex) -> { + final String annotationName = paramAnnotation.value(); + final Parameter parameter = data.method().getParameters()[paramIndex]; + final String name; + if (emptyToNull(annotationName) == null && parameter.isNamePresent()) { + name = parameter.getName(); + } else { + name = annotationName; + } + checkState( + emptyToNull(name) != null, + "Param annotation was empty on param %s.\nHint: %s", + paramIndex, + "Prefer using @Param(value=\"name\"), or compile your code with the -parameters flag.\n" + + "If the value is missing, Feign attempts to retrieve the parameter name from bytecode, " + + "which only works if the class was compiled with the -parameters flag."); + nameParam(data, name, paramIndex); + final Class expander = paramAnnotation.expander(); + if (expander != Param.ToStringExpander.class) { + data.indexToExpanderClass().put(paramIndex, expander); + } + if (!data.template().hasRequestVariable(name)) { + data.formParams().add(name); + } + }); + super.registerParameterAnnotation( + QueryMap.class, + (queryMap, data, paramIndex) -> { + checkState( + data.queryMapIndex() == null, + "QueryMap annotation was present on multiple parameters."); + data.queryMapIndex(paramIndex); + data.queryMapEncoder(queryMap.mapEncoder().instance()); + }); + super.registerParameterAnnotation( + HeaderMap.class, + (queryMap, data, paramIndex) -> { + checkState( + data.headerMapIndex() == null, + "HeaderMap annotation was present on multiple parameters."); + data.headerMapIndex(paramIndex); + }); + } + + private static Map> toMap(String[] input) { + final Map> result = + new LinkedHashMap>(input.length); + for (final String header : input) { + final int colon = header.indexOf(':'); + final String name = header.substring(0, colon); + if (!result.containsKey(name)) { + result.put(name, new ArrayList(1)); + } + result.get(name).add(header.substring(colon + 1).trim()); + } + return result; + } +} diff --git a/core/src/main/java/feign/DefaultInvocationHandlerFactory.java b/core/src/main/java/feign/DefaultInvocationHandlerFactory.java new file mode 100644 index 0000000000..b6b6d32ef0 --- /dev/null +++ b/core/src/main/java/feign/DefaultInvocationHandlerFactory.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.Map; + +public class DefaultInvocationHandlerFactory implements InvocationHandlerFactory { + + @Override + public InvocationHandler create(Target target, Map dispatch) { + return new ReflectiveFeign.FeignInvocationHandler(target, dispatch); + } +} diff --git a/core/src/main/java/feign/DefaultQueryMapEncoder.java b/core/src/main/java/feign/DefaultQueryMapEncoder.java new file mode 100644 index 0000000000..f1df747f92 --- /dev/null +++ b/core/src/main/java/feign/DefaultQueryMapEncoder.java @@ -0,0 +1,24 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import feign.querymap.FieldQueryMapEncoder; + +/** + * @deprecated use {@link feign.querymap.BeanQueryMapEncoder} instead. + */ +@Deprecated +public class DefaultQueryMapEncoder extends FieldQueryMapEncoder {} diff --git a/core/src/main/java/feign/DefaultRetryer.java b/core/src/main/java/feign/DefaultRetryer.java new file mode 100644 index 0000000000..9248d8c42b --- /dev/null +++ b/core/src/main/java/feign/DefaultRetryer.java @@ -0,0 +1,86 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import static java.util.concurrent.TimeUnit.SECONDS; + +public class DefaultRetryer implements Retryer { + + private final int maxAttempts; + private final long period; + private final long maxPeriod; + int attempt; + long sleptForMillis; + + public DefaultRetryer() { + this(100, SECONDS.toMillis(1), 5); + } + + public DefaultRetryer(long period, long maxPeriod, int maxAttempts) { + this.period = period; + this.maxPeriod = maxPeriod; + this.maxAttempts = maxAttempts; + this.attempt = 1; + } + + // visible for testing; + protected long currentTimeMillis() { + return System.currentTimeMillis(); + } + + public void continueOrPropagate(RetryableException e) { + if (attempt++ >= maxAttempts) { + throw e; + } + + long interval; + if (e.retryAfter() != null) { + interval = e.retryAfter() - currentTimeMillis(); + if (interval > maxPeriod) { + interval = maxPeriod; + } + if (interval < 0) { + return; + } + } else { + interval = nextMaxInterval(); + } + try { + Thread.sleep(interval); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + throw e; + } + sleptForMillis += interval; + } + + /** + * Calculates the time interval to a retry attempt.
+ * The interval increases exponentially with each attempt, at a rate of nextInterval *= 1.5 (where + * 1.5 is the backoff factor), to the maximum interval. + * + * @return time in milliseconds from now until the next attempt. + */ + long nextMaxInterval() { + long interval = (long) (period * Math.pow(1.5, attempt - 1)); + return Math.min(interval, maxPeriod); + } + + @Override + public Retryer clone() { + return new DefaultRetryer(period, maxPeriod, maxAttempts); + } +} diff --git a/core/src/main/java/feign/Feign.java b/core/src/main/java/feign/Feign.java index 950b0c4e8c..c9095fb1d8 100644 --- a/core/src/main/java/feign/Feign.java +++ b/core/src/main/java/feign/Feign.java @@ -95,7 +95,7 @@ public static String configKey(Method method) { public static class Builder extends BaseBuilder { - private Client client = new Client.Default(null, null); + private Client client = new DefaultClient(null, null); @Override public Builder logLevel(Logger.Level logLevel) { diff --git a/core/src/main/java/feign/InvocationHandlerFactory.java b/core/src/main/java/feign/InvocationHandlerFactory.java index f091e91a2f..64cd47f8ea 100644 --- a/core/src/main/java/feign/InvocationHandlerFactory.java +++ b/core/src/main/java/feign/InvocationHandlerFactory.java @@ -37,11 +37,9 @@ interface Factory { } } - static final class Default implements InvocationHandlerFactory { - - @Override - public InvocationHandler create(Target target, Map dispatch) { - return new ReflectiveFeign.FeignInvocationHandler(target, dispatch); - } - } + /** + * @deprecated use {@link DefaultInvocationHandlerFactory} instead. + */ + @Deprecated + static final class Default extends DefaultInvocationHandlerFactory {} } diff --git a/core/src/main/java/feign/QueryMapEncoder.java b/core/src/main/java/feign/QueryMapEncoder.java index 9543136f94..8ba510f03b 100644 --- a/core/src/main/java/feign/QueryMapEncoder.java +++ b/core/src/main/java/feign/QueryMapEncoder.java @@ -36,10 +36,8 @@ public interface QueryMapEncoder { Map encode(Object object); /** - * @deprecated use {@link BeanQueryMapEncoder} instead. default encoder uses reflection to inspect - * provided objects Fields to expand the objects values into a query string. If you prefer - * that the query string be built using getter and setter methods, as defined in the Java - * Beans API, please use the {@link BeanQueryMapEncoder} + * @deprecated use {@link DefaultQueryMapEncoder} instead. */ - class Default extends FieldQueryMapEncoder {} + @Deprecated + class Default extends DefaultQueryMapEncoder {} } diff --git a/core/src/main/java/feign/Retryer.java b/core/src/main/java/feign/Retryer.java index 0f7045333f..e4023f3777 100644 --- a/core/src/main/java/feign/Retryer.java +++ b/core/src/main/java/feign/Retryer.java @@ -15,8 +15,6 @@ */ package feign; -import static java.util.concurrent.TimeUnit.SECONDS; - /** * Cloned for each invocation to {@link Client#execute(Request, feign.Request.Options)}. * Implementations may keep state to determine if retry operations should continue or not. @@ -30,71 +28,18 @@ public interface Retryer extends Cloneable { Retryer clone(); - class Default implements Retryer { - - private final int maxAttempts; - private final long period; - private final long maxPeriod; - int attempt; - long sleptForMillis; + /** + * @deprecated use {@link DefaultRetryer} instead. + */ + @Deprecated + class Default extends DefaultRetryer { public Default() { - this(100, SECONDS.toMillis(1), 5); + super(); } public Default(long period, long maxPeriod, int maxAttempts) { - this.period = period; - this.maxPeriod = maxPeriod; - this.maxAttempts = maxAttempts; - this.attempt = 1; - } - - // visible for testing; - protected long currentTimeMillis() { - return System.currentTimeMillis(); - } - - public void continueOrPropagate(RetryableException e) { - if (attempt++ >= maxAttempts) { - throw e; - } - - long interval; - if (e.retryAfter() != null) { - interval = e.retryAfter() - currentTimeMillis(); - if (interval > maxPeriod) { - interval = maxPeriod; - } - if (interval < 0) { - return; - } - } else { - interval = nextMaxInterval(); - } - try { - Thread.sleep(interval); - } catch (InterruptedException ignored) { - Thread.currentThread().interrupt(); - throw e; - } - sleptForMillis += interval; - } - - /** - * Calculates the time interval to a retry attempt.
- * The interval increases exponentially with each attempt, at a rate of nextInterval *= 1.5 - * (where 1.5 is the backoff factor), to the maximum interval. - * - * @return time in milliseconds from now until the next attempt. - */ - long nextMaxInterval() { - long interval = (long) (period * Math.pow(1.5, attempt - 1)); - return Math.min(interval, maxPeriod); - } - - @Override - public Retryer clone() { - return new Default(period, maxPeriod, maxAttempts); + super(period, maxPeriod, maxAttempts); } } diff --git a/core/src/main/java/feign/codec/Decoder.java b/core/src/main/java/feign/codec/Decoder.java index defe925abf..4ae473b9b2 100644 --- a/core/src/main/java/feign/codec/Decoder.java +++ b/core/src/main/java/feign/codec/Decoder.java @@ -18,7 +18,6 @@ import feign.Feign; import feign.FeignException; import feign.Response; -import feign.Util; import java.io.IOException; import java.lang.reflect.Type; @@ -85,17 +84,9 @@ public interface Decoder { */ Object decode(Response response, Type type) throws IOException, DecodeException, FeignException; - /** Default implementation of {@code Decoder}. */ - public class Default extends StringDecoder { - - @Override - public Object decode(Response response, Type type) throws IOException { - if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type); - if (response.body() == null) return null; - if (byte[].class.equals(type)) { - return Util.toByteArray(response.body().asInputStream()); - } - return super.decode(response, type); - } - } + /** + * @deprecated use {@link DefaultDecoder} instead. + */ + @Deprecated + public class Default extends DefaultDecoder {} } diff --git a/core/src/main/java/feign/codec/DefaultDecoder.java b/core/src/main/java/feign/codec/DefaultDecoder.java new file mode 100644 index 0000000000..c6ada10252 --- /dev/null +++ b/core/src/main/java/feign/codec/DefaultDecoder.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.codec; + +import feign.Response; +import feign.Util; +import java.io.IOException; +import java.lang.reflect.Type; + +public class DefaultDecoder extends StringDecoder { + + @Override + public Object decode(Response response, Type type) throws IOException { + if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type); + if (response.body() == null) return null; + if (byte[].class.equals(type)) { + return Util.toByteArray(response.body().asInputStream()); + } + return super.decode(response, type); + } +} diff --git a/core/src/main/java/feign/codec/DefaultEncoder.java b/core/src/main/java/feign/codec/DefaultEncoder.java new file mode 100644 index 0000000000..39a0f8daba --- /dev/null +++ b/core/src/main/java/feign/codec/DefaultEncoder.java @@ -0,0 +1,36 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.codec; + +import static java.lang.String.format; + +import feign.RequestTemplate; +import java.lang.reflect.Type; + +public class DefaultEncoder implements Encoder { + + @Override + public void encode(Object object, Type bodyType, RequestTemplate template) { + if (bodyType == String.class) { + template.body(object.toString()); + } else if (bodyType == byte[].class) { + template.body((byte[]) object, null); + } else if (object != null) { + throw new EncodeException( + format("%s is not a type supported by this encoder.", object.getClass())); + } + } +} diff --git a/core/src/main/java/feign/codec/DefaultErrorDecoder.java b/core/src/main/java/feign/codec/DefaultErrorDecoder.java new file mode 100644 index 0000000000..fc7172cd4e --- /dev/null +++ b/core/src/main/java/feign/codec/DefaultErrorDecoder.java @@ -0,0 +1,68 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.codec; + +import static feign.FeignException.errorStatus; +import static feign.Util.RETRY_AFTER; + +import feign.FeignException; +import feign.Response; +import feign.RetryableException; +import java.util.Collection; +import java.util.Map; + +public class DefaultErrorDecoder implements ErrorDecoder { + + private final ErrorDecoder.RetryAfterDecoder retryAfterDecoder = + new ErrorDecoder.RetryAfterDecoder(); + private Integer maxBodyBytesLength; + private Integer maxBodyCharsLength; + + public DefaultErrorDecoder() { + this.maxBodyBytesLength = null; + this.maxBodyCharsLength = null; + } + + public DefaultErrorDecoder(Integer maxBodyBytesLength, Integer maxBodyCharsLength) { + this.maxBodyBytesLength = maxBodyBytesLength; + this.maxBodyCharsLength = maxBodyCharsLength; + } + + @Override + public Exception decode(String methodKey, Response response) { + FeignException exception = + errorStatus(methodKey, response, maxBodyBytesLength, maxBodyCharsLength); + Long retryAfter = retryAfterDecoder.apply(firstOrNull(response.headers(), RETRY_AFTER)); + if (retryAfter != null) { + return new RetryableException( + response.status(), + exception.getMessage(), + response.request().httpMethod(), + exception, + retryAfter, + response.request(), + methodKey); + } + return exception; + } + + private T firstOrNull(Map> map, String key) { + if (map.containsKey(key) && !map.get(key).isEmpty()) { + return map.get(key).iterator().next(); + } + return null; + } +} diff --git a/core/src/main/java/feign/codec/Encoder.java b/core/src/main/java/feign/codec/Encoder.java index 79a7f2003d..143d33b228 100644 --- a/core/src/main/java/feign/codec/Encoder.java +++ b/core/src/main/java/feign/codec/Encoder.java @@ -15,8 +15,6 @@ */ package feign.codec; -import static java.lang.String.format; - import feign.RequestTemplate; import feign.Util; import java.lang.reflect.Type; @@ -83,19 +81,9 @@ public interface Encoder { */ void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException; - /** Default implementation of {@code Encoder}. */ - class Default implements Encoder { - - @Override - public void encode(Object object, Type bodyType, RequestTemplate template) { - if (bodyType == String.class) { - template.body(object.toString()); - } else if (bodyType == byte[].class) { - template.body((byte[]) object, null); - } else if (object != null) { - throw new EncodeException( - format("%s is not a type supported by this encoder.", object.getClass())); - } - } - } + /** + * @deprecated use {@link DefaultEncoder} instead. + */ + @Deprecated + class Default extends DefaultEncoder {} } diff --git a/core/src/main/java/feign/codec/ErrorDecoder.java b/core/src/main/java/feign/codec/ErrorDecoder.java index 83c72ee887..a2a55dc54a 100644 --- a/core/src/main/java/feign/codec/ErrorDecoder.java +++ b/core/src/main/java/feign/codec/ErrorDecoder.java @@ -15,20 +15,14 @@ */ package feign.codec; -import static feign.FeignException.errorStatus; -import static feign.Util.RETRY_AFTER; import static feign.Util.checkNotNull; import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; import static java.util.concurrent.TimeUnit.SECONDS; -import feign.FeignException; import feign.Response; -import feign.RetryableException; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; -import java.util.Collection; -import java.util.Map; /** * Allows you to massage an exception into a application-specific one. Converting out to a throttle @@ -81,45 +75,18 @@ public interface ErrorDecoder { */ public Exception decode(String methodKey, Response response); - public class Default implements ErrorDecoder { - - private final RetryAfterDecoder retryAfterDecoder = new RetryAfterDecoder(); - private Integer maxBodyBytesLength; - private Integer maxBodyCharsLength; + /** + * @deprecated use {@link DefaultErrorDecoder} instead. + */ + @Deprecated + public class Default extends DefaultErrorDecoder { public Default() { - this.maxBodyBytesLength = null; - this.maxBodyCharsLength = null; + super(); } public Default(Integer maxBodyBytesLength, Integer maxBodyCharsLength) { - this.maxBodyBytesLength = maxBodyBytesLength; - this.maxBodyCharsLength = maxBodyCharsLength; - } - - @Override - public Exception decode(String methodKey, Response response) { - FeignException exception = - errorStatus(methodKey, response, maxBodyBytesLength, maxBodyCharsLength); - Long retryAfter = retryAfterDecoder.apply(firstOrNull(response.headers(), RETRY_AFTER)); - if (retryAfter != null) { - return new RetryableException( - response.status(), - exception.getMessage(), - response.request().httpMethod(), - exception, - retryAfter, - response.request(), - methodKey); - } - return exception; - } - - private T firstOrNull(Map> map, String key) { - if (map.containsKey(key) && !map.get(key).isEmpty()) { - return map.get(key).iterator().next(); - } - return null; + super(maxBodyBytesLength, maxBodyCharsLength); } } diff --git a/core/src/test/java/feign/AsyncFeignTest.java b/core/src/test/java/feign/AsyncFeignTest.java index 62f2c8067f..efd965632e 100644 --- a/core/src/test/java/feign/AsyncFeignTest.java +++ b/core/src/test/java/feign/AsyncFeignTest.java @@ -32,6 +32,9 @@ import feign.Target.HardCodedTarget; import feign.codec.DecodeException; import feign.codec.Decoder; +import feign.codec.DefaultDecoder; +import feign.codec.DefaultEncoder; +import feign.codec.DefaultErrorDecoder; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.ErrorDecoder; @@ -145,7 +148,7 @@ void bodyTypeCorrespondsWithParameterType() throws Exception { TestInterfaceAsync api = new TestInterfaceAsyncBuilder() .encoder( - new Encoder.Default() { + new DefaultEncoder() { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { encodedType.set(bodyType); @@ -645,7 +648,7 @@ void throwsOriginalExceptionAfterFailedRetries() throws Throwable { TestInterfaceAsync api = AsyncFeign.builder() .exceptionPropagationPolicy(UNWRAP) - .retryer(new Retryer.Default(1, 1, 2)) + .retryer(new DefaultRetryer(1, 1, 2)) .errorDecoder( (_, response) -> new RetryableException( @@ -671,7 +674,7 @@ void throwsRetryableExceptionIfNoUnderlyingCause() throws Throwable { TestInterfaceAsync api = AsyncFeign.builder() .exceptionPropagationPolicy(UNWRAP) - .retryer(new Retryer.Default(1, 1, 2)) + .retryer(new DefaultRetryer(1, 1, 2)) .errorDecoder( (_, response) -> new RetryableException( @@ -705,7 +708,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { // fake client as Client.Default follows redirects. TestInterfaceAsync api = AsyncFeign.builder() - .client(new AsyncClient.Default<>((_, _) -> response, execs)) + .client(new DefaultAsyncClient<>((_, _) -> response, execs)) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); assertThat(unwrap(api.response()).headers()) @@ -755,7 +758,7 @@ public void cancelRetry(final int expectedTryCount) throws Throwable { final TestInterfaceAsync sut = AsyncFeign.builder() .client(clientMock) - .retryer(new Retryer.Default(0, Long.MAX_VALUE, expectedTryCount * 2)) + .retryer(new DefaultRetryer(0, Long.MAX_VALUE, expectedTryCount * 2)) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); // Act @@ -1194,7 +1197,7 @@ public void apply(RequestTemplate template) { } } - static class IllegalArgumentExceptionOn400 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn400 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -1205,7 +1208,7 @@ public Exception decode(String methodKey, Response response) { } } - static class IllegalArgumentExceptionOn404 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn404 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -1220,7 +1223,7 @@ static final class TestInterfaceAsyncBuilder { private final AsyncFeign.AsyncBuilder delegate = AsyncFeign.builder() - .decoder(new Decoder.Default()) + .decoder(new DefaultDecoder()) .encoder( (object, _, template) -> { if (object instanceof Map) { diff --git a/core/src/test/java/feign/CapabilityTest.java b/core/src/test/java/feign/CapabilityTest.java index bc68902491..3acfe89cb4 100644 --- a/core/src/test/java/feign/CapabilityTest.java +++ b/core/src/test/java/feign/CapabilityTest.java @@ -27,7 +27,7 @@ class CapabilityTest { private class AClient implements Client { public AClient(Client client) { - if (!(client instanceof Client.Default)) { + if (!(client instanceof DefaultClient)) { throw new RuntimeException( "Test is chaining invokations, expected Default Client instace here"); } @@ -58,7 +58,7 @@ void enrichClient() { Client enriched = (Client) Capability.enrich( - new Client.Default(null, null), + new DefaultClient(null, null), Client.class, Arrays.asList( new Capability() { diff --git a/core/src/test/java/feign/ClientTest.java b/core/src/test/java/feign/ClientTest.java index 8f6a072b70..cdfe54d292 100644 --- a/core/src/test/java/feign/ClientTest.java +++ b/core/src/test/java/feign/ClientTest.java @@ -68,7 +68,7 @@ void testConvertAndSendWithAcceptEncoding() throws IOException { Request request = Request.create( Request.HttpMethod.GET, "http://example.com", headers, body, requestTemplate); - Client.Default defaultClient = new Client.Default(null, null); + DefaultClient defaultClient = new DefaultClient(null, null); HttpURLConnection urlConnection = defaultClient.convertAndSend(request, options); Map> requestProperties = urlConnection.getRequestProperties(); // Test Avoid add "Accept-encoding" twice or more when "compression" option is enabled @@ -89,7 +89,7 @@ void testConvertAndSendWithContentLength() throws IOException { Request request = Request.create( Request.HttpMethod.GET, "http://example.com", headers, body, requestTemplate); - Client.Default defaultClient = new Client.Default(null, null); + DefaultClient defaultClient = new DefaultClient(null, null); HttpURLConnection urlConnection = defaultClient.convertAndSend(request, options); Map> requestProperties = urlConnection.getRequestProperties(); String requestProperty = urlConnection.getRequestProperty(Util.CONTENT_LENGTH); diff --git a/core/src/test/java/feign/ContractWithRuntimeInjectionTest.java b/core/src/test/java/feign/ContractWithRuntimeInjectionTest.java index 6d03fd16f2..12be78518c 100644 --- a/core/src/test/java/feign/ContractWithRuntimeInjectionTest.java +++ b/core/src/test/java/feign/ContractWithRuntimeInjectionTest.java @@ -96,7 +96,7 @@ static class ContractWithRuntimeInjection implements Contract { */ @Override public List parseAndValidateMetadata(Class targetType) { - List result = new Contract.Default().parseAndValidateMetadata(targetType); + List result = new DefaultContract().parseAndValidateMetadata(targetType); for (MethodMetadata md : result) { Map indexToExpander = new LinkedHashMap<>(); for (Map.Entry> entry : diff --git a/core/src/test/java/feign/DefaultContractInheritanceTest.java b/core/src/test/java/feign/DefaultContractInheritanceTest.java index f8eb63b364..77788f037e 100644 --- a/core/src/test/java/feign/DefaultContractInheritanceTest.java +++ b/core/src/test/java/feign/DefaultContractInheritanceTest.java @@ -30,7 +30,7 @@ */ class DefaultContractInheritanceTest { - Contract.Default contract = new Contract.Default(); + DefaultContract contract = new DefaultContract(); @Headers("Foo: Bar") interface SimpleParameterizedBaseApi { diff --git a/core/src/test/java/feign/DefaultContractTest.java b/core/src/test/java/feign/DefaultContractTest.java index e704ca57ab..6b26d1ed0e 100644 --- a/core/src/test/java/feign/DefaultContractTest.java +++ b/core/src/test/java/feign/DefaultContractTest.java @@ -48,7 +48,7 @@ */ class DefaultContractTest { - Contract.Default contract = new Contract.Default(); + DefaultContract contract = new DefaultContract(); @Test void httpMethods() throws Exception { @@ -863,7 +863,7 @@ void errorMessageOnMixedContracts() { assertThrows( IllegalStateException.class, () -> contract.parseAndValidateMetadata(MixedAnnotations.class)); - assertThat(exception.getMessage()).contains("are not used by contract Default"); + assertThat(exception.getMessage()).contains("are not used by contract DefaultContract"); } interface MixedAnnotations { diff --git a/core/src/test/java/feign/FeignBuilderTest.java b/core/src/test/java/feign/FeignBuilderTest.java index 2194c02490..2db2fd9df5 100644 --- a/core/src/test/java/feign/FeignBuilderTest.java +++ b/core/src/test/java/feign/FeignBuilderTest.java @@ -400,7 +400,7 @@ void doNotCloseAfterDecodeDecoderFailure() { Feign.builder() .client( new Client() { - Client client = new Client.Default(null, null); + Client client = new DefaultClient(null, null); @Override public Response execute(Request request, Request.Options options) diff --git a/core/src/test/java/feign/FeignTest.java b/core/src/test/java/feign/FeignTest.java index 6369047419..748bfe1ad5 100755 --- a/core/src/test/java/feign/FeignTest.java +++ b/core/src/test/java/feign/FeignTest.java @@ -39,6 +39,9 @@ import feign.Target.HardCodedTarget; import feign.codec.DecodeException; import feign.codec.Decoder; +import feign.codec.DefaultDecoder; +import feign.codec.DefaultEncoder; +import feign.codec.DefaultErrorDecoder; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.ErrorDecoder; @@ -166,7 +169,7 @@ void bodyTypeCorrespondsWithParameterType() throws Exception { TestInterface api = new TestInterfaceBuilder() .encoder( - new Encoder.Default() { + new DefaultEncoder() { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { encodedType.set(bodyType); @@ -665,7 +668,7 @@ void throwsOriginalExceptionAfterFailedRetries() throws Exception { TestInterface api = Feign.builder() .exceptionPropagationPolicy(UNWRAP) - .retryer(new Retryer.Default(1, 1, 2)) + .retryer(new DefaultRetryer(1, 1, 2)) .errorDecoder( (_, response) -> new RetryableException( @@ -690,7 +693,7 @@ void throwsRetryableExceptionIfNoUnderlyingCause() throws Exception { TestInterface api = Feign.builder() .exceptionPropagationPolicy(UNWRAP) - .retryer(new Retryer.Default(1, 1, 2)) + .retryer(new DefaultRetryer(1, 1, 2)) .errorDecoder( (_, response) -> new RetryableException( @@ -1398,7 +1401,7 @@ public void apply(RequestTemplate template) { } } - static class IllegalArgumentExceptionOn400 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn400 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -1409,7 +1412,7 @@ public Exception decode(String methodKey, Response response) { } } - static class IllegalArgumentExceptionOn404 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn404 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -1424,7 +1427,7 @@ static final class TestInterfaceBuilder { private final Feign.Builder delegate = new Feign.Builder() - .decoder(new Decoder.Default()) + .decoder(new DefaultDecoder()) .encoder( (object, _, template) -> { if (object instanceof Map) { diff --git a/core/src/test/java/feign/FeignUnderAsyncTest.java b/core/src/test/java/feign/FeignUnderAsyncTest.java index d99c543cf7..f18fd5d747 100644 --- a/core/src/test/java/feign/FeignUnderAsyncTest.java +++ b/core/src/test/java/feign/FeignUnderAsyncTest.java @@ -30,6 +30,9 @@ import feign.Target.HardCodedTarget; import feign.codec.DecodeException; import feign.codec.Decoder; +import feign.codec.DefaultDecoder; +import feign.codec.DefaultEncoder; +import feign.codec.DefaultErrorDecoder; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.ErrorDecoder; @@ -128,7 +131,7 @@ void bodyTypeCorrespondsWithParameterType() throws Exception { TestInterface api = new TestInterfaceBuilder() .encoder( - new Encoder.Default() { + new DefaultEncoder() { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { encodedType.set(bodyType); @@ -533,7 +536,7 @@ void whenReturnTypeIsResponseNoErrorHandling() { // fake client as Client.Default follows redirects. TestInterface api = AsyncFeign.builder() - .client(new AsyncClient.Default<>((_, _) -> response, execs)) + .client(new DefaultAsyncClient<>((_, _) -> response, execs)) .target(TestInterface.class, "http://localhost:" + server.getPort()); assertThat(api.response().headers()) @@ -931,7 +934,7 @@ public void apply(RequestTemplate template) { } } - static class IllegalArgumentExceptionOn400 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn400 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -942,7 +945,7 @@ public Exception decode(String methodKey, Response response) { } } - static class IllegalArgumentExceptionOn404 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn404 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -957,7 +960,7 @@ static final class TestInterfaceBuilder { private final AsyncFeign.AsyncBuilder delegate = AsyncFeign.builder() - .decoder(new Decoder.Default()) + .decoder(new DefaultDecoder()) .encoder( (object, _, template) -> { if (object instanceof Map) { diff --git a/core/src/test/java/feign/MethodMetadataPresenceTest.java b/core/src/test/java/feign/MethodMetadataPresenceTest.java index 653fbd29bf..3be2c6054d 100644 --- a/core/src/test/java/feign/MethodMetadataPresenceTest.java +++ b/core/src/test/java/feign/MethodMetadataPresenceTest.java @@ -20,8 +20,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import feign.FeignBuilderTest.TestInterface; -import feign.codec.Decoder; -import feign.codec.Encoder; +import feign.codec.DefaultDecoder; +import feign.codec.DefaultEncoder; import java.io.IOException; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -44,7 +44,7 @@ void client() throws Exception { assertNotNull(request.requestTemplate()); assertNotNull(request.requestTemplate().methodMetadata()); assertNotNull(request.requestTemplate().feignTarget()); - return new Client.Default(null, null).execute(request, options); + return new DefaultClient(null, null).execute(request, options); }) .target(TestInterface.class, url); @@ -66,7 +66,7 @@ void encoder() throws Exception { assertNotNull(template); assertNotNull(template.methodMetadata()); assertNotNull(template.feignTarget()); - new Encoder.Default().encode(object, bodyType, template); + new DefaultEncoder().encode(object, bodyType, template); }) .target(TestInterface.class, url); @@ -89,7 +89,7 @@ void decoder() throws Exception { assertNotNull(template); assertNotNull(template.methodMetadata()); assertNotNull(template.feignTarget()); - return new Decoder.Default().decode(response, type); + return new DefaultDecoder().decode(response, type); }) .target(TestInterface.class, url); diff --git a/core/src/test/java/feign/RetryerTest.java b/core/src/test/java/feign/RetryerTest.java index 2b1d604819..74ed8e832b 100644 --- a/core/src/test/java/feign/RetryerTest.java +++ b/core/src/test/java/feign/RetryerTest.java @@ -19,7 +19,6 @@ import static org.assertj.core.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertThrows; -import feign.Retryer.Default; import java.util.Collections; import org.junit.jupiter.api.Test; @@ -33,7 +32,7 @@ class RetryerTest { void only5TriesAllowedAndExponentialBackoff() { final Long nonRetryable = null; RetryableException e = new RetryableException(-1, null, null, nonRetryable, REQUEST); - Default retryer = new Retryer.Default(); + DefaultRetryer retryer = new DefaultRetryer(); assertThat(retryer.attempt).isEqualTo(1); assertThat(retryer.sleptForMillis).isEqualTo(0); @@ -57,8 +56,8 @@ void only5TriesAllowedAndExponentialBackoff() { @Test void considersRetryAfterButNotMoreThanMaxPeriod() { - Default retryer = - new Retryer.Default() { + DefaultRetryer retryer = + new DefaultRetryer() { @Override protected long currentTimeMillis() { return 0; @@ -81,7 +80,7 @@ void neverRetryAlwaysPropagates() { @Test void defaultRetryerFailsOnInterruptedException() { - Default retryer = new Retryer.Default(); + DefaultRetryer retryer = new DefaultRetryer(); Thread.currentThread().interrupt(); RetryableException expected = diff --git a/core/src/test/java/feign/client/DefaultClientTest.java b/core/src/test/java/feign/client/DefaultClientTest.java index 6e05606e76..c61b1b0a4d 100644 --- a/core/src/test/java/feign/client/DefaultClientTest.java +++ b/core/src/test/java/feign/client/DefaultClientTest.java @@ -21,6 +21,7 @@ import feign.Client; import feign.Client.Proxied; +import feign.DefaultClient; import feign.Feign; import feign.Feign.Builder; import feign.RetryableException; @@ -37,11 +38,11 @@ public class DefaultClientTest extends AbstractClientTest { protected Client disableHostnameVerification = - new Client.Default(TrustingSSLSocketFactory.get(), (_, _) -> true); + new DefaultClient(TrustingSSLSocketFactory.get(), (_, _) -> true); @Override public Builder newBuilder() { - return Feign.builder().client(new Client.Default(TrustingSSLSocketFactory.get(), null, false)); + return Feign.builder().client(new DefaultClient(TrustingSSLSocketFactory.get(), null, false)); } @Test diff --git a/core/src/test/java/feign/codec/DefaultDecoderTest.java b/core/src/test/java/feign/codec/DefaultDecoderTest.java index f22828ec81..23ba1d4d06 100644 --- a/core/src/test/java/feign/codec/DefaultDecoderTest.java +++ b/core/src/test/java/feign/codec/DefaultDecoderTest.java @@ -35,7 +35,7 @@ @SuppressWarnings("deprecation") class DefaultDecoderTest { - private final Decoder decoder = new Decoder.Default(); + private final Decoder decoder = new DefaultDecoder(); @Test void decodesToString() throws Exception { diff --git a/core/src/test/java/feign/codec/DefaultEncoderTest.java b/core/src/test/java/feign/codec/DefaultEncoderTest.java index 6808ef4a60..9aecbb9059 100644 --- a/core/src/test/java/feign/codec/DefaultEncoderTest.java +++ b/core/src/test/java/feign/codec/DefaultEncoderTest.java @@ -26,7 +26,7 @@ class DefaultEncoderTest { - private final Encoder encoder = new Encoder.Default(); + private final Encoder encoder = new DefaultEncoder(); @Test void encodesStrings() throws Exception { diff --git a/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java b/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java index 934abb0834..c9dae156bd 100644 --- a/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java +++ b/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java @@ -126,7 +126,7 @@ public static Object[][] errorCodes() { public Class expectedExceptionClass; public String expectedMessage; - private ErrorDecoder errorDecoder = new ErrorDecoder.Default(); + private ErrorDecoder errorDecoder = new DefaultErrorDecoder(); private Map> headers = new LinkedHashMap<>(); diff --git a/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java b/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java index d074f2e0bc..1967e77632 100644 --- a/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java +++ b/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java @@ -36,7 +36,7 @@ @SuppressWarnings("deprecation") class DefaultErrorDecoderTest { - private ErrorDecoder errorDecoder = new ErrorDecoder.Default(); + private ErrorDecoder errorDecoder = new DefaultErrorDecoder(); private Map> headers = new LinkedHashMap<>(); @@ -154,7 +154,7 @@ void lengthOfBodyExceptionTest() { Exception defaultException = errorDecoder.decode("Service#foo()", response); assertThat(defaultException.getMessage().length()).isLessThan(response.body().length()); - ErrorDecoder customizedErrorDecoder = new ErrorDecoder.Default(4000, 2000); + ErrorDecoder customizedErrorDecoder = new DefaultErrorDecoder(4000, 2000); Exception customizedException = customizedErrorDecoder.decode("Service#foo()", response); assertThat(customizedException.getMessage().length()) .isGreaterThanOrEqualTo(response.body().length()); diff --git a/core/src/test/java/feign/optionals/OptionalDecoderTests.java b/core/src/test/java/feign/optionals/OptionalDecoderTests.java index ef54854ac3..d2e015cb25 100644 --- a/core/src/test/java/feign/optionals/OptionalDecoderTests.java +++ b/core/src/test/java/feign/optionals/OptionalDecoderTests.java @@ -19,7 +19,7 @@ import feign.Feign; import feign.RequestLine; -import feign.codec.Decoder; +import feign.codec.DefaultDecoder; import java.io.IOException; import java.util.Optional; import okhttp3.mockwebserver.MockResponse; @@ -45,7 +45,7 @@ void simple404OptionalTest() throws IOException, InterruptedException { final OptionalInterface api = Feign.builder() .dismiss404() - .decoder(new OptionalDecoder(new Decoder.Default())) + .decoder(new OptionalDecoder(new DefaultDecoder())) .target(OptionalInterface.class, server.url("/").toString()); assertThat(api.getAsOptional().isPresent()).isFalse(); @@ -59,7 +59,7 @@ void simple204OptionalTest() throws IOException, InterruptedException { final OptionalInterface api = Feign.builder() - .decoder(new OptionalDecoder(new Decoder.Default())) + .decoder(new OptionalDecoder(new DefaultDecoder())) .target(OptionalInterface.class, server.url("/").toString()); assertThat(api.getAsOptional().isPresent()).isFalse(); @@ -72,7 +72,7 @@ void test200WithOptionalString() throws IOException, InterruptedException { final OptionalInterface api = Feign.builder() - .decoder(new OptionalDecoder(new Decoder.Default())) + .decoder(new OptionalDecoder(new DefaultDecoder())) .target(OptionalInterface.class, server.url("/").toString()); Optional response = api.getAsOptional(); @@ -101,7 +101,7 @@ void test200WhenDecodingNoOptional() throws IOException, InterruptedException { final OptionalInterface api = Feign.builder() - .decoder(new OptionalDecoder(new Decoder.Default())) + .decoder(new OptionalDecoder(new DefaultDecoder())) .target(OptionalInterface.class, server.url("/").toString()); assertThat(api.get()).isEqualTo("foo"); diff --git a/example-github-with-coroutine/src/main/java/example/github/GitHubExample.kt b/example-github-with-coroutine/src/main/java/example/github/GitHubExample.kt index 6af850993b..548f710da5 100644 --- a/example-github-with-coroutine/src/main/java/example/github/GitHubExample.kt +++ b/example-github-with-coroutine/src/main/java/example/github/GitHubExample.kt @@ -24,6 +24,7 @@ import feign.Response import feign.codec.Decoder import feign.codec.Encoder import feign.codec.ErrorDecoder +import feign.codec.DefaultErrorDecoder import feign.gson.GsonEncoder import feign.kotlin.CoroutineFeign import java.io.IOException @@ -122,7 +123,7 @@ internal class GitHubClientError() : RuntimeException() { internal class GitHubErrorDecoder( private val decoder: Decoder ) : ErrorDecoder { - private val defaultDecoder: ErrorDecoder = ErrorDecoder.Default() + private val defaultDecoder: ErrorDecoder = DefaultErrorDecoder() override fun decode(methodKey: String, response: Response): Exception { return try { // must replace status by 200 other GSONDecoder returns null diff --git a/example-github/src/main/java/example/github/GitHubExample.java b/example-github/src/main/java/example/github/GitHubExample.java index 41351df5f8..ecb7368b04 100644 --- a/example-github/src/main/java/example/github/GitHubExample.java +++ b/example-github/src/main/java/example/github/GitHubExample.java @@ -17,6 +17,7 @@ import feign.*; import feign.codec.Decoder; +import feign.codec.DefaultErrorDecoder; import feign.codec.Encoder; import feign.codec.ErrorDecoder; import feign.gson.GsonDecoder; @@ -128,7 +129,7 @@ public static void main(String... args) { static class GitHubErrorDecoder implements ErrorDecoder { final Decoder decoder; - final ErrorDecoder defaultDecoder = new ErrorDecoder.Default(); + final ErrorDecoder defaultDecoder = new DefaultErrorDecoder(); GitHubErrorDecoder(Decoder decoder) { this.decoder = decoder; diff --git a/form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java b/form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java index 58f350f13e..67c9bd2177 100644 --- a/form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java +++ b/form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java @@ -19,6 +19,7 @@ import static java.util.Collections.singletonMap; import feign.RequestTemplate; +import feign.codec.DefaultEncoder; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.form.FormEncoder; @@ -38,7 +39,7 @@ public class SpringFormEncoder extends FormEncoder { /** Constructor with the default Feign's encoder as a delegate. */ public SpringFormEncoder() { - this(new Encoder.Default()); + this(new DefaultEncoder()); } /** diff --git a/form/src/main/java/feign/form/FormEncoder.java b/form/src/main/java/feign/form/FormEncoder.java index d9959964bb..e01e24976c 100644 --- a/form/src/main/java/feign/form/FormEncoder.java +++ b/form/src/main/java/feign/form/FormEncoder.java @@ -22,6 +22,7 @@ import static lombok.AccessLevel.PRIVATE; import feign.RequestTemplate; +import feign.codec.DefaultEncoder; import feign.codec.EncodeException; import feign.codec.Encoder; import java.lang.reflect.Type; @@ -56,7 +57,7 @@ public class FormEncoder implements Encoder { /** Constructor with the default Feign's encoder as a delegate. */ public FormEncoder() { - this(new Encoder.Default()); + this(new DefaultEncoder()); } /** diff --git a/graphql/src/main/java/feign/graphql/GraphqlContract.java b/graphql/src/main/java/feign/graphql/GraphqlContract.java index 6f089e8555..98d1ae4217 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlContract.java +++ b/graphql/src/main/java/feign/graphql/GraphqlContract.java @@ -15,13 +15,13 @@ */ package feign.graphql; -import feign.Contract; +import feign.DefaultContract; import feign.Request.HttpMethod; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; -public class GraphqlContract extends Contract.Default { +public class GraphqlContract extends DefaultContract { private static final Pattern OPERATION_FIELD_PATTERN = Pattern.compile("\\{\\s*(\\w+)\\s*[({]", Pattern.DOTALL); diff --git a/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java b/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java index 82440460a7..6d5902d9c0 100644 --- a/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java +++ b/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java @@ -25,10 +25,10 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import feign.AsyncClient; import feign.AsyncFeign; import feign.Body; import feign.ChildPojo; +import feign.DefaultAsyncClient; import feign.Feign; import feign.Feign.ResponseMappingDecoder; import feign.FeignException; @@ -50,6 +50,9 @@ import feign.Util; import feign.codec.DecodeException; import feign.codec.Decoder; +import feign.codec.DefaultDecoder; +import feign.codec.DefaultEncoder; +import feign.codec.DefaultErrorDecoder; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.ErrorDecoder; @@ -158,7 +161,7 @@ void bodyTypeCorrespondsWithParameterType() throws Exception { final TestInterfaceAsync api = new TestInterfaceAsyncBuilder() .encoder( - new Encoder.Default() { + new DefaultEncoder() { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { encodedType.set(bodyType); @@ -578,7 +581,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { // fake client as Client.Default follows redirects. final TestInterfaceAsync api = AsyncFeign.builder() - .client(new AsyncClient.Default<>((_, _) -> response, execs)) + .client(new DefaultAsyncClient<>((_, _) -> response, execs)) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); assertThat(unwrap(api.response()).headers()) @@ -1050,7 +1053,7 @@ public void apply(RequestTemplate template) { } } - static class IllegalArgumentExceptionOn400 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn400 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -1061,7 +1064,7 @@ public Exception decode(String methodKey, Response response) { } } - static class IllegalArgumentExceptionOn404 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn404 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -1077,7 +1080,7 @@ static final class TestInterfaceAsyncBuilder { private final AsyncFeign.AsyncBuilder delegate = AsyncFeign.builder() .client(new AsyncApacheHttp5Client()) - .decoder(new Decoder.Default()) + .decoder(new DefaultDecoder()) .encoder( (object, _, template) -> { if (object instanceof Map) { diff --git a/hystrix/src/main/java/feign/hystrix/HystrixFeign.java b/hystrix/src/main/java/feign/hystrix/HystrixFeign.java index dee5cd2907..54d27a460f 100644 --- a/hystrix/src/main/java/feign/hystrix/HystrixFeign.java +++ b/hystrix/src/main/java/feign/hystrix/HystrixFeign.java @@ -18,6 +18,7 @@ import com.netflix.hystrix.HystrixCommand; import feign.Client; import feign.Contract; +import feign.DefaultContract; import feign.Feign; import feign.InvocationHandlerFactory; import feign.Logger; @@ -46,7 +47,7 @@ public static Builder builder() { public static final class Builder extends Feign.Builder { - private Contract contract = new Contract.Default(); + private Contract contract = new DefaultContract(); private SetterFactory setterFactory = new SetterFactory.Default(); /** Allows you to override hystrix properties such as thread pools and command keys. */ diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java index d0d00c3a36..0d3cd6570b 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java @@ -25,10 +25,10 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import feign.AsyncClient; import feign.AsyncFeign; import feign.Body; import feign.ChildPojo; +import feign.DefaultAsyncClient; import feign.Feign; import feign.Feign.ResponseMappingDecoder; import feign.FeignException; @@ -50,6 +50,9 @@ import feign.Util; import feign.codec.DecodeException; import feign.codec.Decoder; +import feign.codec.DefaultDecoder; +import feign.codec.DefaultEncoder; +import feign.codec.DefaultErrorDecoder; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.ErrorDecoder; @@ -166,7 +169,7 @@ void bodyTypeCorrespondsWithParameterType() throws Exception { final TestInterfaceAsync api = newAsyncBuilder() .encoder( - new Encoder.Default() { + new DefaultEncoder() { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { encodedType.set(bodyType); @@ -572,7 +575,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { // fake client as Client.Default follows redirects. final TestInterfaceAsync api = AsyncFeign.builder() - .client(new AsyncClient.Default<>((_, _) -> response, execs)) + .client(new DefaultAsyncClient<>((_, _) -> response, execs)) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); assertThat(unwrap(api.response()).headers().get("Location")).contains("http://bar.com"); @@ -702,7 +705,7 @@ void encodeLogicSupportsByteArray() throws Exception { final OtherTestInterfaceAsync api = newAsyncBuilder() - .encoder(new Encoder.Default()) + .encoder(new DefaultEncoder()) .target( new HardCodedTarget<>( OtherTestInterfaceAsync.class, "http://localhost:" + server.getPort())); @@ -994,7 +997,7 @@ public void apply(RequestTemplate template) { } } - static class IllegalArgumentExceptionOn400 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn400 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -1005,7 +1008,7 @@ public Exception decode(String methodKey, Response response) { } } - static class IllegalArgumentExceptionOn404 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn404 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -1021,7 +1024,7 @@ static final class TestInterfaceAsyncBuilder { private final AsyncFeign.AsyncBuilder delegate = AsyncFeign.builder() .client(new Http2Client()) - .decoder(new Decoder.Default()) + .decoder(new DefaultDecoder()) .encoder( (object, _, template) -> { if (object instanceof Map) { diff --git a/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java b/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java index 9f6c912a57..4027e1d149 100644 --- a/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java +++ b/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java @@ -19,7 +19,8 @@ import feign.AsyncContextSupplier; import feign.AsyncFeign; import feign.BaseBuilder; -import feign.Client; +import feign.DefaultAsyncClient; +import feign.DefaultClient; import feign.Experimental; import feign.MethodInfoResolver; import feign.Target; @@ -118,8 +119,8 @@ public static class CoroutineBuilder private AsyncContextSupplier defaultContextSupplier = () -> null; private AsyncClient client = - new AsyncClient.Default<>( - new Client.Default(null, null), LazyInitializedExecutorService.instance); + new DefaultAsyncClient<>( + new DefaultClient(null, null), LazyInitializedExecutorService.instance); private MethodInfoResolver methodInfoResolver = KotlinMethodInfo::createInstance; @Deprecated diff --git a/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt b/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt index d60b980f1f..011ee32ac2 100644 --- a/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt +++ b/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt @@ -24,6 +24,7 @@ import feign.RequestLine import feign.Response import feign.Util import feign.codec.Decoder +import feign.codec.DefaultDecoder import feign.codec.Encoder import feign.codec.ErrorDecoder import kotlinx.coroutines.runBlocking @@ -148,7 +149,7 @@ class CoroutineFeignTest { internal class TestInterfaceAsyncBuilder { private val delegate = CoroutineFeign.builder() - .decoder(Decoder.Default()).encoder { `object`, bodyType, template -> + .decoder(DefaultDecoder()).encoder { `object`, bodyType, template -> if (`object` is Map<*, *>) { template.body(Gson().toJson(`object`)) } else { diff --git a/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java b/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java index a4ff3a5485..79150b86b9 100644 --- a/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java +++ b/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java @@ -25,10 +25,10 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import feign.AsyncClient; import feign.AsyncFeign; import feign.Body; import feign.ChildPojo; +import feign.DefaultAsyncClient; import feign.Feign; import feign.Feign.ResponseMappingDecoder; import feign.FeignException; @@ -50,6 +50,9 @@ import feign.Util; import feign.codec.DecodeException; import feign.codec.Decoder; +import feign.codec.DefaultDecoder; +import feign.codec.DefaultEncoder; +import feign.codec.DefaultErrorDecoder; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.ErrorDecoder; @@ -165,7 +168,7 @@ void bodyTypeCorrespondsWithParameterType() throws Exception { final TestInterfaceAsync api = newAsyncBuilder() .encoder( - new Encoder.Default() { + new DefaultEncoder() { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { encodedType.set(bodyType); @@ -571,7 +574,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { // fake client as Client.Default follows redirects. final TestInterfaceAsync api = AsyncFeign.builder() - .client(new AsyncClient.Default<>((_, _) -> response, execs)) + .client(new DefaultAsyncClient<>((_, _) -> response, execs)) .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); assertThat(unwrap(api.response()).headers().get("Location")).contains("http://bar.com"); @@ -701,7 +704,7 @@ void encodeLogicSupportsByteArray() throws Exception { final OtherTestInterfaceAsync api = newAsyncBuilder() - .encoder(new Encoder.Default()) + .encoder(new DefaultEncoder()) .target( new HardCodedTarget<>( OtherTestInterfaceAsync.class, "http://localhost:" + server.getPort())); @@ -993,7 +996,7 @@ public void apply(RequestTemplate template) { } } - static class IllegalArgumentExceptionOn400 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn400 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -1004,7 +1007,7 @@ public Exception decode(String methodKey, Response response) { } } - static class IllegalArgumentExceptionOn404 extends ErrorDecoder.Default { + static class IllegalArgumentExceptionOn404 extends DefaultErrorDecoder { @Override public Exception decode(String methodKey, Response response) { @@ -1020,7 +1023,7 @@ static final class TestInterfaceAsyncBuilder { private final AsyncFeign.AsyncBuilder delegate = AsyncFeign.builder() .client(new OkHttpClient()) - .decoder(new Decoder.Default()) + .decoder(new DefaultDecoder()) .encoder( (object, _, template) -> { if (object instanceof Map) { diff --git a/reactive/src/main/java/feign/reactive/ReactiveFeign.java b/reactive/src/main/java/feign/reactive/ReactiveFeign.java index b7b6c24c9e..8518666aa6 100644 --- a/reactive/src/main/java/feign/reactive/ReactiveFeign.java +++ b/reactive/src/main/java/feign/reactive/ReactiveFeign.java @@ -16,13 +16,14 @@ package feign.reactive; import feign.Contract; +import feign.DefaultContract; import feign.Feign; abstract class ReactiveFeign { public static class Builder extends Feign.Builder { - private Contract contract = new Contract.Default(); + private Contract contract = new DefaultContract(); /** * Extend the current contract to support Reactive Stream return types. diff --git a/reactive/src/test/java/feign/reactive/ReactiveDelegatingContractTest.java b/reactive/src/test/java/feign/reactive/ReactiveDelegatingContractTest.java index d042a48cb7..f4bbd87d0a 100644 --- a/reactive/src/test/java/feign/reactive/ReactiveDelegatingContractTest.java +++ b/reactive/src/test/java/feign/reactive/ReactiveDelegatingContractTest.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import feign.Contract; +import feign.DefaultContract; import feign.Param; import feign.RequestLine; import io.reactivex.Flowable; @@ -33,20 +34,20 @@ void onlyReactiveReturnTypesSupported() { assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy( () -> { - Contract contract = new ReactiveDelegatingContract(new Contract.Default()); + Contract contract = new ReactiveDelegatingContract(new DefaultContract()); contract.parseAndValidateMetadata(TestSynchronousService.class); }); } @Test void reactorTypes() { - Contract contract = new ReactiveDelegatingContract(new Contract.Default()); + Contract contract = new ReactiveDelegatingContract(new DefaultContract()); contract.parseAndValidateMetadata(TestReactorService.class); } @Test void reactivexTypes() { - Contract contract = new ReactiveDelegatingContract(new Contract.Default()); + Contract contract = new ReactiveDelegatingContract(new DefaultContract()); contract.parseAndValidateMetadata(TestReactiveXService.class); } @@ -55,7 +56,7 @@ void streamsAreNotSupported() { assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy( () -> { - Contract contract = new ReactiveDelegatingContract(new Contract.Default()); + Contract contract = new ReactiveDelegatingContract(new DefaultContract()); contract.parseAndValidateMetadata(StreamsService.class); }); } diff --git a/reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java b/reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java index 7e583f0986..d268c4d01d 100644 --- a/reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java +++ b/reactive/src/test/java/feign/reactive/ReactiveFeignIntegrationTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.when; import feign.Client; +import feign.DefaultRetryer; import feign.FeignIgnore; import feign.Logger; import feign.Logger.Level; @@ -44,6 +45,7 @@ import feign.RetryableException; import feign.Retryer; import feign.codec.Decoder; +import feign.codec.DefaultDecoder; import feign.codec.ErrorDecoder; import feign.jackson.JacksonDecoder; import feign.jackson.JacksonEncoder; @@ -203,7 +205,7 @@ void requestInterceptor() { TestReactorService service = ReactorFeign.builder() .requestInterceptor(mockInterceptor) - .decoder(new ReactorDecoder(new Decoder.Default())) + .decoder(new ReactorDecoder(new DefaultDecoder())) .target(TestReactorService.class, this.getServerUrl()); StepVerifier.create(service.version()).expectNext("1.0").expectComplete().verify(); verify(mockInterceptor, times(1)).apply(any(RequestTemplate.class)); @@ -217,7 +219,7 @@ void requestInterceptors() { TestReactorService service = ReactorFeign.builder() .requestInterceptors(Arrays.asList(mockInterceptor, mockInterceptor)) - .decoder(new ReactorDecoder(new Decoder.Default())) + .decoder(new ReactorDecoder(new DefaultDecoder())) .target(TestReactorService.class, this.getServerUrl()); StepVerifier.create(service.version()).expectNext("1.0").expectComplete().verify(); verify(mockInterceptor, times(2)).apply(any(RequestTemplate.class)); @@ -251,7 +253,7 @@ void queryMapEncoders() { TestReactiveXService service = RxJavaFeign.builder() .queryMapEncoder(encoder) - .decoder(new RxJavaDecoder(new Decoder.Default())) + .decoder(new RxJavaDecoder(new DefaultDecoder())) .target(TestReactiveXService.class, this.getServerUrl()); StepVerifier.create(service.search(new SearchQuery())) .expectNext("No Results Found") @@ -286,13 +288,13 @@ void retryer() { this.webServer.enqueue(new MockResponse().setBody("Not Available").setResponseCode(-1)); this.webServer.enqueue(new MockResponse().setBody("1.0")); - Retryer retryer = new Retryer.Default(); + Retryer retryer = new DefaultRetryer(); Retryer spy = spy(retryer); when(spy.clone()).thenReturn(spy); TestReactorService service = ReactorFeign.builder() .retryer(spy) - .decoder(new ReactorDecoder(new Decoder.Default())) + .decoder(new ReactorDecoder(new DefaultDecoder())) .target(TestReactorService.class, this.getServerUrl()); StepVerifier.create(service.version()).expectNext("1.0").expectComplete().verify(); verify(spy, times(1)).continueOrPropagate(any(RetryableException.class)); @@ -315,7 +317,7 @@ void client() throws Exception { TestReactorService service = ReactorFeign.builder() .client(client) - .decoder(new ReactorDecoder(new Decoder.Default())) + .decoder(new ReactorDecoder(new DefaultDecoder())) .target(TestReactorService.class, this.getServerUrl()); StepVerifier.create(service.version()).expectNext("1.0").expectComplete().verify(); verify(client, times(1)).execute(any(Request.class), any(Options.class)); @@ -328,7 +330,7 @@ void differentContract() throws Exception { TestJaxRSReactorService service = ReactorFeign.builder() .contract(new JAXRSContract()) - .decoder(new ReactorDecoder(new Decoder.Default())) + .decoder(new ReactorDecoder(new DefaultDecoder())) .target(TestJaxRSReactorService.class, this.getServerUrl()); StepVerifier.create(service.version()).expectNext("1.0").expectComplete().verify(); assertThat(webServer.takeRequest().getPath()).isEqualToIgnoringCase("/version"); diff --git a/ribbon/src/main/java/feign/ribbon/RibbonClient.java b/ribbon/src/main/java/feign/ribbon/RibbonClient.java index bae03c4bfd..c9a8e93899 100644 --- a/ribbon/src/main/java/feign/ribbon/RibbonClient.java +++ b/ribbon/src/main/java/feign/ribbon/RibbonClient.java @@ -19,6 +19,7 @@ import com.netflix.client.config.CommonClientConfigKey; import com.netflix.client.config.DefaultClientConfigImpl; import feign.Client; +import feign.DefaultClient; import feign.Request; import feign.Response; import java.io.IOException; @@ -54,7 +55,7 @@ public static Builder builder() { */ @Deprecated public RibbonClient() { - this(new Client.Default(null, null)); + this(new DefaultClient(null, null)); } /** @@ -138,7 +139,7 @@ public Builder lbClientFactory(LBClientFactory lbClientFactory) { public RibbonClient build() { return new RibbonClient( - delegate != null ? delegate : new Client.Default(null, null), + delegate != null ? delegate : new DefaultClient(null, null), lbClientFactory != null ? lbClientFactory : new LBClientFactory.Default()); } } diff --git a/ribbon/src/test/java/feign/ribbon/RibbonClientTest.java b/ribbon/src/test/java/feign/ribbon/RibbonClientTest.java index eefe1d5d20..3abc4cde0f 100644 --- a/ribbon/src/test/java/feign/ribbon/RibbonClientTest.java +++ b/ribbon/src/test/java/feign/ribbon/RibbonClientTest.java @@ -22,6 +22,7 @@ import com.netflix.client.config.CommonClientConfigKey; import com.netflix.client.config.IClientConfig; import feign.Client; +import feign.DefaultClient; import feign.Feign; import feign.Param; import feign.Request; @@ -243,7 +244,7 @@ void urlEncodeQueryStringParameters() throws IOException, InterruptedException { @Test void hTTPSViaRibbon() { - Client trustSSLSockets = new Client.Default(TrustingSSLSocketFactory.get(), null); + Client trustSSLSockets = new DefaultClient(TrustingSSLSocketFactory.get(), null); server1.useHttps(TrustingSSLSocketFactory.get("localhost"), false); server1.enqueue(new MockResponse().setBody("success!")); diff --git a/soap-jakarta/src/main/java/feign/soap/SOAPErrorDecoder.java b/soap-jakarta/src/main/java/feign/soap/SOAPErrorDecoder.java index b54da6365c..ce2210f30c 100644 --- a/soap-jakarta/src/main/java/feign/soap/SOAPErrorDecoder.java +++ b/soap-jakarta/src/main/java/feign/soap/SOAPErrorDecoder.java @@ -16,6 +16,7 @@ package feign.soap; import feign.Response; +import feign.codec.DefaultErrorDecoder; import feign.codec.ErrorDecoder; import jakarta.xml.soap.*; import jakarta.xml.ws.soap.SOAPFaultException; @@ -69,6 +70,6 @@ public Exception decode(String methodKey, Response response) { } private Exception defaultErrorDecoder(String methodKey, Response response) { - return new ErrorDecoder.Default().decode(methodKey, response); + return new DefaultErrorDecoder().decode(methodKey, response); } } diff --git a/soap/src/main/java/feign/soap/SOAPErrorDecoder.java b/soap/src/main/java/feign/soap/SOAPErrorDecoder.java index fa08a089b4..74f64061ba 100644 --- a/soap/src/main/java/feign/soap/SOAPErrorDecoder.java +++ b/soap/src/main/java/feign/soap/SOAPErrorDecoder.java @@ -16,6 +16,7 @@ package feign.soap; import feign.Response; +import feign.codec.DefaultErrorDecoder; import feign.codec.ErrorDecoder; import java.io.IOException; import javax.xml.soap.MessageFactory; @@ -73,6 +74,6 @@ public Exception decode(String methodKey, Response response) { } private Exception defaultErrorDecoder(String methodKey, Response response) { - return new ErrorDecoder.Default().decode(methodKey, response); + return new DefaultErrorDecoder().decode(methodKey, response); } } diff --git a/vertx/feign-vertx/src/main/java/feign/VertxFeign.java b/vertx/feign-vertx/src/main/java/feign/VertxFeign.java index e03e6e26a4..09a6264ebe 100644 --- a/vertx/feign-vertx/src/main/java/feign/VertxFeign.java +++ b/vertx/feign-vertx/src/main/java/feign/VertxFeign.java @@ -20,6 +20,9 @@ import feign.InvocationHandlerFactory.MethodHandler; import feign.codec.Decoder; +import feign.codec.DefaultDecoder; +import feign.codec.DefaultEncoder; +import feign.codec.DefaultErrorDecoder; import feign.codec.Encoder; import feign.codec.ErrorDecoder; import feign.querymap.FieldQueryMapEncoder; @@ -94,14 +97,14 @@ public static final class Builder extends Feign.Builder { private WebClient webClient; private final List requestInterceptors = new ArrayList<>(); private Logger.Level logLevel = Logger.Level.NONE; - private Contract contract = new VertxDelegatingContract(new Contract.Default()); - private Retryer retryer = new Retryer.Default(); + private Contract contract = new VertxDelegatingContract(new DefaultContract()); + private Retryer retryer = new DefaultRetryer(); private Logger logger = new Logger.NoOpLogger(); - private Encoder encoder = new Encoder.Default(); - private Decoder decoder = new Decoder.Default(); + private Encoder encoder = new DefaultEncoder(); + private Decoder decoder = new DefaultDecoder(); private QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder(); private List capabilities = new ArrayList<>(); - private ErrorDecoder errorDecoder = new ErrorDecoder.Default(); + private ErrorDecoder errorDecoder = new DefaultErrorDecoder(); private long timeout = -1; private boolean decode404; private UnaryOperator> requestPreProcessor = UnaryOperator.identity(); diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java index c5ce7cba3b..b294d99363 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java @@ -22,9 +22,9 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.Assertions.assertThat; +import feign.DefaultRetryer; import feign.Logger; import feign.RetryableException; -import feign.Retryer; import feign.VertxFeign; import feign.jackson.JacksonDecoder; import feign.slf4j.Slf4jLogger; @@ -50,7 +50,7 @@ static void createClient(Vertx vertx) { VertxFeign.builder() .webClient(WebClient.create(vertx)) .decoder(new JacksonDecoder(MAPPER)) - .retryer(new Retryer.Default(100, SECONDS.toMillis(1), 5)) + .retryer(new DefaultRetryer(100, SECONDS.toMillis(1), 5)) .logger(new Slf4jLogger()) .logLevel(Logger.Level.FULL) .target(IcecreamServiceApi.class, wireMock.baseUrl()); diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java index c5ce7cba3b..b294d99363 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java @@ -22,9 +22,9 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.Assertions.assertThat; +import feign.DefaultRetryer; import feign.Logger; import feign.RetryableException; -import feign.Retryer; import feign.VertxFeign; import feign.jackson.JacksonDecoder; import feign.slf4j.Slf4jLogger; @@ -50,7 +50,7 @@ static void createClient(Vertx vertx) { VertxFeign.builder() .webClient(WebClient.create(vertx)) .decoder(new JacksonDecoder(MAPPER)) - .retryer(new Retryer.Default(100, SECONDS.toMillis(1), 5)) + .retryer(new DefaultRetryer(100, SECONDS.toMillis(1), 5)) .logger(new Slf4jLogger()) .logLevel(Logger.Level.FULL) .target(IcecreamServiceApi.class, wireMock.baseUrl()); From 4453fce45b2052f66d523e8f86fc4f4c80a35597 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 05:23:41 +0000 Subject: [PATCH 400/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.27.1 to 3.28.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.27.1...v3.28.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.28.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9fd9c9ff1b..c3bf5fbbb2 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 4.0.0 6.29.0 3.27.0 - 3.27.1 + 3.28.0 1.0 From 814def15e096f5b92f1a4ffcb533a0df5364ddb7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 05:25:00 +0000 Subject: [PATCH 401/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.29.0 to 6.30.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.29.0...v6.30.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.30.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9fd9c9ff1b..d99c688c35 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 3.2.0 1.2.8 4.0.0 - 6.29.0 + 6.30.0 3.27.0 3.27.1 1.0 From b6381680c3404105f5187403a7a884b731f9fec9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 05:36:26 +0000 Subject: [PATCH 402/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.27.0 to 3.28.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.27.0...v3.28.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.28.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e5afadf972..a001d6327b 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 1.2.8 4.0.0 6.30.0 - 3.27.0 + 3.28.0 3.28.0 1.0 From 96830ba5fe4059bb05694704d04bc3b291fd4d17 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Thu, 26 Feb 2026 06:15:02 -0300 Subject: [PATCH 403/615] Ignore m2e-target Signed-off-by: Marvin Froeder --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index a001d6327b..d8abe8f30c 100644 --- a/pom.xml +++ b/pom.xml @@ -738,6 +738,7 @@ etc/header.txt **/.idea/** **/target/** + **/m2e-target/** **/scripts/** **/src/config/** **/codequality/** From 6cfad7760ec5064de0f117ed9b4c40c124c133bd Mon Sep 17 00:00:00 2001 From: Marvin Date: Thu, 26 Feb 2026 06:54:25 -0300 Subject: [PATCH 404/615] Add japicmp-maven-plugin for API compatibility checks (#3244) Signed-off-by: Marvin Froeder --- apt-test-generator/pom.xml | 91 +------------------ core/src/main/java/feign/Client.java | 2 +- .../java/feign/graphql/GraphqlContract.java | 2 + .../java/feign/graphql/GraphqlDecoder.java | 2 + .../java/feign/graphql/GraphqlEncoder.java | 2 + .../feign/graphql/GraphqlErrorException.java | 2 + .../main/java/feign/graphql/GraphqlQuery.java | 2 + .../java/feign/graphql/GraphqlSchema.java | 2 + .../src/main/java/feign/graphql/Scalar.java | 2 + pom.xml | 33 +++++++ 10 files changed, 49 insertions(+), 91 deletions(-) diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index dd6cb51502..ef73b59fc3 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -33,6 +33,7 @@ 17 true + true @@ -82,63 +83,7 @@ - - - docker - true - - ${project.basedir}/docker - - - - ${basedir}/src/main/resources - - - src/main/java - - **/*.java - - - - - - org.apache.maven.plugins - maven-shade-plugin - ${maven-shade-plugin.version} - - - - shade - - package - - - - feign.aptgenerator.github.GitHubFactoryExample - - - false - - - - - - org.skife.maven - really-executable-jar-maven-plugin - ${really-executable-jar-maven-plugin.version} - - github - - - - - really-executable-jar - - package - - - org.apache.maven.plugins maven-failsafe-plugin @@ -152,40 +97,6 @@ - - - com.spotify - docker-maven-plugin - ${docker-maven-plugin.version} - - - ${project.build.directory}/classes/docker/ - - - true - - docker-hub - https://index.docker.io/v1/ - feign-apt-generator/test - - - / - ${project.build.directory} - ${project.artifactId}-${project.version}.jar - - - - - - - - build - - post-integration-test - - - - org.apache.maven.plugins maven-surefire-plugin diff --git a/core/src/main/java/feign/Client.java b/core/src/main/java/feign/Client.java index 939f305a61..acaf75bb55 100644 --- a/core/src/main/java/feign/Client.java +++ b/core/src/main/java/feign/Client.java @@ -61,7 +61,7 @@ public Default( } /** Client that supports a {@link java.net.Proxy}. */ - class Proxied extends DefaultClient { + class Proxied extends Default { public static final String PROXY_AUTHORIZATION = "Proxy-Authorization"; private final Proxy proxy; diff --git a/graphql/src/main/java/feign/graphql/GraphqlContract.java b/graphql/src/main/java/feign/graphql/GraphqlContract.java index 98d1ae4217..3a84bf40e4 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlContract.java +++ b/graphql/src/main/java/feign/graphql/GraphqlContract.java @@ -16,11 +16,13 @@ package feign.graphql; import feign.DefaultContract; +import feign.Experimental; import feign.Request.HttpMethod; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; +@Experimental public class GraphqlContract extends DefaultContract { private static final Pattern OPERATION_FIELD_PATTERN = diff --git a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java index 4a430a80e5..8adc726957 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java @@ -15,6 +15,7 @@ */ package feign.graphql; +import feign.Experimental; import feign.Response; import feign.Util; import feign.codec.Decoder; @@ -27,6 +28,7 @@ import java.util.Map; import java.util.Optional; +@Experimental public class GraphqlDecoder implements Decoder { private final JsonDecoder jsonDecoder; diff --git a/graphql/src/main/java/feign/graphql/GraphqlEncoder.java b/graphql/src/main/java/feign/graphql/GraphqlEncoder.java index 391d8a5678..9a87426734 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlEncoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlEncoder.java @@ -15,6 +15,7 @@ */ package feign.graphql; +import feign.Experimental; import feign.RequestInterceptor; import feign.RequestTemplate; import feign.codec.EncodeException; @@ -23,6 +24,7 @@ import java.util.LinkedHashMap; import java.util.Map; +@Experimental public class GraphqlEncoder implements Encoder, RequestInterceptor { private final Encoder delegate; diff --git a/graphql/src/main/java/feign/graphql/GraphqlErrorException.java b/graphql/src/main/java/feign/graphql/GraphqlErrorException.java index 942b96fed7..0c66a8ece4 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlErrorException.java +++ b/graphql/src/main/java/feign/graphql/GraphqlErrorException.java @@ -15,9 +15,11 @@ */ package feign.graphql; +import feign.Experimental; import feign.FeignException; import feign.Request; +@Experimental public class GraphqlErrorException extends FeignException { private final String operation; diff --git a/graphql/src/main/java/feign/graphql/GraphqlQuery.java b/graphql/src/main/java/feign/graphql/GraphqlQuery.java index beef534899..b02987e34b 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlQuery.java +++ b/graphql/src/main/java/feign/graphql/GraphqlQuery.java @@ -15,11 +15,13 @@ */ package feign.graphql; +import feign.Experimental; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +@Experimental @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface GraphqlQuery { diff --git a/graphql/src/main/java/feign/graphql/GraphqlSchema.java b/graphql/src/main/java/feign/graphql/GraphqlSchema.java index 785bdf19c2..695ae21ff2 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlSchema.java +++ b/graphql/src/main/java/feign/graphql/GraphqlSchema.java @@ -15,11 +15,13 @@ */ package feign.graphql; +import feign.Experimental; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +@Experimental @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface GraphqlSchema { diff --git a/graphql/src/main/java/feign/graphql/Scalar.java b/graphql/src/main/java/feign/graphql/Scalar.java index 1a9ba21e5d..4fb9c5a777 100644 --- a/graphql/src/main/java/feign/graphql/Scalar.java +++ b/graphql/src/main/java/feign/graphql/Scalar.java @@ -15,11 +15,13 @@ */ package feign.graphql; +import feign.Experimental; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +@Experimental @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Scalar { diff --git a/pom.xml b/pom.xml index d8abe8f30c..b2ce324de2 100644 --- a/pom.xml +++ b/pom.xml @@ -204,6 +204,7 @@ 6.30.0 3.28.0 3.28.0 + 0.25.4 1.0 @@ -924,6 +925,38 @@ + + com.github.siom79.japicmp + japicmp-maven-plugin + ${japicmp-maven-plugin.version} + + + true + true + true + true + true + true + + feign-example-.* + feign-benchmark + + + @feign.Experimental + feign.graphql + + public + + + + + + cmp + + verify + + + From 1acb3ce2ce43b626c3a76cc081e12651719f9764 Mon Sep 17 00:00:00 2001 From: Marvin Date: Thu, 26 Feb 2026 07:12:00 -0300 Subject: [PATCH 405/615] Remove feign-example-github dependency from apt-test-generator to fix deploy (#3246) Signed-off-by: Marvin Froeder --- apt-test-generator/pom.xml | 8 +- .../GenerateTestStubAPTTest.java | 6 +- .../example/github/GitHubExample.java | 149 ++++++++++++++++++ .../example/github/GitHubStub.java | 0 4 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 apt-test-generator/src/test/resources/example/github/GitHubExample.java rename apt-test-generator/src/test/{java => resources}/example/github/GitHubStub.java (100%) diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index ef73b59fc3..d5a62da711 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -45,7 +45,13 @@ io.github.openfeign - feign-example-github + feign-core + ${project.version} + test + + + io.github.openfeign + feign-gson ${project.version} test diff --git a/apt-test-generator/src/test/java/feign/apttestgenerator/GenerateTestStubAPTTest.java b/apt-test-generator/src/test/java/feign/apttestgenerator/GenerateTestStubAPTTest.java index c31990e5ed..8a635fa994 100644 --- a/apt-test-generator/src/test/java/feign/apttestgenerator/GenerateTestStubAPTTest.java +++ b/apt-test-generator/src/test/java/feign/apttestgenerator/GenerateTestStubAPTTest.java @@ -26,7 +26,7 @@ /** Test for {@link GenerateTestStubAPT} */ class GenerateTestStubAPTTest { - private final File main = new File("../example-github/src/main/java/").getAbsoluteFile(); + private final File resources = new File("src/test/resources/").getAbsoluteFile(); @Test void test() throws Exception { @@ -35,12 +35,12 @@ void test() throws Exception { .withProcessors(new GenerateTestStubAPT()) .compile( JavaFileObjects.forResource( - new File(main, "example/github/GitHubExample.java").toURI().toURL())); + new File(resources, "example/github/GitHubExample.java").toURI().toURL())); assertThat(compilation).succeeded(); assertThat(compilation) .generatedSourceFile("example.github.GitHubStub") .hasSourceEquivalentTo( JavaFileObjects.forResource( - new File("src/test/java/example/github/GitHubStub.java").toURI().toURL())); + new File(resources, "example/github/GitHubStub.java").toURI().toURL())); } } diff --git a/apt-test-generator/src/test/resources/example/github/GitHubExample.java b/apt-test-generator/src/test/resources/example/github/GitHubExample.java new file mode 100644 index 0000000000..ecb7368b04 --- /dev/null +++ b/apt-test-generator/src/test/resources/example/github/GitHubExample.java @@ -0,0 +1,149 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.github; + +import feign.*; +import feign.codec.Decoder; +import feign.codec.DefaultErrorDecoder; +import feign.codec.Encoder; +import feign.codec.ErrorDecoder; +import feign.gson.GsonDecoder; +import feign.gson.GsonEncoder; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** Inspired by {@code com.example.retrofit.GitHubClient} */ +public class GitHubExample { + + public interface GitHub { + + public class Repository { + String name; + } + + public class Contributor { + String login; + } + + public class Issue { + + Issue() {} + + String title; + String body; + List assignees; + int milestone; + List labels; + } + + @RequestLine("GET /users/{username}/repos?sort=full_name") + List repos(@Param("username") String owner); + + @RequestLine("GET /repos/{owner}/{repo}/contributors") + List contributors(@Param("owner") String owner, @Param("repo") String repo); + + @RequestLine("POST /repos/{owner}/{repo}/issues") + void createIssue(Issue issue, @Param("owner") String owner, @Param("repo") String repo); + + /** Lists all contributors for all repos owned by a user. */ + default List contributors(String owner) { + return repos(owner).stream() + .flatMap(repo -> contributors(owner, repo.name).stream()) + .map(c -> c.login) + .distinct() + .collect(Collectors.toList()); + } + + static GitHub connect() { + final Decoder decoder = new GsonDecoder(); + final Encoder encoder = new GsonEncoder(); + return Feign.builder() + .encoder(encoder) + .decoder(decoder) + .errorDecoder(new GitHubErrorDecoder(decoder)) + .logger(new Logger.ErrorLogger()) + .logLevel(Logger.Level.BASIC) + .requestInterceptor( + template -> { + template.header( + // not available when building PRs... + // https://docs.travis-ci.com/user/environment-variables/#defining-encrypted-variables-in-travisyml + "Authorization", "token 383f1c1b474d8f05a21e7964976ab0d403fee071"); + }) + .options(new Request.Options(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true)) + .target(GitHub.class, "https://api.github.com"); + } + } + + static class GitHubClientError extends RuntimeException { + private String message; // parsed from json + + @Override + public String getMessage() { + return message; + } + } + + public static void main(String... args) { + final GitHub github = GitHub.connect(); + + System.out.println("Let's fetch and print a list of the contributors to this org."); + final List contributors = github.contributors("openfeign"); + for (final String contributor : contributors) { + System.out.println(contributor); + } + + System.out.println("Now, let's cause an error."); + try { + github.contributors("openfeign", "some-unknown-project"); + } catch (final GitHubClientError e) { + System.out.println(e.getMessage()); + } + + System.out.println("Now, try to create an issue - which will also cause an error."); + try { + final GitHub.Issue issue = new GitHub.Issue(); + issue.title = "The title"; + issue.body = "Some Text"; + github.createIssue(issue, "OpenFeign", "SomeRepo"); + } catch (final GitHubClientError e) { + System.out.println(e.getMessage()); + } + } + + static class GitHubErrorDecoder implements ErrorDecoder { + + final Decoder decoder; + final ErrorDecoder defaultDecoder = new DefaultErrorDecoder(); + + GitHubErrorDecoder(Decoder decoder) { + this.decoder = decoder; + } + + @Override + public Exception decode(String methodKey, Response response) { + try { + // must replace status by 200 other GSONDecoder returns null + response = response.toBuilder().status(200).build(); + return (Exception) decoder.decode(response, GitHubClientError.class); + } catch (final IOException fallbackToDefault) { + return defaultDecoder.decode(methodKey, response); + } + } + } +} diff --git a/apt-test-generator/src/test/java/example/github/GitHubStub.java b/apt-test-generator/src/test/resources/example/github/GitHubStub.java similarity index 100% rename from apt-test-generator/src/test/java/example/github/GitHubStub.java rename to apt-test-generator/src/test/resources/example/github/GitHubStub.java From 9ce8200794d70bc0a69e023d679b0c86d4346d44 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Thu, 26 Feb 2026 07:52:56 -0300 Subject: [PATCH 406/615] prepare release 13.9.1 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 2d8f3c26f7..98e429a9ab 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index d5a62da711..644a4a6159 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index dde47f4b40..3977df0b03 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index d653233e6f..761c0028e6 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 7155c1d438..c6b29a7583 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 6880e543ed..9ac4add12e 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 63cb280898..279a0c7fa9 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 577e429644..02204cc0aa 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index d2f2b27e78..e6a69e57e2 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 10085b77e1..97485c3942 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 10b8365c0d..a7586af3ad 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index f6b94cbb21..fa275e102c 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index d839964803..0a47ea4a96 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 55a72207f7..870cf0423e 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index e8f23c2232..4b0754a659 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index f5f770103a..fe13a3c042 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index 20cbe814d1..3019dd3125 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 00b1e67d35..19a7fc701b 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 3d7321f28b..40363d4071 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 085e5d36ce..96263691ce 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 0eb2b99863..b8f82a4308 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index e37e24df14..fa13a5ba73 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 28da8e722a..9a8d53a2ae 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 398f3391ff..3c45b34e8e 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 3864ca1c61..6ff9207ee0 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 47300b18ab..7fb368145d 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 3987b7fe82..df6883bdf8 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index d5e6e68257..999d96175f 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 3f827cb095..5ad4221d22 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index e121974e9f..f50b679483 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 7ed79f6943..422160782e 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 9dc9b921b0..f053325ffc 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index ab0112f806..51e1f61688 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 7f0c7317ad..f036c27e8b 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 7b2b677b24..29ca9af97a 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 6ecf4f3da2..45d425caa2 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 2245c7583a..ee79459977 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 3a092d194c..834fc67037 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-okhttp diff --git a/pom.xml b/pom.xml index b2ce324de2..2b4054d303 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index ee1e2add7c..ca0483534e 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 2b5cb5b1d6..6e379de234 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 66ed6c90c3..8f2be83d41 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 673ee625d0..c29b8529d4 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 39cf7266d1..dae0a971a1 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 14208a1579..04d077f442 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 8856f0fde3..086649fe60 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index d3abe020bc..83c5aae1a6 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 1ca081213e..cb7fb73d76 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.9.1 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 3d5bb5d8b3..de2f9c5978 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.9.1 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 0625cfeae9..e8bc934624 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.9.1 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 87a914f193..32646b5a2f 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.1 feign-vertx-parent From f0873f4604b58e4925e9dd92d5ef25fcf354c6fd Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Thu, 26 Feb 2026 07:53:13 -0300 Subject: [PATCH 407/615] [ci skip] updating versions to next development iteration 13.10-SNAPSHOT --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 98e429a9ab..2d8f3c26f7 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index 644a4a6159..d5a62da711 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 3977df0b03..dde47f4b40 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 761c0028e6..d653233e6f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index c6b29a7583..7155c1d438 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 9ac4add12e..6880e543ed 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 279a0c7fa9..63cb280898 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 02204cc0aa..577e429644 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index e6a69e57e2..d2f2b27e78 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 97485c3942..10085b77e1 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index a7586af3ad..10b8365c0d 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index fa275e102c..f6b94cbb21 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 0a47ea4a96..d839964803 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 870cf0423e..55a72207f7 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index 4b0754a659..e8f23c2232 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index fe13a3c042..f5f770103a 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index 3019dd3125..20cbe814d1 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 19a7fc701b..00b1e67d35 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 40363d4071..3d7321f28b 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 96263691ce..085e5d36ce 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index b8f82a4308..0eb2b99863 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index fa13a5ba73..e37e24df14 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 9a8d53a2ae..28da8e722a 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 3c45b34e8e..398f3391ff 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 6ff9207ee0..3864ca1c61 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 7fb368145d..47300b18ab 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index df6883bdf8..3987b7fe82 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 999d96175f..d5e6e68257 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 5ad4221d22..3f827cb095 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index f50b679483..e121974e9f 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 422160782e..7ed79f6943 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index f053325ffc..9dc9b921b0 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 51e1f61688..ab0112f806 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index f036c27e8b..7f0c7317ad 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 29ca9af97a..7b2b677b24 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 45d425caa2..6ecf4f3da2 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index ee79459977..2245c7583a 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 834fc67037..3a092d194c 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index 2b4054d303..b2ce324de2 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index ca0483534e..ee1e2add7c 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 6e379de234..2b5cb5b1d6 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 8f2be83d41..66ed6c90c3 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index c29b8529d4..673ee625d0 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index dae0a971a1..39cf7266d1 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 04d077f442..14208a1579 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 086649fe60..8856f0fde3 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 83c5aae1a6..d3abe020bc 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index cb7fb73d76..1ca081213e 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9.1 + 13.10-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index de2f9c5978..3d5bb5d8b3 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9.1 + 13.10-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index e8bc934624..0625cfeae9 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9.1 + 13.10-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 32646b5a2f..87a914f193 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.1 + 13.10-SNAPSHOT feign-vertx-parent From a2d48a9fce05c8bfe44698fe474a7e22a31b6e71 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Thu, 26 Feb 2026 07:54:22 -0300 Subject: [PATCH 408/615] Allow passing release and snapshot versions as arguments to release.sh Signed-off-by: Marvin Froeder --- scripts/release.sh | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/scripts/release.sh b/scripts/release.sh index 9871d2faf4..7fb51e3cc8 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -19,17 +19,27 @@ function increment() { echo "${result}-SNAPSHOT" } -# extract the release version from the pom file -version=`./mvnw -B help:evaluate -N -Dexpression=project.version | sed -n '/^[0-9]/p'` -tag=`echo ${version} | cut -d'-' -f 1` - -# determine the next snapshot version -snapshot=$(increment ${tag}) +if [ -n "$1" ]; then + tag=$1 + if [ -n "$2" ]; then + snapshot=$2 + else + snapshot=$(increment ${tag}) + fi +else + # extract the release version from the pom file + version=`./mvnw -B help:evaluate -N -Dexpression=project.version | sed -n '/^[0-9]/p'` + tag=`echo ${version} | cut -d'-' -f 1` + snapshot=$(increment ${tag}) +fi echo "release version is: ${tag} and next snapshot is: ${snapshot}" # Update the versions, removing the snapshots, then create a new tag for the release, this will # start the travis-ci release process. +if [ -n "$1" ]; then + ./mvnw -B versions:set -DnewVersion="${tag}" -DgenerateBackupPoms=false +fi ./mvnw -B versions:set license:format scm:checkin -DremoveSnapshot -DgenerateBackupPoms=false -Dmessage="prepare release ${tag}" -DpushChanges=false # tag the release From 5fac965440c0b2f3a1f06ac2a0cbf3132c1ee4bf Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Thu, 26 Feb 2026 07:56:11 -0300 Subject: [PATCH 409/615] Document release process in AGENTS.md Signed-off-by: Marvin Froeder --- AGENTS.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 23a8257c03..016f882190 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -123,6 +123,36 @@ Some modules define the same Maven property name (e.g., `jersey.version`, `vertx 2. Add a per-directory entry for the new module with `allow` for the specific dependency and `ignore` for `version-update:semver-major` 3. Verify existing modules with the same property also have their own per-directory entries +## Releasing + +The release script is at `scripts/release.sh`. It handles version updates, tagging, and pushing. + +### Usage +- `./scripts/release.sh` — auto-detect release version from pom (strips `-SNAPSHOT`), auto-compute next snapshot +- `./scripts/release.sh ` — release a specific version, auto-compute next snapshot +- `./scripts/release.sh ` — release a specific version with explicit next snapshot + +### Examples +```bash +# Standard release (pom is at 13.10-SNAPSHOT, releases 13.10, next becomes 13.11-SNAPSHOT) +./scripts/release.sh + +# Patch release with custom next snapshot +./scripts/release.sh 13.9.1 13.10-SNAPSHOT +``` + +### What the script does +1. Sets pom versions to the release version (removes `-SNAPSHOT`) +2. Formats license headers and commits locally (no push) +3. Creates and pushes a git tag for the release version +4. Sets pom versions to the next snapshot and commits/pushes + +### Patch releases +When doing a patch release (e.g., 13.9.1 while pom is at 13.10-SNAPSHOT), pass both arguments so the next snapshot returns to the current development version: +```bash +./scripts/release.sh 13.9.1 13.10-SNAPSHOT +``` + ## Documentation Requirements - New modules must include a `README.md` with usage examples following the style of existing module READMEs (e.g., `jackson/README.md`, `graphql/README.md`) From 05d78975439ce1d0e1d1929b842d9f7af7f4f628 Mon Sep 17 00:00:00 2001 From: Marvin Date: Fri, 27 Feb 2026 08:30:55 -0300 Subject: [PATCH 410/615] Generate nested result types as inner records in graphql-apt (#3247) * Generate nested result types as inner records in graphql-apt Signed-off-by: Marvin Froeder * Improve conflict error: show field selections and both method names Signed-off-by: Marvin Froeder * Update README with improved conflict error message format Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder --- graphql-apt/README.md | 70 +++- .../java/feign/graphql/apt/TypeGenerator.java | 188 ++++++++-- .../apt/GraphqlSchemaProcessorTest.java | 334 +++++++++++++----- .../test/resources/scalar-test-schema.graphql | 6 +- .../src/test/resources/test-schema.graphql | 144 ++++---- 5 files changed, 544 insertions(+), 198 deletions(-) diff --git a/graphql-apt/README.md b/graphql-apt/README.md index db67c2418a..cc6935233b 100644 --- a/graphql-apt/README.md +++ b/graphql-apt/README.md @@ -14,32 +14,74 @@ See the [feign-graphql README](../graphql/README.md) for usage examples. ## Generated Output -For a schema type like: +### Result types with inner records + +Nested result types are generated as inner records scoped to each query result. This ensures each query gets exactly the fields it selects, even when different queries target the same GraphQL type. + +For a query like: ```graphql -type User { - id: ID! - name: String! - email: String - status: Status! +{ + starship(id: "1") { + id name + location { planet sector } + specs { lengthMeters classification } + } } +``` + +The processor generates a single file with inner records: + +```java +public record StarshipResult(String id, String name, Location location, Specs specs) { + + public record Location(String planet, String sector) {} + + public record Specs(Integer lengthMeters, String classification) {} -enum Status { - ACTIVE - INACTIVE } ``` -The processor generates: +Two different queries can select different fields from the same GraphQL type without conflict: + +```java +// Query 1: selects location { planet } +public record CharByPlanet(String id, Location location) { + public record Location(String planet) {} +} + +// Query 2: selects location { sector region } +public record CharByRegion(String id, Location location) { + public record Location(String sector, String region) {} +} +``` + +### Conflicting return type error + +If two queries use the same return type name but select different fields, the processor reports compilation errors on both methods showing which fields each selects: + +``` +error: Conflicting return type 'CharResult': method selects [id, email] but method 'query1()' already selects [id, name] + CharResult query2(); + ^ +error: Conflicting return type 'CharResult': method selects [id, name] but method 'query2()' selects [id, email] + CharResult query1(); + ^ +``` + +### Input types and enums + +Input types and enums are generated as top-level files since they represent the full schema type: ```java -public record User(String id, String name, String email, Status status) {} +public record CreateCharacterInput(String name, String email, Episode appearsIn) {} ``` ```java -public enum Status { - ACTIVE, - INACTIVE +public enum Episode { + NEWHOPE, + EMPIRE, + JEDI } ``` diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java index 3b70e8480f..ce30adff65 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java @@ -34,8 +34,10 @@ import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.TreeSet; @@ -56,6 +58,7 @@ public class TypeGenerator { private final String targetPackage; private final Set generatedTypes = new HashSet<>(); private final Queue pendingTypes = new ArrayDeque<>(); + private final Map resultTypeSignatures = new HashMap<>(); public TypeGenerator( Filer filer, @@ -75,20 +78,60 @@ public void generateResultType( SelectionSet selectionSet, ObjectTypeDefinition parentType, Element element) { - if (generatedTypes.contains(className)) { + var signature = canonicalize(selectionSet); + var fields = describeFields(selectionSet); + var existing = resultTypeSignatures.get(className); + if (existing != null) { + if (!existing.signature.equals(signature)) { + messager.printMessage( + Diagnostic.Kind.ERROR, + "Conflicting return type '" + + className + + "': method selects [" + + fields + + "] but method '" + + existing.element.getSimpleName() + + "()' already selects [" + + existing.fields + + "]", + element); + messager.printMessage( + Diagnostic.Kind.ERROR, + "Conflicting return type '" + + className + + "': method selects [" + + existing.fields + + "] but method '" + + element.getSimpleName() + + "()' selects [" + + fields + + "]", + existing.element); + return; + } + return; + } + resultTypeSignatures.put(className, new ResultTypeUsage(signature, fields, element)); + + var tree = buildResultType(className, selectionSet, parentType); + if (tree == null) { return; } - generatedTypes.add(className); + writeResultRecord(tree, element); + processPendingTypes(element); + } + + private ResultTypeDefinition buildResultType( + String className, SelectionSet selectionSet, ObjectTypeDefinition parentType) { var fields = new ArrayList(); + var innerTypes = new ArrayList(); for (var selection : selectionSet.getSelections()) { - if (!(selection instanceof Field)) { + if (!(selection instanceof Field field)) { continue; } - var field = (Field) selection; var fieldName = field.getName(); - var schemaDef = findFieldDefinition(parentType, fieldName); if (schemaDef == null) { continue; @@ -99,8 +142,16 @@ public void generateResultType( if (field.getSelectionSet() != null && !field.getSelectionSet().getSelections().isEmpty()) { var nestedClassName = capitalize(fieldName); - generateNestedResultType(nestedClassName, field.getSelectionSet(), rawTypeName, element); - var nestedType = wrapType(fieldType, ClassName.get(targetPackage, nestedClassName)); + var nestedObjectType = + registry.getType(rawTypeName, ObjectTypeDefinition.class).orElse(null); + if (nestedObjectType != null) { + var innerTree = + buildResultType(nestedClassName, field.getSelectionSet(), nestedObjectType); + if (innerTree != null) { + innerTypes.add(innerTree); + } + } + var nestedType = wrapType(fieldType, ClassName.get("", nestedClassName)); fields.add(toRecordField(fieldName, nestedType)); } else { var javaType = typeMapper.map(fieldType); @@ -109,8 +160,105 @@ public void generateResultType( } } - writeRecord(className, fields, element); - processPendingTypes(element); + var def = new ResultTypeDefinition(); + def.className = className; + def.fields = fields; + def.innerTypes = innerTypes; + return def; + } + + private void writeResultRecord(ResultTypeDefinition tree, Element element) { + var fqn = targetPackage.isEmpty() ? tree.className : targetPackage + "." + tree.className; + try { + var sourceFile = filer.createSourceFile(fqn, element); + try (var out = new PrintWriter(sourceFile.openWriter())) { + if (!targetPackage.isEmpty()) { + out.println("package " + targetPackage + ";"); + out.println(); + } + + var imports = new TreeSet(); + collectAllImports(tree, imports); + if (!imports.isEmpty()) { + for (var imp : imports) { + out.println("import " + imp + ";"); + } + out.println(); + } + + writeRecordBody(out, tree, ""); + } + } catch (FilerException e) { + // Type already generated by another interface in the same compilation round + } catch (IOException e) { + messager.printMessage( + Diagnostic.Kind.ERROR, + "Failed to write generated type " + tree.className + ": " + e.getMessage(), + element); + } + } + + private void writeRecordBody(PrintWriter out, ResultTypeDefinition tree, String indent) { + var params = + tree.fields.stream() + .map(f -> f.typeString + " " + f.name) + .collect(Collectors.joining(", ")); + + if (tree.innerTypes.isEmpty()) { + out.println(indent + "public record " + tree.className + "(" + params + ") {}"); + } else { + out.println(indent + "public record " + tree.className + "(" + params + ") {"); + out.println(); + for (var inner : tree.innerTypes) { + writeRecordBody(out, inner, indent + " "); + out.println(); + } + out.println(indent + "}"); + } + } + + private void collectAllImports(ResultTypeDefinition tree, Set imports) { + for (var field : tree.fields) { + if (field.typeName != null) { + collectImportsFromTypeName(field.typeName, imports); + } + } + for (var inner : tree.innerTypes) { + collectAllImports(inner, imports); + } + } + + private String canonicalize(SelectionSet selectionSet) { + var entries = new ArrayList(); + for (var selection : selectionSet.getSelections()) { + if (!(selection instanceof Field field)) { + continue; + } + var name = field.getName(); + if (field.getSelectionSet() != null && !field.getSelectionSet().getSelections().isEmpty()) { + entries.add(name + "{" + canonicalize(field.getSelectionSet()) + "}"); + } else { + entries.add(name); + } + } + entries.sort(String::compareTo); + return String.join(",", entries); + } + + private String describeFields(SelectionSet selectionSet) { + var entries = new ArrayList(); + for (var selection : selectionSet.getSelections()) { + if (!(selection instanceof Field field)) { + continue; + } + var name = field.getName(); + if (field.getSelectionSet() != null && !field.getSelectionSet().getSelections().isEmpty()) { + entries.add(name + " { " + describeFields(field.getSelectionSet()) + " }"); + } else { + entries.add(name); + } + } + return String.join(", ", entries); } public void generateInputType(String className, String graphqlTypeName, Element element) { @@ -143,20 +291,6 @@ public void generateInputType(String className, String graphqlTypeName, Element processPendingTypes(element); } - private void generateNestedResultType( - String className, SelectionSet selectionSet, String graphqlTypeName, Element element) { - if (generatedTypes.contains(className)) { - return; - } - - var maybeDef = registry.getType(graphqlTypeName, ObjectTypeDefinition.class); - if (maybeDef.isEmpty()) { - return; - } - - generateResultType(className, selectionSet, maybeDef.get(), element); - } - private void processPendingTypes(Element element) { while (!pendingTypes.isEmpty()) { var typeName = pendingTypes.poll(); @@ -378,6 +512,14 @@ private void writeRecord(String className, List fields, Element ele } } + record ResultTypeUsage(String signature, String fields, Element element) {} + + static class ResultTypeDefinition { + String className; + List fields; + List innerTypes; + } + static class RecordField { final String typeString; final String name; diff --git a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java index cd272b2f25..1ab5408fca 100644 --- a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java +++ b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java @@ -37,18 +37,18 @@ void validMutationGeneratesTypes() { @GraphqlSchema("test-schema.graphql") interface MyApi { @GraphqlQuery(\""" - mutation createUser($input: CreateUserInput!) { - createUser(input: $input) { id name email status } + mutation createCharacter($input: CreateCharacterInput!) { + createCharacter(input: $input) { id name email appearsIn } }\""") - CreateUserResult createUser(CreateUserInput input); + CreateCharacterResult createCharacter(CreateCharacterInput input); } """); var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.CreateUserResult"); - assertThat(compilation).generatedSourceFile("test.CreateUserInput"); + assertThat(compilation).generatedSourceFile("test.CreateCharacterResult"); + assertThat(compilation).generatedSourceFile("test.CreateCharacterInput"); } @Test @@ -88,7 +88,7 @@ void missingSchemaReportsError() { @GraphqlSchema("nonexistent-schema.graphql") interface NoSchemaApi { - @GraphqlQuery("{ user(id: \\"1\\") { id } }") + @GraphqlQuery("{ character(id: \\"1\\") { id } }") Object query(); } """); @@ -100,7 +100,7 @@ interface NoSchemaApi { } @Test - void nestedTypesAreGenerated() { + void nestedTypesAreGeneratedAsInnerRecords() { var source = JavaFileObjects.forSourceString( "test.NestedApi", @@ -113,17 +113,20 @@ void nestedTypesAreGenerated() { @GraphqlSchema("test-schema.graphql") interface NestedApi { @GraphqlQuery(\""" - { user(id: "1") { id name address { street city country } } } + { character(id: "1") { id name location { planet sector region } } } \""") - UserResult getUser(); + CharacterResult getCharacter(); } """); var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.UserResult"); - assertThat(compilation).generatedSourceFile("test.Address"); + assertThat(compilation).generatedSourceFile("test.CharacterResult"); + assertThat(compilation) + .generatedSourceFile("test.CharacterResult") + .contentsAsUtf8String() + .contains("public record Location(String planet, String sector, String region) {}"); } @Test @@ -140,18 +143,18 @@ void enumsAreGeneratedAsJavaEnums() { @GraphqlSchema("test-schema.graphql") interface EnumApi { @GraphqlQuery(\""" - mutation updateStatus($id: ID!, $status: Status!) { - updateStatus(id: $id, status: $status) { id status } + mutation updateEpisode($id: ID!, $episode: Episode!) { + updateEpisode(id: $id, episode: $episode) { id appearsIn } }\""") - StatusResult updateStatus(String id, Status status); + EpisodeResult updateEpisode(String id, Episode episode); } """); var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.StatusResult"); - assertThat(compilation).generatedSourceFile("test.Status"); + assertThat(compilation).generatedSourceFile("test.EpisodeResult"); + assertThat(compilation).generatedSourceFile("test.Episode"); } @Test @@ -167,15 +170,15 @@ void listTypesMapToJavaList() { @GraphqlSchema("test-schema.graphql") interface ListApi { - @GraphqlQuery("{ user(id: \\"1\\") { id name tags } }") - UserWithTagsResult getUser(); + @GraphqlQuery("{ character(id: \\"1\\") { id name tags } }") + CharacterWithTagsResult getCharacter(); } """); var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.UserWithTagsResult"); + assertThat(compilation).generatedSourceFile("test.CharacterWithTagsResult"); } @Test @@ -192,29 +195,29 @@ void multipleMethodsSharingInputType() { @GraphqlSchema("test-schema.graphql") interface SharedApi { @GraphqlQuery(\""" - mutation createUser($input: CreateUserInput!) { - createUser(input: $input) { id name } + mutation createCharacter($input: CreateCharacterInput!) { + createCharacter(input: $input) { id name } }\""") - CreateResult1 createUser1(CreateUserInput input); + CreateResult1 createCharacter1(CreateCharacterInput input); @GraphqlQuery(\""" - mutation createUser($input: CreateUserInput!) { - createUser(input: $input) { id email } + mutation createCharacter($input: CreateCharacterInput!) { + createCharacter(input: $input) { id email } }\""") - CreateResult2 createUser2(CreateUserInput input); + CreateResult2 createCharacter2(CreateCharacterInput input); } """); var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.CreateUserInput"); + assertThat(compilation).generatedSourceFile("test.CreateCharacterInput"); assertThat(compilation).generatedSourceFile("test.CreateResult1"); assertThat(compilation).generatedSourceFile("test.CreateResult2"); } @Test - void deeplyNestedOrganizationQuery() { + void deeplyNestedStarshipQuery() { var source = JavaFileObjects.forSourceString( "test.DeepApi", @@ -228,31 +231,39 @@ void deeplyNestedOrganizationQuery() { interface DeepApi { @GraphqlQuery(\""" { - organization(id: "1") { + starship(id: "1") { id name - address { street city coordinates { latitude longitude } } - departments { + location { planet sector coordinates { latitude longitude } } + squadrons { id name - lead { id name status } + leader { id name appearsIn } members { id name email } - subDepartments { id name tags { key value } } - tags { key value } + subSquadrons { id name traits { key value } } + traits { key value } } - metadata { foundedYear industry categories { name tags { key value } } } + specs { lengthMeters classification weapons { name traits { key value } } } } }\""") - OrgResult getOrganization(); + StarshipResult getStarship(); } """); var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.OrgResult"); - assertThat(compilation).generatedSourceFile("test.Address"); - assertThat(compilation).generatedSourceFile("test.Coordinates"); - assertThat(compilation).generatedSourceFile("test.Departments"); - assertThat(compilation).generatedSourceFile("test.Metadata"); + assertThat(compilation).generatedSourceFile("test.StarshipResult"); + assertThat(compilation) + .generatedSourceFile("test.StarshipResult") + .contentsAsUtf8String() + .contains("public record Location("); + assertThat(compilation) + .generatedSourceFile("test.StarshipResult") + .contentsAsUtf8String() + .contains("public record Squadrons("); + assertThat(compilation) + .generatedSourceFile("test.StarshipResult") + .contentsAsUtf8String() + .contains("public record Specs("); } @Test @@ -269,26 +280,26 @@ void complexMutationWithNestedInputs() { @GraphqlSchema("test-schema.graphql") interface ComplexMutationApi { @GraphqlQuery(\""" - mutation createOrg($input: CreateOrgInput!) { - createOrganization(input: $input) { + mutation createStarship($input: CreateStarshipInput!) { + createStarship(input: $input) { id name - departments { id name subDepartments { id name } } + squadrons { id name subSquadrons { id name } } } }\""") - CreateOrgResult createOrg(CreateOrgInput input); + CreateStarshipResult createStarship(CreateStarshipInput input); } """); var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.CreateOrgResult"); - assertThat(compilation).generatedSourceFile("test.CreateOrgInput"); - assertThat(compilation).generatedSourceFile("test.DepartmentInput"); - assertThat(compilation).generatedSourceFile("test.TagInput"); - assertThat(compilation).generatedSourceFile("test.AddressInput"); - assertThat(compilation).generatedSourceFile("test.OrgMetadataInput"); - assertThat(compilation).generatedSourceFile("test.CategoryInput"); + assertThat(compilation).generatedSourceFile("test.CreateStarshipResult"); + assertThat(compilation).generatedSourceFile("test.CreateStarshipInput"); + assertThat(compilation).generatedSourceFile("test.SquadronInput"); + assertThat(compilation).generatedSourceFile("test.TraitInput"); + assertThat(compilation).generatedSourceFile("test.LocationInput"); + assertThat(compilation).generatedSourceFile("test.ShipSpecsInput"); + assertThat(compilation).generatedSourceFile("test.WeaponInput"); } @Test @@ -305,14 +316,14 @@ void searchWithComplexFilterInput() { @GraphqlSchema("test-schema.graphql") interface SearchApi { @GraphqlQuery(\""" - query searchOrgs($criteria: OrgSearchCriteria!) { - searchOrganizations(criteria: $criteria) { + query searchStarships($criteria: StarshipSearchCriteria!) { + searchStarships(criteria: $criteria) { id name - departments { id name lead { id name } tags { key value } } - metadata { foundedYear categories { name parentCategory { name } } } + squadrons { id name leader { id name } traits { key value } } + specs { lengthMeters weapons { name parentWeapon { name } } } } }\""") - SearchResult searchOrganizations(OrgSearchCriteria criteria); + SearchResult searchStarships(StarshipSearchCriteria criteria); } """); @@ -320,9 +331,9 @@ query searchOrgs($criteria: OrgSearchCriteria!) { assertThat(compilation).succeeded(); assertThat(compilation).generatedSourceFile("test.SearchResult"); - assertThat(compilation).generatedSourceFile("test.OrgSearchCriteria"); - assertThat(compilation).generatedSourceFile("test.DepartmentFilterInput"); - assertThat(compilation).generatedSourceFile("test.TagInput"); + assertThat(compilation).generatedSourceFile("test.StarshipSearchCriteria"); + assertThat(compilation).generatedSourceFile("test.SquadronFilterInput"); + assertThat(compilation).generatedSourceFile("test.TraitInput"); } @Test @@ -340,18 +351,18 @@ void listReturnTypeGeneratesElementType() { @GraphqlSchema("test-schema.graphql") interface ListReturnApi { @GraphqlQuery(\""" - query listUsers($filter: UserFilter) { - users(filter: $filter) { id name email status } + query listCharacters($filter: CharacterFilter) { + characters(filter: $filter) { id name email appearsIn } }\""") - List listUsers(UserFilter filter); + List listCharacters(CharacterFilter filter); } """); var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.UserListResult"); - assertThat(compilation).generatedSourceFile("test.UserFilter"); + assertThat(compilation).generatedSourceFile("test.CharacterListResult"); + assertThat(compilation).generatedSourceFile("test.CharacterFilter"); } @Test @@ -368,10 +379,10 @@ void existingExternalTypeSkipsGeneration() { @GraphqlSchema("test-schema.graphql") interface ExternalTypeApi { @GraphqlQuery(\""" - mutation createUser($input: CreateUserInput!) { - createUser(input: $input) { id name email } + mutation createCharacter($input: CreateCharacterInput!) { + createCharacter(input: $input) { id name email } }\""") - CreateResult createUser(feign.graphql.GraphqlQuery input); + CreateResult createCharacter(feign.graphql.GraphqlQuery input); } """); @@ -382,7 +393,7 @@ mutation createUser($input: CreateUserInput!) { } @Test - void userWithOrganizationMultipleLevelReuse() { + void characterWithStarshipMultipleLevelReuse() { var source = JavaFileObjects.forSourceString( "test.ReuseApi", @@ -396,31 +407,31 @@ void userWithOrganizationMultipleLevelReuse() { interface ReuseApi { @GraphqlQuery(\""" { - user(id: "1") { - id name status - address { street city country coordinates { latitude longitude } } - organization { + character(id: "1") { + id name appearsIn + location { planet sector region coordinates { latitude longitude } } + starship { id name - address { street city coordinates { latitude longitude } } - departments { id name members { id name } } + location { planet sector coordinates { latitude longitude } } + squadrons { id name members { id name } } } } }\""") - FullUserResult getFullUser(); + FullCharacterResult getFullCharacter(); @GraphqlQuery(\""" - query listUsers($filter: UserFilter) { - users(filter: $filter) { id name email tags } + query listCharacters($filter: CharacterFilter) { + characters(filter: $filter) { id name email tags } }\""") - UserListResult listUsers(UserFilter filter); + CharacterListResult listCharacters(CharacterFilter filter); } """); var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.FullUserResult"); - assertThat(compilation).generatedSourceFile("test.Status"); + assertThat(compilation).generatedSourceFile("test.FullCharacterResult"); + assertThat(compilation).generatedSourceFile("test.Episode"); } @Test @@ -440,15 +451,15 @@ interface ScalarApi { @Scalar("DateTime") default String dateTime(String raw) { return raw; } - @GraphqlQuery("{ event(id: \\"1\\") { id name startTime endTime } }") - EventResult getEvent(); + @GraphqlQuery("{ battle(id: \\"1\\") { id name startTime endTime } }") + BattleResult getBattle(); } """); var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.EventResult"); + assertThat(compilation).generatedSourceFile("test.BattleResult"); } @Test @@ -464,8 +475,8 @@ void missingScalarAnnotationReportsError() { @GraphqlSchema("scalar-test-schema.graphql") interface MissingScalarApi { - @GraphqlQuery("{ event(id: \\"1\\") { id name startTime } }") - EventResult getEvent(); + @GraphqlQuery("{ battle(id: \\"1\\") { id name startTime } }") + BattleResult getBattle(); } """); @@ -503,8 +514,8 @@ interface ScalarDefinitions { @GraphqlSchema("scalar-test-schema.graphql") interface ChildApi extends ScalarDefinitions { - @GraphqlQuery("{ event(id: \\"1\\") { id name startTime } }") - EventResult getEvent(); + @GraphqlQuery("{ battle(id: \\"1\\") { id name startTime } }") + BattleResult getBattle(); } """); @@ -512,6 +523,153 @@ interface ChildApi extends ScalarDefinitions { javac().withProcessors(new GraphqlSchemaProcessor()).compile(parentSource, source); assertThat(compilation).succeeded(); - assertThat(compilation).generatedSourceFile("test.EventResult"); + assertThat(compilation).generatedSourceFile("test.BattleResult"); + } + + @Test + void conflictingReturnTypesReportsError() { + var source = + JavaFileObjects.forSourceString( + "test.ConflictApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface ConflictApi { + @GraphqlQuery(\""" + { character(id: "1") { id name } } + \""") + CharResult query1(); + + @GraphqlQuery(\""" + { character(id: "2") { id email } } + \""") + CharResult query2(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("Conflicting return type 'CharResult'"); + assertThat(compilation).hadErrorContaining("'query1()'"); + assertThat(compilation).hadErrorContaining("'query2()'"); + assertThat(compilation).hadErrorContaining("id, name"); + assertThat(compilation).hadErrorContaining("id, email"); + } + + @Test + void sameReturnTypeSameFieldsSucceeds() { + var source = + JavaFileObjects.forSourceString( + "test.SameFieldsApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface SameFieldsApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + CharResult query1(); + + @GraphqlQuery(\""" + { character(id: "2") { id name email } } + \""") + CharResult query2(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.CharResult"); + } + + @Test + void innerClassContentIsCorrect() { + var source = + JavaFileObjects.forSourceString( + "test.InnerApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface InnerApi { + @GraphqlQuery(\""" + { + starship(id: "1") { + id name + location { planet coordinates { latitude longitude } } + specs { lengthMeters classification } + } + }\""") + ShipResult getShip(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.ShipResult").contentsAsUtf8String(); + + contents.contains( + "public record ShipResult(String id, String name, Location location, Specs specs)"); + contents.contains("public record Location(String planet, Coordinates coordinates)"); + contents.contains("public record Coordinates(Double latitude, Double longitude) {}"); + contents.contains("public record Specs(Integer lengthMeters, String classification) {}"); + } + + @Test + void differentQueriesDifferentNestedFields() { + var source = + JavaFileObjects.forSourceString( + "test.DiffNestedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface DiffNestedApi { + @GraphqlQuery(\""" + { character(id: "1") { id location { planet } } } + \""") + CharByPlanet queryByPlanet(); + + @GraphqlQuery(\""" + { character(id: "2") { id location { sector region } } } + \""") + CharByRegion queryByRegion(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.CharByPlanet"); + assertThat(compilation).generatedSourceFile("test.CharByRegion"); + + assertThat(compilation) + .generatedSourceFile("test.CharByPlanet") + .contentsAsUtf8String() + .contains("public record Location(String planet) {}"); + + assertThat(compilation) + .generatedSourceFile("test.CharByRegion") + .contentsAsUtf8String() + .contains("public record Location(String sector, String region) {}"); } } diff --git a/graphql-apt/src/test/resources/scalar-test-schema.graphql b/graphql-apt/src/test/resources/scalar-test-schema.graphql index d8aa82dd05..aca3bccecf 100644 --- a/graphql-apt/src/test/resources/scalar-test-schema.graphql +++ b/graphql-apt/src/test/resources/scalar-test-schema.graphql @@ -2,11 +2,11 @@ scalar DateTime type Query { - event(id: ID!): Event - events: [Event] + battle(id: ID!): Battle + battles: [Battle] } -type Event { +type Battle { id: ID! name: String! startTime: DateTime! diff --git a/graphql-apt/src/test/resources/test-schema.graphql b/graphql-apt/src/test/resources/test-schema.graphql index ec88456d8a..0a4ec76807 100644 --- a/graphql-apt/src/test/resources/test-schema.graphql +++ b/graphql-apt/src/test/resources/test-schema.graphql @@ -1,64 +1,68 @@ +# Star Wars schema based on https://graphql.org/learn/schema/ +# Adapted for feign-graphql-apt test purposes + type Query { - user(id: ID!): User - users(filter: UserFilter): [User] - organization(id: ID!): Organization - searchOrganizations(criteria: OrgSearchCriteria!): [Organization] + character(id: ID!): Character + characters(filter: CharacterFilter): [Character] + starship(id: ID!): Starship + searchStarships(criteria: StarshipSearchCriteria!): [Starship] } type Mutation { - createUser(input: CreateUserInput!): User - updateStatus(id: ID!, status: Status!): User - createOrganization(input: CreateOrgInput!): Organization + createCharacter(input: CreateCharacterInput!): Character + updateEpisode(id: ID!, episode: Episode!): Character + createStarship(input: CreateStarshipInput!): Starship } -type User { +type Character { id: ID! name: String! email: String - status: Status! - address: Address + appearsIn: Episode! + location: Location tags: [String] - organization: Organization + friends: [Character] + starship: Starship } -type Organization { +type Starship { id: ID! name: String! - address: Address - departments: [Department] - metadata: OrgMetadata + location: Location + squadrons: [Squadron] + specs: ShipSpecs } -type Department { +type Squadron { id: ID! name: String! - lead: User - members: [User] - subDepartments: [Department] - tags: [Tag] + leader: Character + members: [Character] + subSquadrons: [Squadron] + traits: [Trait] } -type Tag { +type Trait { key: String! value: String! } -type OrgMetadata { - foundedYear: Int - industry: String - categories: [Category] +type ShipSpecs { + lengthMeters: Int + classification: String + weapons: [Weapon] } -type Category { +type Weapon { name: String! - parentCategory: Category - tags: [Tag] + parentWeapon: Weapon + traits: [Trait] } -type Address { - street: String - city: String - country: String +type Location { + planet: String + sector: String + region: String coordinates: Coordinates } @@ -67,30 +71,30 @@ type Coordinates { longitude: Float } -input CreateUserInput { +input CreateCharacterInput { name: String! email: String! - status: Status - address: AddressInput + appearsIn: Episode + location: LocationInput tags: [String] - orgId: ID + starshipId: ID } -input UserFilter { +input CharacterFilter { nameContains: String - status: Status - tagFilter: TagFilterInput + appearsIn: Episode + traitFilter: TraitFilterInput } -input TagFilterInput { +input TraitFilterInput { keys: [String] matchAll: Boolean } -input AddressInput { - street: String - city: String - country: String +input LocationInput { + planet: String + sector: String + region: String coordinates: CoordinatesInput } @@ -99,52 +103,52 @@ input CoordinatesInput { longitude: Float } -input CreateOrgInput { +input CreateStarshipInput { name: String! - address: AddressInput - departments: [DepartmentInput] - metadata: OrgMetadataInput + location: LocationInput + squadrons: [SquadronInput] + specs: ShipSpecsInput } -input DepartmentInput { +input SquadronInput { name: String! - leadUserId: ID - subDepartments: [DepartmentInput] - tags: [TagInput] + leaderCharacterId: ID + subSquadrons: [SquadronInput] + traits: [TraitInput] } -input TagInput { +input TraitInput { key: String! value: String! } -input OrgMetadataInput { - foundedYear: Int - industry: String - categories: [CategoryInput] +input ShipSpecsInput { + lengthMeters: Int + classification: String + weapons: [WeaponInput] } -input CategoryInput { +input WeaponInput { name: String! - parentCategoryName: String - tags: [TagInput] + parentWeaponName: String + traits: [TraitInput] } -input OrgSearchCriteria { +input StarshipSearchCriteria { nameContains: String - industries: [String] - minFoundedYear: Int - departmentFilter: DepartmentFilterInput + classifications: [String] + minLengthMeters: Int + squadronFilter: SquadronFilterInput } -input DepartmentFilterInput { +input SquadronFilterInput { nameContains: String minMembers: Int - tags: [TagInput] + traits: [TraitInput] } -enum Status { - ACTIVE - INACTIVE - PENDING +enum Episode { + NEWHOPE + EMPIRE + JEDI } From 770fbbdb301c67c97cc6437292866aa46acda5ee Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 27 Feb 2026 08:45:56 -0300 Subject: [PATCH 411/615] prepare release 13.9.2 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 2d8f3c26f7..270117626c 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index d5a62da711..3516556533 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index dde47f4b40..87eacb89e8 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index d653233e6f..0f495dd67a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 7155c1d438..948562eef9 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 6880e543ed..6d7b1b3d29 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 63cb280898..23e6fc0242 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 577e429644..39be223e88 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index d2f2b27e78..b91effa90d 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 10085b77e1..21cb2ee687 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 10b8365c0d..35938ca535 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index f6b94cbb21..4e7f85a11e 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index d839964803..196d136294 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 55a72207f7..a82c5ebe25 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index e8f23c2232..6bc6ff141d 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index f5f770103a..b3ad2d4a58 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index 20cbe814d1..f8ea0c729e 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 00b1e67d35..cd65653ee5 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 3d7321f28b..fe11b0b540 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 085e5d36ce..da041378b7 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 0eb2b99863..fa4dea055c 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index e37e24df14..9e1bcf235f 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 28da8e722a..d9e85207c7 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 398f3391ff..3b47a3b069 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 3864ca1c61..baa2db2eb6 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 47300b18ab..5d2ef8dbf6 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 3987b7fe82..9dcf5b0e8e 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index d5e6e68257..b5458dd7c3 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 3f827cb095..eb12ec6a07 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index e121974e9f..10b3a0a939 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 7ed79f6943..22e256ca5d 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 9dc9b921b0..264e295e7f 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index ab0112f806..3f829f7d74 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 7f0c7317ad..f744f54eab 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 7b2b677b24..8360bac748 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 6ecf4f3da2..87135aa4c5 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 2245c7583a..e996efb1a2 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 3a092d194c..4765369541 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-okhttp diff --git a/pom.xml b/pom.xml index b2ce324de2..54f5ef3d55 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index ee1e2add7c..086c73af2d 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 2b5cb5b1d6..4f786947ef 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 66ed6c90c3..2e9061fb9a 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 673ee625d0..b89c15f8de 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 39cf7266d1..a57173e78c 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 14208a1579..bdc2d015aa 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 8856f0fde3..f1326a64fe 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index d3abe020bc..a9a9210888 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 1ca081213e..9167176e31 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.9.2 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 3d5bb5d8b3..5956dfbcb2 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.9.2 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 0625cfeae9..2d7386fc7a 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.9.2 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 87a914f193..9f1eef4ec4 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.2 feign-vertx-parent From 86ac598d85053a0acbeb91dbfc7eb0377e9bf707 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 27 Feb 2026 08:46:04 -0300 Subject: [PATCH 412/615] [ci skip] updating versions to next development iteration 13.10-SNAPSHOT --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 270117626c..2d8f3c26f7 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index 3516556533..d5a62da711 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 87eacb89e8..dde47f4b40 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 0f495dd67a..d653233e6f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 948562eef9..7155c1d438 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 6d7b1b3d29..6880e543ed 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 23e6fc0242..63cb280898 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 39be223e88..577e429644 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index b91effa90d..d2f2b27e78 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 21cb2ee687..10085b77e1 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 35938ca535..10b8365c0d 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 4e7f85a11e..f6b94cbb21 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 196d136294..d839964803 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index a82c5ebe25..55a72207f7 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index 6bc6ff141d..e8f23c2232 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index b3ad2d4a58..f5f770103a 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index f8ea0c729e..20cbe814d1 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index cd65653ee5..00b1e67d35 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index fe11b0b540..3d7321f28b 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index da041378b7..085e5d36ce 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index fa4dea055c..0eb2b99863 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 9e1bcf235f..e37e24df14 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index d9e85207c7..28da8e722a 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 3b47a3b069..398f3391ff 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index baa2db2eb6..3864ca1c61 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 5d2ef8dbf6..47300b18ab 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 9dcf5b0e8e..3987b7fe82 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index b5458dd7c3..d5e6e68257 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index eb12ec6a07..3f827cb095 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 10b3a0a939..e121974e9f 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 22e256ca5d..7ed79f6943 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 264e295e7f..9dc9b921b0 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 3f829f7d74..ab0112f806 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index f744f54eab..7f0c7317ad 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 8360bac748..7b2b677b24 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 87135aa4c5..6ecf4f3da2 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index e996efb1a2..2245c7583a 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 4765369541..3a092d194c 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index 54f5ef3d55..b2ce324de2 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 086c73af2d..ee1e2add7c 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 4f786947ef..2b5cb5b1d6 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 2e9061fb9a..66ed6c90c3 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index b89c15f8de..673ee625d0 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index a57173e78c..39cf7266d1 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index bdc2d015aa..14208a1579 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index f1326a64fe..8856f0fde3 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index a9a9210888..d3abe020bc 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 9167176e31..1ca081213e 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9.2 + 13.10-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 5956dfbcb2..3d5bb5d8b3 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9.2 + 13.10-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 2d7386fc7a..0625cfeae9 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9.2 + 13.10-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 9f1eef4ec4..87a914f193 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.2 + 13.10-SNAPSHOT feign-vertx-parent From 85aef9ff1dbfd34b9717fc3faab1297ba5f4e58c Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 27 Feb 2026 09:00:55 -0300 Subject: [PATCH 413/615] Add explicit feign-form-spring dependency for parallel build ordering Signed-off-by: Marvin Froeder --- example-wikipedia-with-springboot/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index d2f2b27e78..224f17d2c1 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -63,6 +63,12 @@ org.springframework.cloud spring-cloud-starter-openfeign + + + io.github.openfeign + feign-form-spring + org.apache.commons commons-exec From c7dbca61ab64dd887fb78b743965df58e8ba6d32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 05:31:22 +0000 Subject: [PATCH 414/615] build(deps): Bump mockito.version from 5.21.0 to 5.22.0 Bumps `mockito.version` from 5.21.0 to 5.22.0. Updates `org.mockito:mockito-core` from 5.21.0 to 5.22.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.21.0...v5.22.0) Updates `org.mockito:mockito-junit-jupiter` from 5.21.0 to 5.22.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.21.0...v5.22.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.22.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-junit-jupiter dependency-version: 5.22.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b2ce324de2..7e0d81dae5 100644 --- a/pom.xml +++ b/pom.xml @@ -173,7 +173,7 @@ 2.21.1 3.1.0 3.27.7 - 5.21.0 + 5.22.0 2.0.61.android8 1.5.3 From 2c3bd9e5bc28310cc347848992458b70d0eab91c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 05:31:46 +0000 Subject: [PATCH 415/615] build(deps): Bump org.apache.felix:maven-bundle-plugin Bumps org.apache.felix:maven-bundle-plugin from 6.0.0 to 6.0.2. --- updated-dependencies: - dependency-name: org.apache.felix:maven-bundle-plugin dependency-version: 6.0.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b2ce324de2..5fe61a2aa4 100644 --- a/pom.xml +++ b/pom.xml @@ -185,7 +185,7 @@ 5.0.0 3.5.0 3.3.1 - 6.0.0 + 6.0.2 0.1.1 0.10.0 3.5.5 From 8a7fc5d066b28f1ec38987a0cce49c198dde57d5 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 3 Mar 2026 12:06:46 -0300 Subject: [PATCH 416/615] fix: ensure BOM publish runs even if deploy step fails Signed-off-by: Marvin Froeder --- .circleci/config.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index e901e0a60d..8f947eb2dd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -103,6 +103,7 @@ commands: ./mvnw -ntp -nsu --serial -s .circleci/settings.xml -P release -pl -:feign-benchmark,-:feign-vertx4-test,-:feign-vertx5-test,-:feign-example-github,-:feign-example-github-with-coroutine,-:feign-example-wikipedia,-:feign-example-wikipedia-with-springboot -DskipTests=true deploy - run: name: 'Publish BOM to Maven Central' + when: always command: | BOM_DIR=target/classes/feign-bom BOM_POM=$BOM_DIR/pom.xml @@ -111,6 +112,10 @@ commands: exit 0 fi BOM_VERSION=$(grep '' "$BOM_POM" | head -1 | sed 's/.*\(.*\)<\/version>.*/\1/') + if [[ "$BOM_VERSION" == *SNAPSHOT* ]]; then + echo "Skipping BOM publish for SNAPSHOT version $BOM_VERSION" + exit 0 + fi STAGING_DIR=/tmp/bom-staging/io/github/openfeign/feign-bom/$BOM_VERSION mkdir -p "$STAGING_DIR" cp "$BOM_POM" "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom" From 46c136f36b4a13799cb732862ee1f8607c781879 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 3 Mar 2026 15:51:58 -0300 Subject: [PATCH 417/615] fix: validate BOM has dependencies before publishing to Maven Central Signed-off-by: Marvin Froeder --- .circleci/config.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8f947eb2dd..b6743fa91c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -116,6 +116,12 @@ commands: echo "Skipping BOM publish for SNAPSHOT version $BOM_VERSION" exit 0 fi + DEP_COUNT=$(grep -c 'feign-' "$BOM_POM" || true) + if [ "$DEP_COUNT" -eq 0 ]; then + echo "ERROR: BOM has no feign dependencies, refusing to publish an empty BOM" + exit 1 + fi + echo "BOM contains $DEP_COUNT feign dependencies" STAGING_DIR=/tmp/bom-staging/io/github/openfeign/feign-bom/$BOM_VERSION mkdir -p "$STAGING_DIR" cp "$BOM_POM" "$STAGING_DIR/feign-bom-${BOM_VERSION}.pom" From 1e925943cc1693cae0ca8b19dc6be68f50102c0a Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 3 Mar 2026 16:00:33 -0300 Subject: [PATCH 418/615] prepare release 13.9.3 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 2d8f3c26f7..eea89a019b 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index d5a62da711..6e267165d3 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index dde47f4b40..f22ba67457 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index d653233e6f..ebe8524cba 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 7155c1d438..505e4c5b1e 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 6880e543ed..ab66f510dd 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 63cb280898..938b12a41f 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 577e429644..11dd0c09f6 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 224f17d2c1..6e486ff2fb 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 10085b77e1..22f04ee916 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 10b8365c0d..e2b7ea52bf 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index f6b94cbb21..258f8269bd 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index d839964803..cedd6df736 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 55a72207f7..24751ad578 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index e8f23c2232..4f594b7fec 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index f5f770103a..3b3e1e4fa6 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index 20cbe814d1..238d25a2ef 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 00b1e67d35..2276087a53 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 3d7321f28b..857573d873 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 085e5d36ce..f8eba3e5be 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 0eb2b99863..5a9d8f27cb 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index e37e24df14..e2034ef95a 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 28da8e722a..e9d17e6aa3 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 398f3391ff..73a793ac14 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 3864ca1c61..bbfc3c3960 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 47300b18ab..7dcdcd2757 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 3987b7fe82..f89742197d 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index d5e6e68257..8e207934da 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 3f827cb095..008de5306f 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index e121974e9f..8dd3405a0b 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 7ed79f6943..9aaa254b5d 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 9dc9b921b0..301e69ce94 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index ab0112f806..094214dea5 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 7f0c7317ad..08c967c0fd 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 7b2b677b24..98e5c64c1b 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 6ecf4f3da2..6c26621954 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 2245c7583a..d4e2d0622f 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 3a092d194c..b0bd7c5203 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-okhttp diff --git a/pom.xml b/pom.xml index 6fc0606163..11247b8b7f 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index ee1e2add7c..387efbbbbb 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 2b5cb5b1d6..b2267e471c 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 66ed6c90c3..bace1af19c 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 673ee625d0..fa05295907 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 39cf7266d1..97aa95b037 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 14208a1579..3a5a85ad60 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 8856f0fde3..2a40f077cc 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index d3abe020bc..0806999f30 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 1ca081213e..ad60f41f9e 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.9.3 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 3d5bb5d8b3..cd97e18c46 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.9.3 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 0625cfeae9..6634548470 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.9.3 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 87a914f193..8c09d7ead2 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.9.3 feign-vertx-parent From babe0961888b6926d01d2fe271f25cba9fb4d91a Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 3 Mar 2026 16:00:43 -0300 Subject: [PATCH 419/615] [ci skip] updating versions to next development iteration 13.10-SNAPSHOT --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index eea89a019b..2d8f3c26f7 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index 6e267165d3..d5a62da711 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index f22ba67457..dde47f4b40 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index ebe8524cba..d653233e6f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 505e4c5b1e..7155c1d438 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index ab66f510dd..6880e543ed 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 938b12a41f..63cb280898 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 11dd0c09f6..577e429644 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 6e486ff2fb..224f17d2c1 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 22f04ee916..10085b77e1 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index e2b7ea52bf..10b8365c0d 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 258f8269bd..f6b94cbb21 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index cedd6df736..d839964803 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 24751ad578..55a72207f7 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index 4f594b7fec..e8f23c2232 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 3b3e1e4fa6..f5f770103a 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index 238d25a2ef..20cbe814d1 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 2276087a53..00b1e67d35 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 857573d873..3d7321f28b 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index f8eba3e5be..085e5d36ce 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 5a9d8f27cb..0eb2b99863 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index e2034ef95a..e37e24df14 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index e9d17e6aa3..28da8e722a 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 73a793ac14..398f3391ff 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index bbfc3c3960..3864ca1c61 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 7dcdcd2757..47300b18ab 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index f89742197d..3987b7fe82 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 8e207934da..d5e6e68257 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 008de5306f..3f827cb095 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 8dd3405a0b..e121974e9f 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 9aaa254b5d..7ed79f6943 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 301e69ce94..9dc9b921b0 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 094214dea5..ab0112f806 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 08c967c0fd..7f0c7317ad 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 98e5c64c1b..7b2b677b24 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 6c26621954..6ecf4f3da2 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index d4e2d0622f..2245c7583a 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index b0bd7c5203..3a092d194c 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index 11247b8b7f..6fc0606163 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 387efbbbbb..ee1e2add7c 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index b2267e471c..2b5cb5b1d6 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index bace1af19c..66ed6c90c3 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index fa05295907..673ee625d0 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 97aa95b037..39cf7266d1 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 3a5a85ad60..14208a1579 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 2a40f077cc..8856f0fde3 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 0806999f30..d3abe020bc 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index ad60f41f9e..1ca081213e 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9.3 + 13.10-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index cd97e18c46..3d5bb5d8b3 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9.3 + 13.10-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 6634548470..0625cfeae9 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.9.3 + 13.10-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 8c09d7ead2..87a914f193 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.9.3 + 13.10-SNAPSHOT feign-vertx-parent From cf8a719833b341957b28c4309537cb8680f03130 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 05:24:47 +0000 Subject: [PATCH 420/615] build(deps): Bump git-code-format-maven-plugin.version from 5.4 to 5.5 Bumps `git-code-format-maven-plugin.version` from 5.4 to 5.5. Updates `com.cosium.code:google-java-format` from 5.4 to 5.5 - [Release notes](https://github.com/Cosium/git-code-format-maven-plugin/releases) - [Commits](https://github.com/Cosium/git-code-format-maven-plugin/compare/5.4...5.5) Updates `com.cosium.code:git-code-format-maven-plugin` from 5.4 to 5.5 - [Release notes](https://github.com/Cosium/git-code-format-maven-plugin/releases) - [Commits](https://github.com/Cosium/git-code-format-maven-plugin/compare/5.4...5.5) --- updated-dependencies: - dependency-name: com.cosium.code:google-java-format dependency-version: '5.5' dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.cosium.code:git-code-format-maven-plugin dependency-version: '5.5' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6fc0606163..761a7de0d2 100644 --- a/pom.xml +++ b/pom.xml @@ -177,7 +177,7 @@ 2.0.61.android8 1.5.3 - 5.4 + 5.5 3.15.0 3.1.4 3.4.0 From 13519ac687b1dfaced43315b8b9707a2341e865f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 05:25:28 +0000 Subject: [PATCH 421/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.28.0 to 3.29.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.28.0...v3.29.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.29.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6fc0606163..48a08316f2 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 1.2.8 4.0.0 6.30.0 - 3.28.0 + 3.29.0 3.28.0 0.25.4 1.0 From 1a2ce1fb5f32a915de1a831c2db84dbbf3719aac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 05:36:25 +0000 Subject: [PATCH 422/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.30.0 to 6.32.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.30.0...v6.32.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.32.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8d01f402f6..26bf9d474e 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 3.2.0 1.2.8 4.0.0 - 6.30.0 + 6.32.0 3.29.0 3.28.0 0.25.4 From 1e2b7fa5c4d8fe2e155b415e904421039195f412 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 05:36:28 +0000 Subject: [PATCH 423/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.28.0 to 3.29.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.28.0...v3.29.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.29.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8d01f402f6..c10b3cdea3 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 4.0.0 6.30.0 3.29.0 - 3.28.0 + 3.29.0 0.25.4 1.0 From 98d4c7221e51f5aa944afeb6e4bb2a976587c4ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 05:25:07 +0000 Subject: [PATCH 424/615] build(deps): Bump org.apache.maven.plugins:maven-shade-plugin Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.6.1 to 3.6.2. - [Release notes](https://github.com/apache/maven-shade-plugin/releases) - [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.6.1...maven-shade-plugin-3.6.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-shade-plugin dependency-version: 3.6.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cb5f43b698..0c13bafc0e 100644 --- a/pom.xml +++ b/pom.xml @@ -234,7 +234,7 @@ 1.19.4 1.1.1 1.18.42 - 3.6.1 + 3.6.2 4.2.38 5.0.6 0.2.0 From ed7ea6b0b79d118bf642e76d6205b29a39e5e154 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 05:26:04 +0000 Subject: [PATCH 425/615] build(deps): Bump git-code-format-maven-plugin.version from 5.5 to 6.0 Bumps `git-code-format-maven-plugin.version` from 5.5 to 6.0. Updates `com.cosium.code:google-java-format` from 5.5 to 6.0 - [Release notes](https://github.com/Cosium/git-code-format-maven-plugin/releases) - [Commits](https://github.com/Cosium/git-code-format-maven-plugin/compare/5.5...6.0) Updates `com.cosium.code:git-code-format-maven-plugin` from 5.5 to 6.0 - [Release notes](https://github.com/Cosium/git-code-format-maven-plugin/releases) - [Commits](https://github.com/Cosium/git-code-format-maven-plugin/compare/5.5...6.0) --- updated-dependencies: - dependency-name: com.cosium.code:google-java-format dependency-version: '6.0' dependency-type: direct:production update-type: version-update:semver-major - dependency-name: com.cosium.code:git-code-format-maven-plugin dependency-version: '6.0' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cb5f43b698..027955f348 100644 --- a/pom.xml +++ b/pom.xml @@ -177,7 +177,7 @@ 2.0.61.android8 1.5.3 - 5.5 + 6.0 3.15.0 3.1.4 3.4.0 From da708714d776843a4fa02f910bbb26a27417f163 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 05:28:38 +0000 Subject: [PATCH 426/615] build(deps): Bump micrometer.version from 1.16.3 to 1.16.4 Bumps `micrometer.version` from 1.16.3 to 1.16.4. Updates `io.micrometer:micrometer-core` from 1.16.3 to 1.16.4 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.3...v1.16.4) Updates `io.micrometer:micrometer-test` from 1.16.3 to 1.16.4 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.3...v1.16.4) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.16.4 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-version: 1.16.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 7b2b677b24..c83af7bac3 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.16.3 + 1.16.4 From b4a71b4ea25df169095e0d42e6d63a51a851698f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 05:30:49 +0000 Subject: [PATCH 427/615] build(deps): Bump org.projectlombok:lombok from 1.18.42 to 1.18.44 Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.42 to 1.18.44. - [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/projectlombok/lombok/compare/v1.18.42...v1.18.44) --- updated-dependencies: - dependency-name: org.projectlombok:lombok dependency-version: 1.18.44 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7d2619801f..fafe70c323 100644 --- a/pom.xml +++ b/pom.xml @@ -233,7 +233,7 @@ 2.3.1 1.19.4 1.1.1 - 1.18.42 + 1.18.44 3.6.2 4.2.38 5.0.6 From 7d96fd114612d559f974338f5be6e788c162203a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 05:31:20 +0000 Subject: [PATCH 428/615] build(deps): Bump reactor.version from 3.8.3 to 3.8.4 Bumps `reactor.version` from 3.8.3 to 3.8.4. Updates `io.projectreactor:reactor-core` from 3.8.3 to 3.8.4 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.3...v3.8.4) Updates `io.projectreactor:reactor-test` from 3.8.3 to 3.8.4 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.3...v3.8.4) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.8.4 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.8.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index ee1e2add7c..7f2e8285f6 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.8.3 + 3.8.4 1.0.4 2.2.21 From 61c7ed8fc6e931471dcc98e60c155c8b89c337dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 05:30:00 +0000 Subject: [PATCH 429/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.29.0 to 3.30.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.29.0...v3.30.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.30.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fafe70c323..00b5ff11a0 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 1.2.8 4.0.0 6.32.0 - 3.29.0 + 3.30.0 3.29.0 0.25.4 1.0 From 259e526dc5a0e460c5aa832fb527c3c51618e7c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 05:30:37 +0000 Subject: [PATCH 430/615] build(deps): Bump mockito.version from 5.22.0 to 5.23.0 Bumps `mockito.version` from 5.22.0 to 5.23.0. Updates `org.mockito:mockito-core` from 5.22.0 to 5.23.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.22.0...v5.23.0) Updates `org.mockito:mockito-junit-jupiter` from 5.22.0 to 5.23.0 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.22.0...v5.23.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.23.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.mockito:mockito-junit-jupiter dependency-version: 5.23.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fafe70c323..3e1c334b17 100644 --- a/pom.xml +++ b/pom.xml @@ -173,7 +173,7 @@ 2.21.1 3.1.0 3.27.7 - 5.22.0 + 5.23.0 2.0.61.android8 1.5.3 From 9b47ca6d92f9b2cc2621e4f68efc0ca63c32a23e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 05:41:15 +0000 Subject: [PATCH 431/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.32.0 to 6.33.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.32.0...v6.33.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.33.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a9da29e54..e347cf97d7 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 3.2.0 1.2.8 4.0.0 - 6.32.0 + 6.33.0 3.30.0 3.29.0 0.25.4 From e692e4f97477e2b799f1d5400718d58d9a6ec3a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 05:41:27 +0000 Subject: [PATCH 432/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.29.0 to 3.30.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.29.0...v3.30.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.30.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a9da29e54..d572854eb8 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 4.0.0 6.32.0 3.30.0 - 3.29.0 + 3.30.0 0.25.4 1.0 From 088eed7a614820a21ae15ad5b3dec657fe06bf74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 05:30:24 +0000 Subject: [PATCH 433/615] build(deps): Bump org.springframework:spring-web from 7.0.5 to 7.0.6 Bumps [org.springframework:spring-web](https://github.com/spring-projects/spring-framework) from 7.0.5 to 7.0.6. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.5...v7.0.6) --- updated-dependencies: - dependency-name: org.springframework:spring-web dependency-version: 7.0.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- spring/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4b91d8fed4..2c94680b63 100644 --- a/pom.xml +++ b/pom.xml @@ -244,7 +244,7 @@ 2025.1.1 5.0.1 7.0.5 - 7.0.5 + 7.0.6 2.3.23.Final 1.18.0 diff --git a/spring/pom.xml b/spring/pom.xml index 8856f0fde3..c552c21f6c 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -31,7 +31,7 @@ 17 - 7.0.5 + 7.0.6 From 897cf0fac6da75bc875e4bcfd804d8356a9194e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 05:41:55 +0000 Subject: [PATCH 434/615] build(deps-dev): Bump org.springframework:spring-context Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 7.0.5 to 7.0.6. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.5...v7.0.6) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 7.0.6 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2c94680b63..7626d2147f 100644 --- a/pom.xml +++ b/pom.xml @@ -243,7 +243,7 @@ 3.0.2 2025.1.1 5.0.1 - 7.0.5 + 7.0.6 7.0.6 2.3.23.Final 1.18.0 From 9a7230537efc05d3e3a0d2def82d1a28d7e39fdc Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 16 Mar 2026 09:45:13 -0300 Subject: [PATCH 435/615] Validate required GraphQL variables have matching method parameters at compile time Signed-off-by: Marvin Froeder --- .../graphql/apt/GraphqlSchemaProcessor.java | 2 + .../feign/graphql/apt/QueryValidator.java | 43 +++++ .../apt/GraphqlSchemaProcessorTest.java | 149 ++++++++++++++++++ 3 files changed, 194 insertions(+) diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java index 0f6e321088..1ae168b8b3 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java @@ -234,6 +234,8 @@ private void processMethod( return; } + validator.validateVariableBindings(operation, method); + var returnTypeName = getSimpleTypeName(method.getReturnType()); if (returnTypeName != null && !isExistingExternalType(method.getReturnType(), targetPackage)) { var rootType = getRootType(operation, registry); diff --git a/graphql-apt/src/main/java/feign/graphql/apt/QueryValidator.java b/graphql-apt/src/main/java/feign/graphql/apt/QueryValidator.java index 17c5e304d0..4fefe5eab7 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/QueryValidator.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/QueryValidator.java @@ -15,13 +15,21 @@ */ package feign.graphql.apt; +import feign.Param; import graphql.GraphQLError; import graphql.language.Document; +import graphql.language.ListType; +import graphql.language.NonNullType; +import graphql.language.OperationDefinition; +import graphql.language.Type; +import graphql.language.VariableDefinition; import graphql.schema.GraphQLSchema; import graphql.validation.Validator; +import java.util.HashSet; import java.util.Locale; import javax.annotation.processing.Messager; import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; import javax.tools.Diagnostic; public class QueryValidator { @@ -58,4 +66,39 @@ public boolean validate(GraphQLSchema schema, Document document, Element methodE } return false; } + + public void validateVariableBindings(OperationDefinition operation, ExecutableElement method) { + var paramNames = new HashSet(); + for (var param : method.getParameters()) { + if (param.getAnnotation(Param.class) == null) { + paramNames.add(param.getSimpleName().toString()); + } + } + + for (VariableDefinition varDef : operation.getVariableDefinitions()) { + if (varDef.getType() instanceof NonNullType && varDef.getDefaultValue() == null) { + var varName = varDef.getName(); + if (!paramNames.contains(varName)) { + messager.printMessage( + Diagnostic.Kind.ERROR, + "Required GraphQL variable '$%s' (%s) has no corresponding method parameter. Add a parameter named '%s' or provide a default value in the query." + .formatted(varName, typeToString(varDef.getType()), varName), + method); + } + } + } + } + + private String typeToString(Type type) { + if (type instanceof NonNullType nonNullType) { + return typeToString(nonNullType.getType()) + "!"; + } + if (type instanceof ListType listType) { + return "[" + typeToString(listType.getType()) + "]"; + } + if (type instanceof graphql.language.TypeName typeName) { + return typeName.getName(); + } + return type.toString(); + } } diff --git a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java index 1ab5408fca..4f0a4ac2e0 100644 --- a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java +++ b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java @@ -672,4 +672,153 @@ interface DiffNestedApi { .contentsAsUtf8String() .contains("public record Location(String sector, String region) {}"); } + + @Test + void missingRequiredVariableReportsError() { + var source = + JavaFileObjects.forSourceString( + "test.MissingVarApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface MissingVarApi { + @GraphqlQuery("query getChar($id: ID!) { character(id: $id) { id name } }") + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("Required GraphQL variable '$id'"); + } + + @Test + void requiredVariableWithDefaultValueIsOptional() { + var source = + JavaFileObjects.forSourceString( + "test.DefaultVarApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface DefaultVarApi { + @GraphqlQuery("query getChar($id: ID! = \\"1\\") { character(id: $id) { id name } }") + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + } + + @Test + void nullableVariableIsOptional() { + var source = + JavaFileObjects.forSourceString( + "test.NullableVarApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface NullableVarApi { + @GraphqlQuery(\""" + query listChars($filter: CharacterFilter) { + characters(filter: $filter) { id name } + }\""") + CharResult listCharacters(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + } + + @Test + void paramAnnotationNotCountedAsVariable() { + var source = + JavaFileObjects.forSourceString( + "test.ParamApi", + """ + package test; + + import feign.Param; + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface ParamApi { + @GraphqlQuery("query getChar($id: ID!) { character(id: $id) { id name } }") + CharResult getCharacter(@Param("auth") String token); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("Required GraphQL variable '$id'"); + } + + @Test + void requiredVariableWithMatchingParameterSucceeds() { + var source = + JavaFileObjects.forSourceString( + "test.MatchApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface MatchApi { + @GraphqlQuery("query getChar($id: ID!) { character(id: $id) { id name } }") + CharResult getCharacter(String id); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + } + + @Test + void multipleRequiredVariablesMissing() { + var source = + JavaFileObjects.forSourceString( + "test.MultiMissingApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface MultiMissingApi { + @GraphqlQuery(\""" + mutation updateEpisode($id: ID!, $episode: Episode!) { + updateEpisode(id: $id, episode: $episode) { id appearsIn } + }\""") + EpisodeResult updateEpisode(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("Required GraphQL variable '$id'"); + assertThat(compilation).hadErrorContaining("Required GraphQL variable '$episode'"); + } } From 3fc6b1add08c2acab6a09c02e8564acfb53e77ad Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 16 Mar 2026 11:31:41 -0300 Subject: [PATCH 436/615] Add test for inline input missing required field validation Signed-off-by: Marvin Froeder --- .../apt/GraphqlSchemaProcessorTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java index 4f0a4ac2e0..eee18234ae 100644 --- a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java +++ b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java @@ -821,4 +821,31 @@ mutation updateEpisode($id: ID!, $episode: Episode!) { assertThat(compilation).hadErrorContaining("Required GraphQL variable '$id'"); assertThat(compilation).hadErrorContaining("Required GraphQL variable '$episode'"); } + + @Test + void inlineInputMissingRequiredFieldReportsError() { + var source = + JavaFileObjects.forSourceString( + "test.InlineApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface InlineApi { + @GraphqlQuery(\""" + mutation create($name: String!) { + createCharacter(input: { name: $name }) { id } + }\""") + Object create(String name); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("email"); + } } From 6e6c3220ee159e320a9419847204b936e24aaacf Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 16 Mar 2026 17:31:48 -0300 Subject: [PATCH 437/615] Add Optional wrapping for nullable fields and configurable type annotations on generated GraphQL types Signed-off-by: Marvin Froeder --- .../graphql/apt/GraphqlSchemaProcessor.java | 61 ++++ .../feign/graphql/apt/GraphqlTypeMapper.java | 18 +- .../graphql/apt/TypeAnnotationConfig.java | 57 +++ .../java/feign/graphql/apt/TypeGenerator.java | 40 +- .../apt/GraphqlSchemaProcessorTest.java | 344 +++++++++++++++++- .../main/java/feign/graphql/GraphqlQuery.java | 6 + .../java/feign/graphql/GraphqlSchema.java | 6 + .../src/main/java/feign/graphql/Toggle.java | 22 ++ 8 files changed, 538 insertions(+), 16 deletions(-) create mode 100644 graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java create mode 100644 graphql/src/main/java/feign/graphql/Toggle.java diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java index 1ae168b8b3..a2cb55141b 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java @@ -20,6 +20,7 @@ import feign.graphql.GraphqlQuery; import feign.graphql.GraphqlSchema; import feign.graphql.Scalar; +import feign.graphql.Toggle; import graphql.language.Document; import graphql.language.Field; import graphql.language.FieldDefinition; @@ -35,6 +36,7 @@ import graphql.schema.idl.SchemaParser; import graphql.schema.idl.TypeDefinitionRegistry; import graphql.schema.idl.UnExecutableSchemaGenerator; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -52,6 +54,7 @@ import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.MirroredTypesException; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; @@ -117,6 +120,8 @@ private void processInterface(TypeElement typeElement) { var validator = new QueryValidator(messager); var generator = new TypeGenerator(filer, messager, registry, typeMapper, targetPackage); + var classConfig = resolveClassConfig(schemaAnnotation); + for (var enclosed : typeElement.getEnclosedElements()) { if (!(enclosed instanceof ExecutableElement method)) { continue; @@ -126,6 +131,9 @@ private void processInterface(TypeElement typeElement) { continue; } + var methodConfig = resolveMethodConfig(queryAnnotation, classConfig); + generator.setAnnotationConfig(methodConfig); + processMethod( method, queryAnnotation, @@ -434,6 +442,59 @@ private TypeMirror unwrapListTypeMirror(TypeMirror typeMirror) { return typeMirror; } + private TypeAnnotationConfig resolveClassConfig(GraphqlSchema annotation) { + var fqns = extractTypeAnnotationFqns(annotation); + var rawAnnotations = annotation.rawTypeAnnotations(); + return TypeAnnotationConfig.resolve(fqns, rawAnnotations, annotation.useOptional()); + } + + private TypeAnnotationConfig resolveMethodConfig( + GraphqlQuery annotation, TypeAnnotationConfig classConfig) { + var methodFqns = extractTypeAnnotationFqns(annotation); + var methodRaw = annotation.rawTypeAnnotations(); + var methodToggle = annotation.useOptional(); + + var useOptional = + methodToggle == Toggle.INHERIT ? classConfig.useOptional() : methodToggle == Toggle.TRUE; + + boolean hasMethodAnnotations = !methodFqns.isEmpty() || methodRaw.length > 0; + if (!hasMethodAnnotations) { + if (useOptional == classConfig.useOptional()) { + return classConfig; + } + return new TypeAnnotationConfig( + classConfig.imports(), classConfig.annotations(), useOptional); + } + + return TypeAnnotationConfig.resolve(methodFqns, methodRaw, useOptional); + } + + private List extractTypeAnnotationFqns(GraphqlSchema annotation) { + try { + var classes = annotation.typeAnnotations(); + var result = new ArrayList(classes.length); + for (var cls : classes) { + result.add(cls.getCanonicalName()); + } + return result; + } catch (MirroredTypesException e) { + return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); + } + } + + private List extractTypeAnnotationFqns(GraphqlQuery annotation) { + try { + var classes = annotation.typeAnnotations(); + var result = new ArrayList(classes.length); + for (var cls : classes) { + result.add(cls.getCanonicalName()); + } + return result; + } catch (MirroredTypesException e) { + return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); + } + } + private String getPackageName(TypeElement typeElement) { var enclosing = typeElement.getEnclosingElement(); while (enclosing != null && !(enclosing instanceof PackageElement)) { diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java index d9be1fa18f..94ef2793db 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; public class GraphqlTypeMapper { @@ -44,11 +45,24 @@ public GraphqlTypeMapper(String targetPackage, Map customScala } public TypeName map(Type type) { + return map(type, false); + } + + public TypeName map(Type type, boolean useOptional) { + boolean nullable = !(type instanceof NonNullType); + var mapped = mapInner(type); + if (useOptional && nullable) { + return ParameterizedTypeName.get(ClassName.get(Optional.class), mapped); + } + return mapped; + } + + private TypeName mapInner(Type type) { if (type instanceof NonNullType nullType) { - return map(nullType.getType()); + return mapInner(nullType.getType()); } if (type instanceof ListType listType) { - var elementType = map(listType.getType()); + var elementType = mapInner(listType.getType()); return ParameterizedTypeName.get(ClassName.get(List.class), elementType); } if (type instanceof graphql.language.TypeName name) { diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java new file mode 100644 index 0000000000..b57c836a16 --- /dev/null +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql.apt; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +record TypeAnnotationConfig(Set imports, List annotations, boolean useOptional) { + + static final TypeAnnotationConfig EMPTY = new TypeAnnotationConfig(Set.of(), List.of(), false); + + static TypeAnnotationConfig resolve( + List typeAnnotationFqns, String[] rawTypeAnnotations, boolean useOptional) { + + var rawSimpleNames = new HashSet(); + for (var raw : rawTypeAnnotations) { + var stripped = raw.startsWith("@") ? raw.substring(1) : raw; + var parenIdx = stripped.indexOf('('); + rawSimpleNames.add(parenIdx > 0 ? stripped.substring(0, parenIdx).trim() : stripped.trim()); + } + + var imports = new TreeSet(); + var annotations = new ArrayList(); + + for (var fqn : typeAnnotationFqns) { + var simpleName = fqn.substring(fqn.lastIndexOf('.') + 1); + if (!fqn.startsWith("java.lang.")) { + imports.add(fqn); + } + if (!rawSimpleNames.contains(simpleName)) { + annotations.add("@" + simpleName); + } + } + + for (var raw : rawTypeAnnotations) { + annotations.add(raw.startsWith("@") ? raw : "@" + raw); + } + + return new TypeAnnotationConfig(imports, annotations, useOptional); + } +} diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java index ce30adff65..9ff208acac 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java @@ -38,6 +38,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Queue; import java.util.Set; import java.util.TreeSet; @@ -59,6 +60,7 @@ public class TypeGenerator { private final Set generatedTypes = new HashSet<>(); private final Queue pendingTypes = new ArrayDeque<>(); private final Map resultTypeSignatures = new HashMap<>(); + private TypeAnnotationConfig annotationConfig = TypeAnnotationConfig.EMPTY; public TypeGenerator( Filer filer, @@ -73,6 +75,10 @@ public TypeGenerator( this.targetPackage = targetPackage; } + public void setAnnotationConfig(TypeAnnotationConfig config) { + this.annotationConfig = config; + } + public void generateResultType( String className, SelectionSet selectionSet, @@ -151,10 +157,11 @@ private ResultTypeDefinition buildResultType( innerTypes.add(innerTree); } } - var nestedType = wrapType(fieldType, ClassName.get("", nestedClassName)); + var nestedType = + wrapType(fieldType, ClassName.get("", nestedClassName), annotationConfig.useOptional()); fields.add(toRecordField(fieldName, nestedType)); } else { - var javaType = typeMapper.map(fieldType); + var javaType = typeMapper.map(fieldType, annotationConfig.useOptional()); fields.add(toRecordField(fieldName, javaType)); enqueueIfNonScalar(rawTypeName); } @@ -179,6 +186,7 @@ private void writeResultRecord(ResultTypeDefinition tree, Element element) { var imports = new TreeSet(); collectAllImports(tree, imports); + imports.addAll(annotationConfig.imports()); if (!imports.isEmpty()) { for (var imp : imports) { out.println("import " + imp + ";"); @@ -204,6 +212,10 @@ private void writeRecordBody(PrintWriter out, ResultTypeDefinition tree, String .map(f -> f.typeString + " " + f.name) .collect(Collectors.joining(", ")); + for (var annotation : annotationConfig.annotations()) { + out.println(indent + annotation); + } + if (tree.innerTypes.isEmpty()) { out.println(indent + "public record " + tree.className + "(" + params + ") {}"); } else { @@ -280,7 +292,7 @@ public void generateInputType(String className, String graphqlTypeName, Element for (var valueDef : inputDef.getInputValueDefinitions()) { var fieldName = valueDef.getName(); var fieldType = valueDef.getType(); - var javaType = typeMapper.map(fieldType); + var javaType = typeMapper.map(fieldType, annotationConfig.useOptional()); fields.add(toRecordField(fieldName, javaType)); var rawTypeName = unwrapTypeName(fieldType); @@ -343,7 +355,7 @@ private void generateFullObjectType( for (var fieldDef : objectDef.getFieldDefinitions()) { var fieldName = fieldDef.getName(); - var javaType = typeMapper.map(fieldDef.getType()); + var javaType = typeMapper.map(fieldDef.getType(), annotationConfig.useOptional()); fields.add(toRecordField(fieldName, javaType)); var rawTypeName = unwrapTypeName(fieldDef.getType()); @@ -382,13 +394,22 @@ private String unwrapTypeName(Type type) { return "String"; } - private TypeName wrapType(Type schemaType, TypeName innerType) { + private TypeName wrapType(Type schemaType, TypeName innerType, boolean useOptional) { + boolean nullable = !(schemaType instanceof NonNullType); + var wrapped = wrapTypeInner(schemaType, innerType); + if (useOptional && nullable) { + return ParameterizedTypeName.get(ClassName.get(Optional.class), wrapped); + } + return wrapped; + } + + private TypeName wrapTypeInner(Type schemaType, TypeName innerType) { if (schemaType instanceof NonNullType type) { - return wrapType(type.getType(), innerType); + return wrapTypeInner(type.getType(), innerType); } if (schemaType instanceof ListType type) { return ParameterizedTypeName.get( - ClassName.get(List.class), wrapType(type.getType(), innerType)); + ClassName.get(List.class), wrapTypeInner(type.getType(), innerType)); } return innerType; } @@ -490,6 +511,7 @@ private void writeRecord(String className, List fields, Element ele } var imports = collectImports(fields); + imports.addAll(annotationConfig.imports()); if (!imports.isEmpty()) { for (var imp : imports) { out.println("import " + imp + ";"); @@ -497,6 +519,10 @@ private void writeRecord(String className, List fields, Element ele out.println(); } + for (var annotation : annotationConfig.annotations()) { + out.println(annotation); + } + var params = fields.stream().map(f -> f.typeString + " " + f.name).collect(Collectors.joining(", ")); diff --git a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java index eee18234ae..511bea1010 100644 --- a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java +++ b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java @@ -126,7 +126,8 @@ interface NestedApi { assertThat(compilation) .generatedSourceFile("test.CharacterResult") .contentsAsUtf8String() - .contains("public record Location(String planet, String sector, String region) {}"); + .contains( + "public record Location(Optional planet, Optional sector, Optional region) {}"); } @Test @@ -625,10 +626,13 @@ interface InnerApi { assertThat(compilation).generatedSourceFile("test.ShipResult").contentsAsUtf8String(); contents.contains( - "public record ShipResult(String id, String name, Location location, Specs specs)"); - contents.contains("public record Location(String planet, Coordinates coordinates)"); - contents.contains("public record Coordinates(Double latitude, Double longitude) {}"); - contents.contains("public record Specs(Integer lengthMeters, String classification) {}"); + "public record ShipResult(String id, String name, Optional location, Optional specs)"); + contents.contains( + "public record Location(Optional planet, Optional coordinates)"); + contents.contains( + "public record Coordinates(Optional latitude, Optional longitude) {}"); + contents.contains( + "public record Specs(Optional lengthMeters, Optional classification) {}"); } @Test @@ -665,12 +669,12 @@ interface DiffNestedApi { assertThat(compilation) .generatedSourceFile("test.CharByPlanet") .contentsAsUtf8String() - .contains("public record Location(String planet) {}"); + .contains("public record Location(Optional planet) {}"); assertThat(compilation) .generatedSourceFile("test.CharByRegion") .contentsAsUtf8String() - .contains("public record Location(String sector, String region) {}"); + .contains("public record Location(Optional sector, Optional region) {}"); } @Test @@ -848,4 +852,330 @@ mutation create($name: String!) { assertThat(compilation).failed(); assertThat(compilation).hadErrorContaining("email"); } + + @Test + void useOptionalDisabledGeneratesPlainTypes() { + var source = + JavaFileObjects.forSourceString( + "test.NoOptionalApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface NoOptionalApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email location { planet } } } + \""") + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains( + "public record CharResult(String id, String name, String email, Location location)"); + contents.contains("public record Location(String planet) {}"); + } + + @Test + void useOptionalDefaultWrapsNullableFields() { + var source = + JavaFileObjects.forSourceString( + "test.OptionalApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface OptionalApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email location { planet } } } + \""") + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("import java.util.Optional;"); + contents.contains( + "String id, String name, Optional email, Optional location"); + contents.contains("public record Location(Optional planet) {}"); + } + + @Test + void useOptionalMethodOverridesClassLevel() { + var source = + JavaFileObjects.forSourceString( + "test.OverrideApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.Toggle; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface OverrideApi { + @GraphqlQuery(value = \""" + { character(id: "1") { id name email } } + \""", useOptional = Toggle.TRUE) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("import java.util.Optional;"); + contents.contains("String id, String name, Optional email"); + } + + @Test + void typeAnnotationsAddedToGeneratedRecords() { + var source = + JavaFileObjects.forSourceString( + "test.AnnotatedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + typeAnnotations = {Deprecated.class}) + interface AnnotatedApi { + @GraphqlQuery(\""" + mutation createCharacter($input: CreateCharacterInput!) { + createCharacter(input: $input) { id name } + }\""") + CreateResult createCharacter(CreateCharacterInput input); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.CreateResult") + .contentsAsUtf8String() + .contains("@Deprecated"); + assertThat(compilation) + .generatedSourceFile("test.CreateCharacterInput") + .contentsAsUtf8String() + .contains("@Deprecated"); + } + + @Test + void rawTypeAnnotationsAppendedToGeneratedRecords() { + var source = + JavaFileObjects.forSourceString( + "test.RawAnnotatedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + rawTypeAnnotations = {"@Deprecated"}) + interface RawAnnotatedApi { + @GraphqlQuery(\""" + { character(id: "1") { id name } } + \""") + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.CharResult") + .contentsAsUtf8String() + .contains("@Deprecated"); + } + + @Test + void collisionBetweenTypeAndRawAnnotationUsesClassAsImportOnly() { + var source = + JavaFileObjects.forSourceString( + "test.CollisionApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + typeAnnotations = {Deprecated.class}, + rawTypeAnnotations = {"@Deprecated(since = \\"1.0\\")"}) + interface CollisionApi { + @GraphqlQuery(\""" + { character(id: "1") { id name } } + \""") + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("@Deprecated(since = \"1.0\")"); + } + + @Test + void methodLevelAnnotationsOverrideClassLevel() { + var source = + JavaFileObjects.forSourceString( + "test.MethodOverrideApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + typeAnnotations = {Deprecated.class}) + interface MethodOverrideApi { + @GraphqlQuery(value = \""" + { character(id: "1") { id name } } + \""", rawTypeAnnotations = {"@SuppressWarnings(\\"unchecked\\")"}) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("@SuppressWarnings(\"unchecked\")"); + } + + @Test + void optionalOnInputTypeWrapsNullableFields() { + var source = + JavaFileObjects.forSourceString( + "test.OptionalInputApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("test-schema.graphql") + interface OptionalInputApi { + @GraphqlQuery(\""" + mutation createCharacter($input: CreateCharacterInput!) { + createCharacter(input: $input) { id } + }\""") + Object createCharacter(CreateCharacterInput input); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation) + .generatedSourceFile("test.CreateCharacterInput") + .contentsAsUtf8String(); + contents.contains("String name, String email"); + contents.contains("Optional appearsIn"); + contents.contains("Optional location"); + contents.contains("Optional> tags"); + contents.contains("Optional starshipId"); + } + + @Test + void mixedTypeAndRawAnnotationsWithoutCollision() { + var source = + JavaFileObjects.forSourceString( + "test.MixedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + typeAnnotations = {Deprecated.class}, + rawTypeAnnotations = {"@SuppressWarnings(\\"unchecked\\")"}) + interface MixedApi { + @GraphqlQuery(\""" + { character(id: "1") { id name } } + \""") + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("@Deprecated"); + contents.contains("@SuppressWarnings(\"unchecked\")"); + } + + @Test + void annotationsAppliedToNestedResultRecords() { + var source = + JavaFileObjects.forSourceString( + "test.NestedAnnotatedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + typeAnnotations = {Deprecated.class}) + interface NestedAnnotatedApi { + @GraphqlQuery(\""" + { + starship(id: "1") { + id name + location { planet coordinates { latitude longitude } } + } + }\""") + ShipResult getShip(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.ShipResult").contentsAsUtf8String(); + contents.contains("@Deprecated\npublic record ShipResult("); + contents.contains("@Deprecated\n public record Location("); + contents.contains("@Deprecated\n public record Coordinates("); + } } diff --git a/graphql/src/main/java/feign/graphql/GraphqlQuery.java b/graphql/src/main/java/feign/graphql/GraphqlQuery.java index b02987e34b..59d12d7150 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlQuery.java +++ b/graphql/src/main/java/feign/graphql/GraphqlQuery.java @@ -27,4 +27,10 @@ public @interface GraphqlQuery { String value(); + + Toggle useOptional() default Toggle.INHERIT; + + Class[] typeAnnotations() default {}; + + String[] rawTypeAnnotations() default {}; } diff --git a/graphql/src/main/java/feign/graphql/GraphqlSchema.java b/graphql/src/main/java/feign/graphql/GraphqlSchema.java index 695ae21ff2..e605f0c745 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlSchema.java +++ b/graphql/src/main/java/feign/graphql/GraphqlSchema.java @@ -29,4 +29,10 @@ String value(); boolean generateTypes() default true; + + boolean useOptional() default true; + + Class[] typeAnnotations() default {}; + + String[] rawTypeAnnotations() default {}; } diff --git a/graphql/src/main/java/feign/graphql/Toggle.java b/graphql/src/main/java/feign/graphql/Toggle.java new file mode 100644 index 0000000000..9dd7b6957d --- /dev/null +++ b/graphql/src/main/java/feign/graphql/Toggle.java @@ -0,0 +1,22 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +public enum Toggle { + INHERIT, + TRUE, + FALSE +} From d44b76edb2089622d1e70ceb43a2f844ff4d45ed Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 16 Mar 2026 18:40:46 -0300 Subject: [PATCH 438/615] Add @GraphqlField for field-level annotations/type overrides, non-null field annotations, and uses for imports Signed-off-by: Marvin Froeder --- .../graphql/apt/GraphqlSchemaProcessor.java | 162 ++++- .../graphql/apt/TypeAnnotationConfig.java | 127 +++- .../java/feign/graphql/apt/TypeGenerator.java | 75 ++- .../apt/GraphqlSchemaProcessorTest.java | 612 ++++++++++++++++++ graphql/README.md | 138 ++++ .../main/java/feign/graphql/GraphqlField.java | 38 ++ .../java/feign/graphql/GraphqlFields.java | 30 + .../main/java/feign/graphql/GraphqlQuery.java | 4 + .../java/feign/graphql/GraphqlSchema.java | 6 + 9 files changed, 1161 insertions(+), 31 deletions(-) create mode 100644 graphql/src/main/java/feign/graphql/GraphqlField.java create mode 100644 graphql/src/main/java/feign/graphql/GraphqlFields.java diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java index a2cb55141b..af49d31397 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java @@ -17,6 +17,7 @@ import com.google.auto.service.AutoService; import com.squareup.javapoet.TypeName; +import feign.graphql.GraphqlField; import feign.graphql.GraphqlQuery; import feign.graphql.GraphqlSchema; import feign.graphql.Scalar; @@ -41,6 +42,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; @@ -50,10 +52,12 @@ import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.MirroredTypeException; import javax.lang.model.type.MirroredTypesException; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; @@ -120,7 +124,8 @@ private void processInterface(TypeElement typeElement) { var validator = new QueryValidator(messager); var generator = new TypeGenerator(filer, messager, registry, typeMapper, targetPackage); - var classConfig = resolveClassConfig(schemaAnnotation); + var classFieldAnnotations = extractFieldAnnotations(typeElement); + var classConfig = resolveClassConfig(schemaAnnotation, classFieldAnnotations); for (var enclosed : typeElement.getEnclosedElements()) { if (!(enclosed instanceof ExecutableElement method)) { @@ -131,7 +136,7 @@ private void processInterface(TypeElement typeElement) { continue; } - var methodConfig = resolveMethodConfig(queryAnnotation, classConfig); + var methodConfig = resolveMethodConfig(method, queryAnnotation, classConfig); generator.setAnnotationConfig(methodConfig); processMethod( @@ -442,14 +447,80 @@ private TypeMirror unwrapListTypeMirror(TypeMirror typeMirror) { return typeMirror; } - private TypeAnnotationConfig resolveClassConfig(GraphqlSchema annotation) { + private TypeAnnotationConfig resolveClassConfig( + GraphqlSchema annotation, + Map classFieldAnnotations) { var fqns = extractTypeAnnotationFqns(annotation); var rawAnnotations = annotation.rawTypeAnnotations(); - return TypeAnnotationConfig.resolve(fqns, rawAnnotations, annotation.useOptional()); + var usesFqns = extractUsesFqns(annotation); + var nonNullFqns = extractNonNullTypeAnnotationFqns(annotation); + var nonNullRaw = annotation.nonNullRawTypeAnnotations(); + var config = + TypeAnnotationConfig.resolve( + fqns, + rawAnnotations, + annotation.useOptional(), + classFieldAnnotations, + nonNullFqns, + nonNullRaw); + if (usesFqns.isEmpty()) { + return config; + } + var mergedImports = new TreeSet<>(config.imports()); + for (var fqn : usesFqns) { + if (!fqn.startsWith("java.lang.")) { + mergedImports.add(fqn); + } + } + return new TypeAnnotationConfig( + mergedImports, + config.annotations(), + config.useOptional(), + config.fieldAnnotations(), + config.nonNullAnnotations()); + } + + private List extractNonNullTypeAnnotationFqns(GraphqlSchema annotation) { + try { + var classes = annotation.nonNullTypeAnnotations(); + var result = new ArrayList(classes.length); + for (var cls : classes) { + result.add(cls.getCanonicalName()); + } + return result; + } catch (MirroredTypesException e) { + return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); + } + } + + private List extractNonNullTypeAnnotationFqns(GraphqlQuery annotation) { + try { + var classes = annotation.nonNullTypeAnnotations(); + var result = new ArrayList(classes.length); + for (var cls : classes) { + result.add(cls.getCanonicalName()); + } + return result; + } catch (MirroredTypesException e) { + return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); + } + } + + private List extractUsesFqns(GraphqlSchema annotation) { + try { + var classes = annotation.uses(); + var result = new ArrayList(classes.length); + for (var cls : classes) { + result.add(cls.getCanonicalName()); + } + return result; + } catch (MirroredTypesException e) { + return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); + } } private TypeAnnotationConfig resolveMethodConfig( - GraphqlQuery annotation, TypeAnnotationConfig classConfig) { + ExecutableElement method, GraphqlQuery annotation, TypeAnnotationConfig classConfig) { var methodFqns = extractTypeAnnotationFqns(annotation); var methodRaw = annotation.rawTypeAnnotations(); var methodToggle = annotation.useOptional(); @@ -457,16 +528,89 @@ private TypeAnnotationConfig resolveMethodConfig( var useOptional = methodToggle == Toggle.INHERIT ? classConfig.useOptional() : methodToggle == Toggle.TRUE; + var methodFieldAnnotations = extractFieldAnnotations(method); + var fieldAnnotations = + TypeAnnotationConfig.FieldAnnotations.merge( + classConfig.fieldAnnotations(), methodFieldAnnotations); + + var methodNonNullFqns = extractNonNullTypeAnnotationFqns(annotation); + var methodNonNullRaw = annotation.nonNullRawTypeAnnotations(); + boolean hasMethodNonNull = !methodNonNullFqns.isEmpty() || methodNonNullRaw.length > 0; + var resolvedNonNull = hasMethodNonNull ? null : classConfig.nonNullAnnotations(); + boolean hasMethodAnnotations = !methodFqns.isEmpty() || methodRaw.length > 0; - if (!hasMethodAnnotations) { - if (useOptional == classConfig.useOptional()) { + if (!hasMethodAnnotations && !hasMethodNonNull) { + if (useOptional == classConfig.useOptional() + && fieldAnnotations.equals(classConfig.fieldAnnotations())) { return classConfig; } + var mergedImports = new TreeSet<>(classConfig.imports()); + for (var fa : fieldAnnotations.values()) { + mergedImports.addAll(fa.imports()); + } + return new TypeAnnotationConfig( + mergedImports, + classConfig.annotations(), + useOptional, + fieldAnnotations, + classConfig.nonNullAnnotations()); + } + + var nonNullFqns = hasMethodNonNull ? methodNonNullFqns : List.of(); + var nonNullRaw = hasMethodNonNull ? methodNonNullRaw : new String[0]; + var config = + TypeAnnotationConfig.resolve( + methodFqns, methodRaw, useOptional, fieldAnnotations, nonNullFqns, nonNullRaw); + + if (resolvedNonNull != null && !resolvedNonNull.isEmpty()) { + var mergedImports = new TreeSet<>(config.imports()); + mergedImports.addAll(classConfig.imports()); return new TypeAnnotationConfig( - classConfig.imports(), classConfig.annotations(), useOptional); + mergedImports, config.annotations(), useOptional, fieldAnnotations, resolvedNonNull); + } + + return config; + } + + private Map extractFieldAnnotations( + Element method) { + var fieldAnnotations = new HashMap(); + var graphqlFields = method.getAnnotationsByType(GraphqlField.class); + for (var gf : graphqlFields) { + var fqns = extractFieldTypeAnnotationFqns(gf); + var typeOverride = extractFieldTypeOverride(gf); + var resolved = + TypeAnnotationConfig.FieldAnnotations.resolve( + fqns, gf.rawTypeAnnotations(), typeOverride); + fieldAnnotations.put(gf.name(), resolved); } + return fieldAnnotations; + } - return TypeAnnotationConfig.resolve(methodFqns, methodRaw, useOptional); + private String extractFieldTypeOverride(GraphqlField annotation) { + try { + var cls = annotation.type(); + if (cls == Void.class) { + return null; + } + return cls.getCanonicalName(); + } catch (MirroredTypeException e) { + var fqn = e.getTypeMirror().toString(); + return "java.lang.Void".equals(fqn) ? null : fqn; + } + } + + private List extractFieldTypeAnnotationFqns(GraphqlField annotation) { + try { + var classes = annotation.typeAnnotations(); + var result = new ArrayList(classes.length); + for (var cls : classes) { + result.add(cls.getCanonicalName()); + } + return result; + } catch (MirroredTypesException e) { + return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); + } } private List extractTypeAnnotationFqns(GraphqlSchema annotation) { diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java index b57c836a16..9025601960 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java @@ -16,17 +16,50 @@ package feign.graphql.apt; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeSet; -record TypeAnnotationConfig(Set imports, List annotations, boolean useOptional) { +record TypeAnnotationConfig( + Set imports, + List annotations, + boolean useOptional, + Map fieldAnnotations, + List nonNullAnnotations) { - static final TypeAnnotationConfig EMPTY = new TypeAnnotationConfig(Set.of(), List.of(), false); + static final TypeAnnotationConfig EMPTY = + new TypeAnnotationConfig(Set.of(), List.of(), false, Map.of(), List.of()); static TypeAnnotationConfig resolve( List typeAnnotationFqns, String[] rawTypeAnnotations, boolean useOptional) { + return resolve( + typeAnnotationFqns, rawTypeAnnotations, useOptional, Map.of(), List.of(), new String[0]); + } + + static TypeAnnotationConfig resolve( + List typeAnnotationFqns, + String[] rawTypeAnnotations, + boolean useOptional, + Map fieldAnnotations) { + return resolve( + typeAnnotationFqns, + rawTypeAnnotations, + useOptional, + fieldAnnotations, + List.of(), + new String[0]); + } + + static TypeAnnotationConfig resolve( + List typeAnnotationFqns, + String[] rawTypeAnnotations, + boolean useOptional, + Map fieldAnnotations, + List nonNullFqns, + String[] nonNullRawAnnotations) { var rawSimpleNames = new HashSet(); for (var raw : rawTypeAnnotations) { @@ -52,6 +85,94 @@ static TypeAnnotationConfig resolve( annotations.add(raw.startsWith("@") ? raw : "@" + raw); } - return new TypeAnnotationConfig(imports, annotations, useOptional); + for (var fa : fieldAnnotations.values()) { + imports.addAll(fa.imports()); + } + + var nonNullResolved = resolveAnnotationList(nonNullFqns, nonNullRawAnnotations, imports); + + return new TypeAnnotationConfig( + imports, annotations, useOptional, fieldAnnotations, nonNullResolved); + } + + private static List resolveAnnotationList( + List fqns, String[] rawAnnotations, Set imports) { + var rawSimpleNames = new HashSet(); + for (var raw : rawAnnotations) { + var stripped = raw.startsWith("@") ? raw.substring(1) : raw; + var parenIdx = stripped.indexOf('('); + rawSimpleNames.add(parenIdx > 0 ? stripped.substring(0, parenIdx).trim() : stripped.trim()); + } + + var annotations = new ArrayList(); + + for (var fqn : fqns) { + var simpleName = fqn.substring(fqn.lastIndexOf('.') + 1); + if (!fqn.startsWith("java.lang.")) { + imports.add(fqn); + } + if (!rawSimpleNames.contains(simpleName)) { + annotations.add("@" + simpleName); + } + } + + for (var raw : rawAnnotations) { + annotations.add(raw.startsWith("@") ? raw : "@" + raw); + } + + return annotations; + } + + record FieldAnnotations(Set imports, List annotations, String typeOverride) { + + static FieldAnnotations resolve( + List fqns, String[] rawAnnotations, String typeOverride) { + var rawSimpleNames = new HashSet(); + for (var raw : rawAnnotations) { + var stripped = raw.startsWith("@") ? raw.substring(1) : raw; + var parenIdx = stripped.indexOf('('); + rawSimpleNames.add(parenIdx > 0 ? stripped.substring(0, parenIdx).trim() : stripped.trim()); + } + + var imports = new TreeSet(); + var annotations = new ArrayList(); + + for (var fqn : fqns) { + var simpleName = fqn.substring(fqn.lastIndexOf('.') + 1); + if (!fqn.startsWith("java.lang.")) { + imports.add(fqn); + } + if (!rawSimpleNames.contains(simpleName)) { + annotations.add("@" + simpleName); + } + } + + for (var raw : rawAnnotations) { + annotations.add(raw.startsWith("@") ? raw : "@" + raw); + } + + if (typeOverride != null) { + var simpleName = typeOverride.substring(typeOverride.lastIndexOf('.') + 1); + if (!typeOverride.startsWith("java.lang.")) { + imports.add(typeOverride); + } + return new FieldAnnotations(imports, annotations, simpleName); + } + + return new FieldAnnotations(imports, annotations, null); + } + + static Map merge( + Map classLevel, Map methodLevel) { + if (methodLevel.isEmpty()) { + return classLevel; + } + if (classLevel.isEmpty()) { + return methodLevel; + } + var merged = new HashMap<>(classLevel); + merged.putAll(methodLevel); + return merged; + } } } diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java index 9ff208acac..1a4c8392bb 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java @@ -119,7 +119,7 @@ public void generateResultType( } resultTypeSignatures.put(className, new ResultTypeUsage(signature, fields, element)); - var tree = buildResultType(className, selectionSet, parentType); + var tree = buildResultType(className, selectionSet, parentType, ""); if (tree == null) { return; } @@ -129,7 +129,10 @@ public void generateResultType( } private ResultTypeDefinition buildResultType( - String className, SelectionSet selectionSet, ObjectTypeDefinition parentType) { + String className, + SelectionSet selectionSet, + ObjectTypeDefinition parentType, + String pathPrefix) { var fields = new ArrayList(); var innerTypes = new ArrayList(); @@ -148,27 +151,32 @@ private ResultTypeDefinition buildResultType( if (field.getSelectionSet() != null && !field.getSelectionSet().getSelections().isEmpty()) { var nestedClassName = capitalize(fieldName); + var nestedPath = pathPrefix.isEmpty() ? fieldName : pathPrefix + "." + fieldName; var nestedObjectType = registry.getType(rawTypeName, ObjectTypeDefinition.class).orElse(null); if (nestedObjectType != null) { var innerTree = - buildResultType(nestedClassName, field.getSelectionSet(), nestedObjectType); + buildResultType( + nestedClassName, field.getSelectionSet(), nestedObjectType, nestedPath); if (innerTree != null) { innerTypes.add(innerTree); } } var nestedType = wrapType(fieldType, ClassName.get("", nestedClassName), annotationConfig.useOptional()); - fields.add(toRecordField(fieldName, nestedType)); + var fieldNonNull = fieldType instanceof NonNullType; + fields.add(toRecordField(fieldName, nestedType, fieldNonNull)); } else { var javaType = typeMapper.map(fieldType, annotationConfig.useOptional()); - fields.add(toRecordField(fieldName, javaType)); + var fieldNonNull = fieldType instanceof NonNullType; + fields.add(toRecordField(fieldName, javaType, fieldNonNull)); enqueueIfNonScalar(rawTypeName); } } var def = new ResultTypeDefinition(); def.className = className; + def.fieldName = pathPrefix; def.fields = fields; def.innerTypes = innerTypes; return def; @@ -207,9 +215,10 @@ private void writeResultRecord(ResultTypeDefinition tree, Element element) { } private void writeRecordBody(PrintWriter out, ResultTypeDefinition tree, String indent) { + var pathPrefix = tree.fieldName; var params = tree.fields.stream() - .map(f -> f.typeString + " " + f.name) + .map(f -> formatFieldParam(f, pathPrefix)) .collect(Collectors.joining(", ")); for (var annotation : annotationConfig.annotations()) { @@ -293,7 +302,8 @@ public void generateInputType(String className, String graphqlTypeName, Element var fieldName = valueDef.getName(); var fieldType = valueDef.getType(); var javaType = typeMapper.map(fieldType, annotationConfig.useOptional()); - fields.add(toRecordField(fieldName, javaType)); + var fieldNonNull = fieldType instanceof NonNullType; + fields.add(toRecordField(fieldName, javaType, fieldNonNull)); var rawTypeName = unwrapTypeName(fieldType); enqueueIfNonScalar(rawTypeName); @@ -355,8 +365,10 @@ private void generateFullObjectType( for (var fieldDef : objectDef.getFieldDefinitions()) { var fieldName = fieldDef.getName(); - var javaType = typeMapper.map(fieldDef.getType(), annotationConfig.useOptional()); - fields.add(toRecordField(fieldName, javaType)); + var fieldType = fieldDef.getType(); + var javaType = typeMapper.map(fieldType, annotationConfig.useOptional()); + var fieldNonNull = fieldType instanceof NonNullType; + fields.add(toRecordField(fieldName, javaType, fieldNonNull)); var rawTypeName = unwrapTypeName(fieldDef.getType()); enqueueIfNonScalar(rawTypeName); @@ -435,10 +447,38 @@ private void writeType(TypeSpec typeSpec, Element element) { } } + private String formatFieldParam(RecordField f, String pathPrefix) { + var fieldPath = pathPrefix.isEmpty() ? f.name : pathPrefix + "." + f.name; + var fa = annotationConfig.fieldAnnotations().get(fieldPath); + + var typeStr = f.typeString; + var fieldAnns = new ArrayList(); + + if (f.nonNull && !annotationConfig.nonNullAnnotations().isEmpty()) { + fieldAnns.addAll(annotationConfig.nonNullAnnotations()); + } + + if (fa != null) { + if (fa.typeOverride() != null) { + typeStr = fa.typeOverride(); + } + fieldAnns.addAll(fa.annotations()); + } + + if (fieldAnns.isEmpty()) { + return typeStr + " " + f.name; + } + return String.join(" ", fieldAnns) + " " + typeStr + " " + f.name; + } + private RecordField toRecordField(String name, TypeName typeName) { + return toRecordField(name, typeName, false); + } + + private RecordField toRecordField(String name, TypeName typeName, boolean nonNull) { var typeString = typeNameToString(typeName); var importFqn = resolveImport(typeName); - return new RecordField(typeString, name, importFqn, typeName); + return new RecordField(typeString, name, importFqn, typeName, nonNull); } private String typeNameToString(TypeName typeName) { @@ -524,7 +564,7 @@ private void writeRecord(String className, List fields, Element ele } var params = - fields.stream().map(f -> f.typeString + " " + f.name).collect(Collectors.joining(", ")); + fields.stream().map(f -> formatFieldParam(f, "")).collect(Collectors.joining(", ")); out.println("public record " + className + "(" + params + ") {}"); } @@ -542,6 +582,7 @@ record ResultTypeUsage(String signature, String fields, Element element) {} static class ResultTypeDefinition { String className; + String fieldName; List fields; List innerTypes; } @@ -551,19 +592,15 @@ static class RecordField { final String name; final String importFqn; final TypeName typeName; + final boolean nonNull; - RecordField(String typeString, String name, String importFqn) { - this.typeString = typeString; - this.name = name; - this.importFqn = importFqn; - this.typeName = null; - } - - RecordField(String typeString, String name, String importFqn, TypeName typeName) { + RecordField( + String typeString, String name, String importFqn, TypeName typeName, boolean nonNull) { this.typeString = typeString; this.name = name; this.importFqn = importFqn; this.typeName = typeName; + this.nonNull = nonNull; } } } diff --git a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java index 511bea1010..180c223ad0 100644 --- a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java +++ b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java @@ -1178,4 +1178,616 @@ interface NestedAnnotatedApi { contents.contains("@Deprecated\n public record Location("); contents.contains("@Deprecated\n public record Coordinates("); } + + @Test + void fieldAnnotationOnSimpleField() { + var source = + JavaFileObjects.forSourceString( + "test.FieldAnnotApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface FieldAnnotApi { + @GraphqlQuery(\""" + mutation createCharacter($input: CreateCharacterInput!) { + createCharacter(input: $input) { id name email } + }\""") + @GraphqlField(name = "email", typeAnnotations = {Deprecated.class}) + CreateResult createCharacter(CreateCharacterInput input); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.CreateResult") + .contentsAsUtf8String() + .contains("String id, String name, @Deprecated String email"); + } + + @Test + void fieldAnnotationWithRawString() { + var source = + JavaFileObjects.forSourceString( + "test.FieldRawApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface FieldRawApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + @GraphqlField(name = "name", rawTypeAnnotations = {"@SuppressWarnings(\\"unchecked\\")"}) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.CharResult") + .contentsAsUtf8String() + .contains("@SuppressWarnings(\"unchecked\") String name"); + } + + @Test + void fieldAnnotationWithDotNotationForNestedField() { + var source = + JavaFileObjects.forSourceString( + "test.DotNotationApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface DotNotationApi { + @GraphqlQuery(\""" + { + character(id: "1") { + id name + location { planet sector } + } + }\""") + @GraphqlField(name = "location.planet", typeAnnotations = {Deprecated.class}) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.CharResult") + .contentsAsUtf8String() + .contains("@Deprecated String planet, String sector"); + } + + @Test + void fieldAnnotationCollisionUsesClassAsImportOnly() { + var source = + JavaFileObjects.forSourceString( + "test.FieldCollisionApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface FieldCollisionApi { + @GraphqlQuery(\""" + { character(id: "1") { id name } } + \""") + @GraphqlField(name = "name", + typeAnnotations = {Deprecated.class}, + rawTypeAnnotations = {"@Deprecated(since = \\"2.0\\")"}) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.CharResult") + .contentsAsUtf8String() + .contains("@Deprecated(since = \"2.0\") String name"); + } + + @Test + void multipleFieldAnnotations() { + var source = + JavaFileObjects.forSourceString( + "test.MultiFieldApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface MultiFieldApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + @GraphqlField(name = "name", typeAnnotations = {Deprecated.class}) + @GraphqlField(name = "email", typeAnnotations = {Deprecated.class}) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("@Deprecated String name"); + contents.contains("@Deprecated String email"); + } + + @Test + void classLevelTypeAnnotationsWithMethodLevelFieldAnnotations() { + var source = + JavaFileObjects.forSourceString( + "test.ClassAndFieldApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + typeAnnotations = {Deprecated.class}) + interface ClassAndFieldApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + @GraphqlField(name = "email", rawTypeAnnotations = {"@SuppressWarnings(\\"unchecked\\")"}) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("@Deprecated\npublic record CharResult("); + contents.contains("@SuppressWarnings(\"unchecked\") String email"); + } + + @Test + void deepNestedDotNotation() { + var source = + JavaFileObjects.forSourceString( + "test.DeepDotApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface DeepDotApi { + @GraphqlQuery(\""" + { + starship(id: "1") { + id name + location { planet coordinates { latitude longitude } } + } + }\""") + @GraphqlField(name = "location.coordinates.latitude", typeAnnotations = {Deprecated.class}) + ShipResult getShip(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.ShipResult") + .contentsAsUtf8String() + .contains("@Deprecated Double latitude, Double longitude"); + } + + @Test + void usesAddsImportsForRawTypeAnnotations() { + var source = + JavaFileObjects.forSourceString( + "test.UsesApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + uses = {Deprecated.class}, + rawTypeAnnotations = {"@Deprecated(since = \\"1.0\\")"}) + interface UsesApi { + @GraphqlQuery(\""" + { character(id: "1") { id name } } + \""") + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.CharResult") + .contentsAsUtf8String() + .contains("@Deprecated(since = \"1.0\")"); + } + + @Test + void usesAddsImportsForRawFieldAnnotations() { + var source = + JavaFileObjects.forSourceString( + "test.UsesFieldApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + uses = {Deprecated.class}) + interface UsesFieldApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + @GraphqlField(name = "email", rawTypeAnnotations = {"@Deprecated(since = \\"2.0\\")"}) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("@Deprecated(since = \"2.0\") String email"); + } + + @Test + void fieldTypeOverride() { + var source = + JavaFileObjects.forSourceString( + "test.TypeOverrideApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + import java.time.ZonedDateTime; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface TypeOverrideApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + @GraphqlField(name = "email", type = ZonedDateTime.class) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("import java.time.ZonedDateTime;"); + contents.contains("String id, String name, ZonedDateTime email"); + } + + @Test + void fieldTypeOverrideWithAnnotations() { + var source = + JavaFileObjects.forSourceString( + "test.TypeOverrideAnnotApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + import java.time.ZonedDateTime; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface TypeOverrideAnnotApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + @GraphqlField(name = "email", type = ZonedDateTime.class, typeAnnotations = {Deprecated.class}) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.CharResult") + .contentsAsUtf8String() + .contains("@Deprecated ZonedDateTime email"); + } + + @Test + void fieldTypeOverrideOnNestedField() { + var source = + JavaFileObjects.forSourceString( + "test.NestedTypeOverrideApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + import java.math.BigDecimal; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + interface NestedTypeOverrideApi { + @GraphqlQuery(\""" + { + character(id: "1") { + id name + location { planet coordinates { latitude longitude } } + } + }\""") + @GraphqlField(name = "location.coordinates.latitude", type = BigDecimal.class) + @GraphqlField(name = "location.coordinates.longitude", type = BigDecimal.class) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("import java.math.BigDecimal;"); + contents.contains("BigDecimal latitude, BigDecimal longitude"); + } + + @Test + void classLevelFieldTypeOverrideAppliesToAllMethods() { + var source = + JavaFileObjects.forSourceString( + "test.ClassFieldOverrideApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + import java.time.ZonedDateTime; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + @GraphqlField(name = "email", type = ZonedDateTime.class) + interface ClassFieldOverrideApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + CharResult1 getCharacter1(); + + @GraphqlQuery(\""" + { character(id: "2") { id email } } + \""") + CharResult2 getCharacter2(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.CharResult1") + .contentsAsUtf8String() + .contains("ZonedDateTime email"); + assertThat(compilation) + .generatedSourceFile("test.CharResult2") + .contentsAsUtf8String() + .contains("ZonedDateTime email"); + } + + @Test + void methodLevelFieldOverridesClassLevel() { + var source = + JavaFileObjects.forSourceString( + "test.MethodOverridesClassFieldApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + import java.time.ZonedDateTime; + import java.time.Instant; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false) + @GraphqlField(name = "email", type = ZonedDateTime.class) + interface MethodOverridesClassFieldApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + @GraphqlField(name = "email", type = Instant.class) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("test.CharResult") + .contentsAsUtf8String() + .contains("Instant email"); + } + + @Test + void nonNullAnnotationsAppliedToRequiredFields() { + var source = + JavaFileObjects.forSourceString( + "test.NonNullApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + nonNullTypeAnnotations = {Deprecated.class}) + interface NonNullApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("@Deprecated String id, @Deprecated String name, String email"); + } + + @Test + void nonNullAnnotationsOnInputType() { + var source = + JavaFileObjects.forSourceString( + "test.NonNullInputApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + nonNullTypeAnnotations = {Deprecated.class}) + interface NonNullInputApi { + @GraphqlQuery(\""" + mutation createCharacter($input: CreateCharacterInput!) { + createCharacter(input: $input) { id } + }\""") + Object createCharacter(CreateCharacterInput input); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation) + .generatedSourceFile("test.CreateCharacterInput") + .contentsAsUtf8String(); + contents.contains("@Deprecated String name, @Deprecated String email"); + contents.contains("Episode appearsIn"); + } + + @Test + void nonNullRawAnnotations() { + var source = + JavaFileObjects.forSourceString( + "test.NonNullRawApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + nonNullRawTypeAnnotations = {"@SuppressWarnings(\\"required\\")"}) + interface NonNullRawApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("@SuppressWarnings(\"required\") String id"); + contents.contains("String email"); + } + + @Test + void nonNullAnnotationsCombinedWithFieldAnnotations() { + var source = + JavaFileObjects.forSourceString( + "test.NonNullFieldComboApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.GraphqlField; + import java.time.ZonedDateTime; + + @GraphqlSchema(value = "test-schema.graphql", useOptional = false, + nonNullTypeAnnotations = {Deprecated.class}) + interface NonNullFieldComboApi { + @GraphqlQuery(\""" + { character(id: "1") { id name email } } + \""") + @GraphqlField(name = "name", type = ZonedDateTime.class) + CharResult getCharacter(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.CharResult").contentsAsUtf8String(); + contents.contains("@Deprecated ZonedDateTime name"); + contents.contains("@Deprecated String id"); + contents.contains("String email"); + } } diff --git a/graphql/README.md b/graphql/README.md index 036540e33a..aefed1c47a 100644 --- a/graphql/README.md +++ b/graphql/README.md @@ -164,6 +164,144 @@ Returns `Optional.empty()` when the data is null or missing, and `Optional.of(va Optional findTopUser(int limit); ``` +## Optional Fields + +By default, nullable GraphQL fields (without `!`) are wrapped in `Optional<>` in generated records: + +```graphql +type User { + id: ID! # non-null + name: String! # non-null + email: String # nullable +} +``` + +```java +public record User(String id, String name, Optional email) {} +``` + +This is controlled by `useOptional` on `@GraphqlSchema` (defaults to `true`): + +```java +@GraphqlSchema(value = "schema.graphql", useOptional = false) +``` + +Override per method with `Toggle`: + +```java +@GraphqlQuery(value = "...", useOptional = Toggle.FALSE) +``` + +## Type Annotations on Generated Records + +Add annotations to all generated records using `typeAnnotations` (no-arg) and `rawTypeAnnotations` (with args): + +```java +@GraphqlSchema( + value = "schema.graphql", + typeAnnotations = {Builder.class, Jacksonized.class}, + rawTypeAnnotations = {"@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)"} +) +``` + +Generates: + +```java +@Builder +@Jacksonized +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +public record User(String id, String name) {} +``` + +**Collision rule:** when the same annotation simple name appears in both `typeAnnotations` and `rawTypeAnnotations`, the class provides only the import and the raw string is used: + +```java +typeAnnotations = {Builder.class}, +rawTypeAnnotations = {"@Builder(toBuilder = true)"} +// Result: import lombok.Builder; + @Builder(toBuilder = true) +``` + +Override per method on `@GraphqlQuery` — non-empty arrays replace class-level values. + +## Import-Only Classes with `uses` + +When raw annotations reference classes not in `typeAnnotations`, use `uses` to add their imports: + +```java +@GraphqlSchema( + value = "schema.graphql", + uses = {Min.class, Max.class, Pattern.class} +) +``` + +These classes are added as imports to all generated files but no annotations are generated from them. + +## Non-Null Field Annotations + +Automatically annotate all non-null (`!`) fields with `nonNullTypeAnnotations`: + +```java +@GraphqlSchema( + value = "schema.graphql", + nonNullTypeAnnotations = {NotNull.class} +) +``` + +For `name: String!` and `email: String`, generates: + +```java +public record User(@NotNull String name, Optional email) {} +``` + +Same collision rule applies with `nonNullRawTypeAnnotations`. Overridable per method on `@GraphqlQuery`. + +## Field-Level Annotations with `@GraphqlField` + +Apply annotations or override types on specific fields. Repeatable, works on both the interface (class-level default) and individual methods: + +```java +@GraphqlSchema(value = "schema.graphql", useOptional = false) +@GraphqlField(name = "email", typeAnnotations = {Email.class}) +interface UserApi { + + @GraphqlQuery("{ user(id: \"1\") { id name email } }") + @GraphqlField(name = "name", typeAnnotations = {NotBlank.class}) + UserResult getUser(); +} +``` + +Generates: + +```java +public record UserResult(String id, @NotBlank String name, @Email String email) {} +``` + +### Dot Notation for Nested Fields + +Use dot notation to target fields in nested records: + +```java +@GraphqlField(name = "location.coordinates.latitude", typeAnnotations = {NotNull.class}) +@GraphqlField(name = "location.planet", typeAnnotations = {NotBlank.class}) +``` + +### Field Type Override + +Override the Java type for a field — useful when APIs return strings for dates without declaring custom scalars: + +```java +@GraphqlField(name = "createdAt", type = ZonedDateTime.class) +@GraphqlField(name = "amount", type = BigDecimal.class) +``` + +Combines with annotations: + +```java +@GraphqlField(name = "createdAt", type = ZonedDateTime.class, typeAnnotations = {NotNull.class}) +``` + +Class-level `@GraphqlField` applies to all methods; method-level overrides for the same field name. + ## Disabling Type Generation If you provide your own model classes, disable automatic generation: diff --git a/graphql/src/main/java/feign/graphql/GraphqlField.java b/graphql/src/main/java/feign/graphql/GraphqlField.java new file mode 100644 index 0000000000..76f3261798 --- /dev/null +++ b/graphql/src/main/java/feign/graphql/GraphqlField.java @@ -0,0 +1,38 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import feign.Experimental; +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Experimental +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Repeatable(GraphqlFields.class) +public @interface GraphqlField { + + String name(); + + Class type() default Void.class; + + Class[] typeAnnotations() default {}; + + String[] rawTypeAnnotations() default {}; +} diff --git a/graphql/src/main/java/feign/graphql/GraphqlFields.java b/graphql/src/main/java/feign/graphql/GraphqlFields.java new file mode 100644 index 0000000000..c7652f76d7 --- /dev/null +++ b/graphql/src/main/java/feign/graphql/GraphqlFields.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import feign.Experimental; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Experimental +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface GraphqlFields { + + GraphqlField[] value(); +} diff --git a/graphql/src/main/java/feign/graphql/GraphqlQuery.java b/graphql/src/main/java/feign/graphql/GraphqlQuery.java index 59d12d7150..4cc896d6d0 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlQuery.java +++ b/graphql/src/main/java/feign/graphql/GraphqlQuery.java @@ -33,4 +33,8 @@ Class[] typeAnnotations() default {}; String[] rawTypeAnnotations() default {}; + + Class[] nonNullTypeAnnotations() default {}; + + String[] nonNullRawTypeAnnotations() default {}; } diff --git a/graphql/src/main/java/feign/graphql/GraphqlSchema.java b/graphql/src/main/java/feign/graphql/GraphqlSchema.java index e605f0c745..5d97e983c4 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlSchema.java +++ b/graphql/src/main/java/feign/graphql/GraphqlSchema.java @@ -32,7 +32,13 @@ boolean useOptional() default true; + Class[] uses() default {}; + Class[] typeAnnotations() default {}; String[] rawTypeAnnotations() default {}; + + Class[] nonNullTypeAnnotations() default {}; + + String[] nonNullRawTypeAnnotations() default {}; } From 9031648f93a37eb34d588fa06e14c0bf1f55395d Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 16 Mar 2026 18:52:41 -0300 Subject: [PATCH 439/615] Deduplicate annotation extraction, resolution logic, and remove dead code Signed-off-by: Marvin Froeder --- .../graphql/apt/GraphqlSchemaProcessor.java | 89 +++---------------- .../graphql/apt/TypeAnnotationConfig.java | 48 +--------- .../java/feign/graphql/apt/TypeGenerator.java | 75 ++++------------ 3 files changed, 29 insertions(+), 183 deletions(-) diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java index af49d31397..266ed1313e 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java @@ -37,12 +37,12 @@ import graphql.schema.idl.SchemaParser; import graphql.schema.idl.TypeDefinitionRegistry; import graphql.schema.idl.UnExecutableSchemaGenerator; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.function.Supplier; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; @@ -450,10 +450,10 @@ private TypeMirror unwrapListTypeMirror(TypeMirror typeMirror) { private TypeAnnotationConfig resolveClassConfig( GraphqlSchema annotation, Map classFieldAnnotations) { - var fqns = extractTypeAnnotationFqns(annotation); + var fqns = extractClassFqns(annotation::typeAnnotations); var rawAnnotations = annotation.rawTypeAnnotations(); - var usesFqns = extractUsesFqns(annotation); - var nonNullFqns = extractNonNullTypeAnnotationFqns(annotation); + var usesFqns = extractClassFqns(annotation::uses); + var nonNullFqns = extractClassFqns(annotation::nonNullTypeAnnotations); var nonNullRaw = annotation.nonNullRawTypeAnnotations(); var config = TypeAnnotationConfig.resolve( @@ -480,40 +480,10 @@ private TypeAnnotationConfig resolveClassConfig( config.nonNullAnnotations()); } - private List extractNonNullTypeAnnotationFqns(GraphqlSchema annotation) { + private static List extractClassFqns(Supplier[]> accessor) { try { - var classes = annotation.nonNullTypeAnnotations(); - var result = new ArrayList(classes.length); - for (var cls : classes) { - result.add(cls.getCanonicalName()); - } - return result; - } catch (MirroredTypesException e) { - return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); - } - } - - private List extractNonNullTypeAnnotationFqns(GraphqlQuery annotation) { - try { - var classes = annotation.nonNullTypeAnnotations(); - var result = new ArrayList(classes.length); - for (var cls : classes) { - result.add(cls.getCanonicalName()); - } - return result; - } catch (MirroredTypesException e) { - return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); - } - } - - private List extractUsesFqns(GraphqlSchema annotation) { - try { - var classes = annotation.uses(); - var result = new ArrayList(classes.length); - for (var cls : classes) { - result.add(cls.getCanonicalName()); - } - return result; + var classes = accessor.get(); + return java.util.Arrays.stream(classes).map(Class::getCanonicalName).toList(); } catch (MirroredTypesException e) { return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); } @@ -521,7 +491,7 @@ private List extractUsesFqns(GraphqlSchema annotation) { private TypeAnnotationConfig resolveMethodConfig( ExecutableElement method, GraphqlQuery annotation, TypeAnnotationConfig classConfig) { - var methodFqns = extractTypeAnnotationFqns(annotation); + var methodFqns = extractClassFqns(annotation::typeAnnotations); var methodRaw = annotation.rawTypeAnnotations(); var methodToggle = annotation.useOptional(); @@ -533,7 +503,7 @@ private TypeAnnotationConfig resolveMethodConfig( TypeAnnotationConfig.FieldAnnotations.merge( classConfig.fieldAnnotations(), methodFieldAnnotations); - var methodNonNullFqns = extractNonNullTypeAnnotationFqns(annotation); + var methodNonNullFqns = extractClassFqns(annotation::nonNullTypeAnnotations); var methodNonNullRaw = annotation.nonNullRawTypeAnnotations(); boolean hasMethodNonNull = !methodNonNullFqns.isEmpty() || methodNonNullRaw.length > 0; var resolvedNonNull = hasMethodNonNull ? null : classConfig.nonNullAnnotations(); @@ -577,7 +547,7 @@ private Map extractFieldAnnotatio var fieldAnnotations = new HashMap(); var graphqlFields = method.getAnnotationsByType(GraphqlField.class); for (var gf : graphqlFields) { - var fqns = extractFieldTypeAnnotationFqns(gf); + var fqns = extractClassFqns(gf::typeAnnotations); var typeOverride = extractFieldTypeOverride(gf); var resolved = TypeAnnotationConfig.FieldAnnotations.resolve( @@ -600,45 +570,6 @@ private String extractFieldTypeOverride(GraphqlField annotation) { } } - private List extractFieldTypeAnnotationFqns(GraphqlField annotation) { - try { - var classes = annotation.typeAnnotations(); - var result = new ArrayList(classes.length); - for (var cls : classes) { - result.add(cls.getCanonicalName()); - } - return result; - } catch (MirroredTypesException e) { - return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); - } - } - - private List extractTypeAnnotationFqns(GraphqlSchema annotation) { - try { - var classes = annotation.typeAnnotations(); - var result = new ArrayList(classes.length); - for (var cls : classes) { - result.add(cls.getCanonicalName()); - } - return result; - } catch (MirroredTypesException e) { - return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); - } - } - - private List extractTypeAnnotationFqns(GraphqlQuery annotation) { - try { - var classes = annotation.typeAnnotations(); - var result = new ArrayList(classes.length); - for (var cls : classes) { - result.add(cls.getCanonicalName()); - } - return result; - } catch (MirroredTypesException e) { - return e.getTypeMirrors().stream().map(TypeMirror::toString).toList(); - } - } - private String getPackageName(TypeElement typeElement) { var enclosing = typeElement.getEnclosingElement(); while (enclosing != null && !(enclosing instanceof PackageElement)) { diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java index 9025601960..a1d17e0f1b 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java @@ -61,29 +61,8 @@ static TypeAnnotationConfig resolve( List nonNullFqns, String[] nonNullRawAnnotations) { - var rawSimpleNames = new HashSet(); - for (var raw : rawTypeAnnotations) { - var stripped = raw.startsWith("@") ? raw.substring(1) : raw; - var parenIdx = stripped.indexOf('('); - rawSimpleNames.add(parenIdx > 0 ? stripped.substring(0, parenIdx).trim() : stripped.trim()); - } - var imports = new TreeSet(); - var annotations = new ArrayList(); - - for (var fqn : typeAnnotationFqns) { - var simpleName = fqn.substring(fqn.lastIndexOf('.') + 1); - if (!fqn.startsWith("java.lang.")) { - imports.add(fqn); - } - if (!rawSimpleNames.contains(simpleName)) { - annotations.add("@" + simpleName); - } - } - - for (var raw : rawTypeAnnotations) { - annotations.add(raw.startsWith("@") ? raw : "@" + raw); - } + var annotations = resolveAnnotationList(typeAnnotationFqns, rawTypeAnnotations, imports); for (var fa : fieldAnnotations.values()) { imports.addAll(fa.imports()); @@ -95,7 +74,7 @@ static TypeAnnotationConfig resolve( imports, annotations, useOptional, fieldAnnotations, nonNullResolved); } - private static List resolveAnnotationList( + static List resolveAnnotationList( List fqns, String[] rawAnnotations, Set imports) { var rawSimpleNames = new HashSet(); for (var raw : rawAnnotations) { @@ -127,29 +106,8 @@ record FieldAnnotations(Set imports, List annotations, String ty static FieldAnnotations resolve( List fqns, String[] rawAnnotations, String typeOverride) { - var rawSimpleNames = new HashSet(); - for (var raw : rawAnnotations) { - var stripped = raw.startsWith("@") ? raw.substring(1) : raw; - var parenIdx = stripped.indexOf('('); - rawSimpleNames.add(parenIdx > 0 ? stripped.substring(0, parenIdx).trim() : stripped.trim()); - } - var imports = new TreeSet(); - var annotations = new ArrayList(); - - for (var fqn : fqns) { - var simpleName = fqn.substring(fqn.lastIndexOf('.') + 1); - if (!fqn.startsWith("java.lang.")) { - imports.add(fqn); - } - if (!rawSimpleNames.contains(simpleName)) { - annotations.add("@" + simpleName); - } - } - - for (var raw : rawAnnotations) { - annotations.add(raw.startsWith("@") ? raw : "@" + raw); - } + var annotations = resolveAnnotationList(fqns, rawAnnotations, imports); if (typeOverride != null) { var simpleName = typeOverride.substring(typeOverride.lastIndexOf('.') + 1); diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java index 1a4c8392bb..cd062083af 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java @@ -174,12 +174,7 @@ private ResultTypeDefinition buildResultType( } } - var def = new ResultTypeDefinition(); - def.className = className; - def.fieldName = pathPrefix; - def.fields = fields; - def.innerTypes = innerTypes; - return def; + return new ResultTypeDefinition(className, pathPrefix, fields, innerTypes); } private void writeResultRecord(ResultTypeDefinition tree, Element element) { @@ -450,35 +445,27 @@ private void writeType(TypeSpec typeSpec, Element element) { private String formatFieldParam(RecordField f, String pathPrefix) { var fieldPath = pathPrefix.isEmpty() ? f.name : pathPrefix + "." + f.name; var fa = annotationConfig.fieldAnnotations().get(fieldPath); + var hasNonNull = f.nonNull && !annotationConfig.nonNullAnnotations().isEmpty(); - var typeStr = f.typeString; - var fieldAnns = new ArrayList(); + var typeStr = fa != null && fa.typeOverride() != null ? fa.typeOverride() : f.typeString; - if (f.nonNull && !annotationConfig.nonNullAnnotations().isEmpty()) { - fieldAnns.addAll(annotationConfig.nonNullAnnotations()); + if (!hasNonNull && (fa == null || fa.annotations().isEmpty())) { + return typeStr + " " + f.name; } + var fieldAnns = new ArrayList(); + if (hasNonNull) { + fieldAnns.addAll(annotationConfig.nonNullAnnotations()); + } if (fa != null) { - if (fa.typeOverride() != null) { - typeStr = fa.typeOverride(); - } fieldAnns.addAll(fa.annotations()); } - - if (fieldAnns.isEmpty()) { - return typeStr + " " + f.name; - } return String.join(" ", fieldAnns) + " " + typeStr + " " + f.name; } - private RecordField toRecordField(String name, TypeName typeName) { - return toRecordField(name, typeName, false); - } - private RecordField toRecordField(String name, TypeName typeName, boolean nonNull) { var typeString = typeNameToString(typeName); - var importFqn = resolveImport(typeName); - return new RecordField(typeString, name, importFqn, typeName, nonNull); + return new RecordField(typeString, name, typeName, nonNull); } private String typeNameToString(TypeName typeName) { @@ -496,20 +483,6 @@ private String typeNameToString(TypeName typeName) { return typeName.toString(); } - private String resolveImport(TypeName typeName) { - if (typeName instanceof ParameterizedTypeName parameterized) { - resolveImport(parameterized.rawType); - for (var typeArg : parameterized.typeArguments) { - resolveImport(typeArg); - } - return fqnIfNeeded(parameterized.rawType); - } - if (typeName instanceof ClassName name) { - return fqnIfNeeded(name); - } - return null; - } - private String fqnIfNeeded(ClassName className) { var pkg = className.packageName(); if (pkg.equals("java.lang") || pkg.equals(targetPackage) || pkg.isEmpty()) { @@ -580,27 +553,11 @@ private void writeRecord(String className, List fields, Element ele record ResultTypeUsage(String signature, String fields, Element element) {} - static class ResultTypeDefinition { - String className; - String fieldName; - List fields; - List innerTypes; - } + record ResultTypeDefinition( + String className, + String fieldName, + List fields, + List innerTypes) {} - static class RecordField { - final String typeString; - final String name; - final String importFqn; - final TypeName typeName; - final boolean nonNull; - - RecordField( - String typeString, String name, String importFqn, TypeName typeName, boolean nonNull) { - this.typeString = typeString; - this.name = name; - this.importFqn = importFqn; - this.typeName = typeName; - this.nonNull = nonNull; - } - } + record RecordField(String typeString, String name, TypeName typeName, boolean nonNull) {} } From 0e5d0a796a37897a149b3adba5ce320817ca9d22 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 16 Mar 2026 18:56:28 -0300 Subject: [PATCH 440/615] Move shared unwrapTypeName/findFieldDefinition to GraphqlTypeMapper, deduplicate getRootType switch Signed-off-by: Marvin Froeder --- .../graphql/apt/GraphqlSchemaProcessor.java | 78 +++++-------------- .../feign/graphql/apt/GraphqlTypeMapper.java | 24 ++++++ .../java/feign/graphql/apt/TypeGenerator.java | 31 +------- 3 files changed, 46 insertions(+), 87 deletions(-) diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java index 266ed1313e..00ade4099c 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java @@ -24,13 +24,9 @@ import feign.graphql.Toggle; import graphql.language.Document; import graphql.language.Field; -import graphql.language.FieldDefinition; -import graphql.language.ListType; -import graphql.language.NonNullType; import graphql.language.ObjectTypeDefinition; import graphql.language.OperationDefinition; import graphql.language.SelectionSet; -import graphql.language.Type; import graphql.language.VariableDefinition; import graphql.parser.Parser; import graphql.schema.GraphQLSchema; @@ -255,9 +251,9 @@ private void processMethod( if (rootType != null) { var rootField = findRootField(operation.getSelectionSet()); if (rootField != null && rootField.getSelectionSet() != null) { - var rootFieldDef = findFieldDefinition(rootType, rootField.getName()); + var rootFieldDef = GraphqlTypeMapper.findFieldDefinition(rootType, rootField.getName()); if (rootFieldDef != null) { - var fieldTypeName = unwrapTypeName(rootFieldDef.getType()); + var fieldTypeName = GraphqlTypeMapper.unwrapTypeName(rootFieldDef.getType()); var fieldObjectType = registry.getType(fieldTypeName, ObjectTypeDefinition.class).orElse(null); if (fieldObjectType != null) { @@ -310,57 +306,32 @@ private Field findRootField(SelectionSet selectionSet) { return null; } - private FieldDefinition findFieldDefinition(ObjectTypeDefinition typeDef, String fieldName) { - for (var fd : typeDef.getFieldDefinitions()) { - if (fd.getName().equals(fieldName)) { - return fd; - } - } - return null; - } - private ObjectTypeDefinition getRootType( OperationDefinition operation, TypeDefinitionRegistry registry) { - var rootTypeName = + var operationName = switch (operation.getOperation()) { - case MUTATION -> - registry - .schemaDefinition() - .flatMap( - sd -> - sd.getOperationTypeDefinitions().stream() - .filter(otd -> otd.getName().equals("mutation")) - .findFirst()) - .map(otd -> otd.getTypeName().getName()) - .orElse("Mutation"); - case SUBSCRIPTION -> - registry - .schemaDefinition() - .flatMap( - sd -> - sd.getOperationTypeDefinitions().stream() - .filter(otd -> otd.getName().equals("subscription")) - .findFirst()) - .map(otd -> otd.getTypeName().getName()) - .orElse("Subscription"); - default -> - registry - .schemaDefinition() - .flatMap( - sd -> - sd.getOperationTypeDefinitions().stream() - .filter(otd -> otd.getName().equals("query")) - .findFirst()) - .map(otd -> otd.getTypeName().getName()) - .orElse("Query"); + case MUTATION -> "mutation"; + case SUBSCRIPTION -> "subscription"; + default -> "query"; }; + var fallback = Character.toUpperCase(operationName.charAt(0)) + operationName.substring(1); + var rootTypeName = + registry + .schemaDefinition() + .flatMap( + sd -> + sd.getOperationTypeDefinitions().stream() + .filter(otd -> otd.getName().equals(operationName)) + .findFirst()) + .map(otd -> otd.getTypeName().getName()) + .orElse(fallback); return registry.getType(rootTypeName, ObjectTypeDefinition.class).orElse(null); } private String findGraphqlInputType( String javaParamTypeName, List variableDefs) { for (var varDef : variableDefs) { - var graphqlTypeName = unwrapTypeName(varDef.getType()); + var graphqlTypeName = GraphqlTypeMapper.unwrapTypeName(varDef.getType()); if (graphqlTypeName.equals(javaParamTypeName)) { return graphqlTypeName; } @@ -368,19 +339,6 @@ private String findGraphqlInputType( return javaParamTypeName; } - private String unwrapTypeName(Type type) { - if (type instanceof NonNullType nullType) { - return unwrapTypeName(nullType.getType()); - } - if (type instanceof ListType listType) { - return unwrapTypeName(listType.getType()); - } - if (type instanceof graphql.language.TypeName name) { - return name.getName(); - } - return "String"; - } - private static final Set JAVA_BUILT_INS = Set.of( "String", diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java index 94ef2793db..240b17983b 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlTypeMapper.java @@ -18,8 +18,10 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; +import graphql.language.FieldDefinition; import graphql.language.ListType; import graphql.language.NonNullType; +import graphql.language.ObjectTypeDefinition; import graphql.language.Type; import java.util.HashMap; import java.util.List; @@ -86,4 +88,26 @@ private TypeName mapScalarOrNamed(String name) { public boolean isScalar(String name) { return BUILT_IN_SCALARS.containsKey(name) || customScalars.containsKey(name); } + + static String unwrapTypeName(Type type) { + if (type instanceof NonNullType nullType) { + return unwrapTypeName(nullType.getType()); + } + if (type instanceof ListType listType) { + return unwrapTypeName(listType.getType()); + } + if (type instanceof graphql.language.TypeName name) { + return name.getName(); + } + return "String"; + } + + static FieldDefinition findFieldDefinition(ObjectTypeDefinition typeDef, String fieldName) { + for (var fd : typeDef.getFieldDefinitions()) { + if (fd.getName().equals(fieldName)) { + return fd; + } + } + return null; + } } diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java index cd062083af..87341b1709 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java @@ -22,7 +22,6 @@ import com.squareup.javapoet.TypeSpec; import graphql.language.EnumTypeDefinition; import graphql.language.Field; -import graphql.language.FieldDefinition; import graphql.language.InputObjectTypeDefinition; import graphql.language.ListType; import graphql.language.NonNullType; @@ -141,13 +140,13 @@ private ResultTypeDefinition buildResultType( continue; } var fieldName = field.getName(); - var schemaDef = findFieldDefinition(parentType, fieldName); + var schemaDef = GraphqlTypeMapper.findFieldDefinition(parentType, fieldName); if (schemaDef == null) { continue; } var fieldType = schemaDef.getType(); - var rawTypeName = unwrapTypeName(fieldType); + var rawTypeName = GraphqlTypeMapper.unwrapTypeName(fieldType); if (field.getSelectionSet() != null && !field.getSelectionSet().getSelections().isEmpty()) { var nestedClassName = capitalize(fieldName); @@ -300,7 +299,7 @@ public void generateInputType(String className, String graphqlTypeName, Element var fieldNonNull = fieldType instanceof NonNullType; fields.add(toRecordField(fieldName, javaType, fieldNonNull)); - var rawTypeName = unwrapTypeName(fieldType); + var rawTypeName = GraphqlTypeMapper.unwrapTypeName(fieldType); enqueueIfNonScalar(rawTypeName); } @@ -365,7 +364,7 @@ private void generateFullObjectType( var fieldNonNull = fieldType instanceof NonNullType; fields.add(toRecordField(fieldName, javaType, fieldNonNull)); - var rawTypeName = unwrapTypeName(fieldDef.getType()); + var rawTypeName = GraphqlTypeMapper.unwrapTypeName(fieldDef.getType()); enqueueIfNonScalar(rawTypeName); } @@ -379,28 +378,6 @@ private void enqueueIfNonScalar(String typeName) { } } - private FieldDefinition findFieldDefinition(ObjectTypeDefinition typeDef, String fieldName) { - for (var fd : typeDef.getFieldDefinitions()) { - if (fd.getName().equals(fieldName)) { - return fd; - } - } - return null; - } - - private String unwrapTypeName(Type type) { - if (type instanceof NonNullType nullType) { - return unwrapTypeName(nullType.getType()); - } - if (type instanceof ListType listType) { - return unwrapTypeName(listType.getType()); - } - if (type instanceof graphql.language.TypeName name) { - return name.getName(); - } - return "String"; - } - private TypeName wrapType(Type schemaType, TypeName innerType, boolean useOptional) { boolean nullable = !(schemaType instanceof NonNullType); var wrapped = wrapTypeInner(schemaType, innerType); From 5dd5aae3eec85b331cb07a8a5c635d69111da18d Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 16 Mar 2026 19:34:12 -0300 Subject: [PATCH 441/615] [maven-release-plugin] prepare release 13.10 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 4 ++-- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 52 insertions(+), 52 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 2d8f3c26f7..4c52ab2aca 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index d5a62da711..26e314e7f0 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index dde47f4b40..85de7e2e93 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index d653233e6f..28ceca4501 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 7155c1d438..8a6938c294 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 6880e543ed..300ab2bfba 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 63cb280898..882a2b4f37 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 577e429644..6d216e1514 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 224f17d2c1..75f582d320 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 10085b77e1..0522059aca 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 10b8365c0d..f433ae820d 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index f6b94cbb21..b3d361c214 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index d839964803..2ae6f01fca 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 55a72207f7..6b08ed7443 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index e8f23c2232..72c79c906d 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index f5f770103a..1c2281857a 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index 20cbe814d1..b7345cffc0 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 00b1e67d35..d1685262de 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 3d7321f28b..dc405fbcff 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 085e5d36ce..9a1818fc91 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 0eb2b99863..7ee8273585 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index e37e24df14..e30e3540f9 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 28da8e722a..0ba9849452 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 398f3391ff..d2744aa3a4 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 3864ca1c61..72b40b5487 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 47300b18ab..c086b19d64 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 3987b7fe82..f62951c619 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index d5e6e68257..860d1b637b 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 3f827cb095..0fa125b1ae 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index e121974e9f..f6fb616667 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 7ed79f6943..ba5970c4f0 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 9dc9b921b0..7daa270bb3 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index ab0112f806..524851b55e 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 7f0c7317ad..d7ed2f5f63 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index c83af7bac3..12c2d1442a 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 6ecf4f3da2..b342cb4860 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 2245c7583a..ac06784eb3 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 3a092d194c..8a9f0a4625 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-okhttp diff --git a/pom.xml b/pom.xml index 7626d2147f..59fbd13883 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 pom Feign (Parent) @@ -135,7 +135,7 @@ scm:git:git@github.com:OpenFeign/feign.git scm:git:git@github.com:OpenFeign/feign.git - HEAD + 13.10 https://github.com/openfeign/feign diff --git a/reactive/pom.xml b/reactive/pom.xml index 7f2e8285f6..e541d4dff1 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 2b5cb5b1d6..b7e7de7243 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 66ed6c90c3..45f303116a 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 673ee625d0..b6dddba661 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 39cf7266d1..57bf286c68 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 14208a1579..df04f4c287 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index c552c21f6c..5b46144671 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index d3abe020bc..c4944934ec 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 1ca081213e..2005fc133c 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.10 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 3d5bb5d8b3..2f59bb58d9 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.10 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 0625cfeae9..56cf05c81a 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10-SNAPSHOT + 13.10 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 87a914f193..2bb0c9bc3f 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10-SNAPSHOT + 13.10 feign-vertx-parent From 0fe68a91bf50457755b521ae48725f874d24c8dd Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 16 Mar 2026 19:34:21 -0300 Subject: [PATCH 442/615] [maven-release-plugin] prepare for next development iteration --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 6 +++--- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 53 insertions(+), 53 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 4c52ab2aca..aaa366a863 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index 26e314e7f0..ab4d29905f 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 85de7e2e93..62b34d6b53 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 28ceca4501..b9a0dff4cb 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 8a6938c294..9bf372e8a4 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 300ab2bfba..238c14cd5b 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 882a2b4f37..482e16f1f5 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 6d216e1514..7f32e7e1c3 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 75f582d320..5f6b3e92fa 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 0522059aca..61796147dc 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index f433ae820d..40c9b2ebca 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index b3d361c214..9e466d206d 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 2ae6f01fca..bda2640041 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 6b08ed7443..875eb2941e 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index 72c79c906d..c48d8c7037 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 1c2281857a..77dfe35763 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index b7345cffc0..e32b9c6618 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index d1685262de..1f4e15b80a 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index dc405fbcff..43c68c9794 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 9a1818fc91..00bfda8513 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 7ee8273585..554078bff4 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index e30e3540f9..12311225c1 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 0ba9849452..31449fc855 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index d2744aa3a4..1d3a815680 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 72b40b5487..54239a0606 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index c086b19d64..2512723fcc 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index f62951c619..364782bb80 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 860d1b637b..51a73c3d7d 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 0fa125b1ae..e574d20fb3 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index f6fb616667..6b4b605b5b 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index ba5970c4f0..99dace963c 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 7daa270bb3..47738dbac6 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 524851b55e..ee6492da48 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index d7ed2f5f63..e3af8e8d4f 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 12c2d1442a..76fa9f1170 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index b342cb4860..90391bc993 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index ac06784eb3..b6104e9063 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 8a9f0a4625..bc886c8f8a 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index 59fbd13883..082fc8ccc1 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT pom Feign (Parent) @@ -135,7 +135,7 @@ scm:git:git@github.com:OpenFeign/feign.git scm:git:git@github.com:OpenFeign/feign.git - 13.10 + HEAD https://github.com/openfeign/feign @@ -568,7 +568,7 @@ false ${jvm.options} - + diff --git a/reactive/pom.xml b/reactive/pom.xml index e541d4dff1..8949c3d5c2 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index b7e7de7243..9f9a738871 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 45f303116a..6a8fc82f5f 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index b6dddba661..da921a999e 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 57bf286c68..7ce24d3768 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index df04f4c287..6da9458911 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 5b46144671..e9722f5da6 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index c4944934ec..b8f699ec31 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 2005fc133c..55ee0bec86 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10 + 13.11-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 2f59bb58d9..039d121e70 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10 + 13.11-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 56cf05c81a..40ad8063ac 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.10 + 13.11-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 2bb0c9bc3f..bd8cae47a7 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.10 + 13.11-SNAPSHOT feign-vertx-parent From 284669a9f471891c24626bd5271ce45348e05ad4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 05:33:02 +0000 Subject: [PATCH 443/615] build(deps): Bump kotlin.version from 2.3.10 to 2.3.20 Bumps `kotlin.version` from 2.3.10 to 2.3.20. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.3.10 to 2.3.20 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v2.3.20/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.3.10...v2.3.20) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.3.10 to 2.3.20 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v2.3.20/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.3.10...v2.3.20) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.3.10 to 2.3.20 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-version: 2.3.20 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-version: 2.3.20 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-version: 2.3.20 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index e3af8e8d4f..c454a26032 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.3.10 + 2.3.20 1.10.2 From b12ea2f5bc2697ba3e20c8002a269677f696e876 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 06:15:50 -0300 Subject: [PATCH 444/615] Add Codec/JsonCodec abstractions, Capability interceptor list enrichment, and GraphqlCapability Signed-off-by: Marvin Froeder --- core/src/main/java/feign/BaseBuilder.java | 47 ++++++++++++- core/src/main/java/feign/Capability.java | 8 +++ .../main/java/feign/RequestInterceptors.java | 33 +++++++++ .../main/java/feign/ResponseInterceptors.java | 33 +++++++++ core/src/main/java/feign/codec/Codec.java | 26 +++++++ core/src/main/java/feign/codec/JsonCodec.java | 28 ++++++++ .../main/java/feign/codec/JsonEncoder.java | 21 ++++++ core/src/test/java/feign/BaseBuilderTest.java | 4 +- .../java/feign/fastjson2/Fastjson2Codec.java | 51 ++++++++++++++ .../feign/fastjson2/Fastjson2Encoder.java | 3 +- graphql/README.md | 17 ++--- .../java/feign/graphql/GraphqlCapability.java | 68 +++++++++++++++++++ .../java/feign/graphql/GraphqlEncoder.java | 20 +----- .../graphql/GraphqlRequestInterceptor.java | 59 ++++++++++++++++ .../java/feign/graphql/GraphqlClientTest.java | 8 +-- .../feign/graphql/GraphqlEncoderTest.java | 11 +-- gson/src/main/java/feign/gson/GsonCodec.java | 55 +++++++++++++++ .../src/main/java/feign/gson/GsonEncoder.java | 3 +- .../main/java/feign/jackson/JacksonCodec.java | 55 +++++++++++++++ .../java/feign/jackson/JacksonEncoder.java | 3 +- .../java/feign/jackson3/Jackson3Codec.java | 55 +++++++++++++++ .../java/feign/jackson3/Jackson3Encoder.java | 3 +- .../src/main/java/feign/jaxb/JAXBCodec.java | 43 ++++++++++++ jaxb/src/main/java/feign/jaxb/JAXBCodec.java | 43 ++++++++++++ .../src/main/java/feign/moshi/MoshiCodec.java | 55 +++++++++++++++ .../main/java/feign/moshi/MoshiEncoder.java | 3 +- .../src/main/java/feign/soap/SOAPCodec.java | 44 ++++++++++++ soap/src/main/java/feign/soap/SOAPCodec.java | 44 ++++++++++++ 28 files changed, 794 insertions(+), 49 deletions(-) create mode 100644 core/src/main/java/feign/RequestInterceptors.java create mode 100644 core/src/main/java/feign/ResponseInterceptors.java create mode 100644 core/src/main/java/feign/codec/Codec.java create mode 100644 core/src/main/java/feign/codec/JsonCodec.java create mode 100644 core/src/main/java/feign/codec/JsonEncoder.java create mode 100644 fastjson2/src/main/java/feign/fastjson2/Fastjson2Codec.java create mode 100644 graphql/src/main/java/feign/graphql/GraphqlCapability.java create mode 100644 graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java create mode 100644 gson/src/main/java/feign/gson/GsonCodec.java create mode 100644 jackson/src/main/java/feign/jackson/JacksonCodec.java create mode 100644 jackson3/src/main/java/feign/jackson3/Jackson3Codec.java create mode 100644 jaxb-jakarta/src/main/java/feign/jaxb/JAXBCodec.java create mode 100644 jaxb/src/main/java/feign/jaxb/JAXBCodec.java create mode 100644 moshi/src/main/java/feign/moshi/MoshiCodec.java create mode 100644 soap-jakarta/src/main/java/feign/soap/SOAPCodec.java create mode 100644 soap/src/main/java/feign/soap/SOAPCodec.java diff --git a/core/src/main/java/feign/BaseBuilder.java b/core/src/main/java/feign/BaseBuilder.java index 5456bcb374..850fb47f63 100644 --- a/core/src/main/java/feign/BaseBuilder.java +++ b/core/src/main/java/feign/BaseBuilder.java @@ -20,6 +20,7 @@ import feign.Feign.ResponseMappingDecoder; import feign.Logger.NoOpLogger; import feign.Request.Options; +import feign.codec.Codec; import feign.codec.Decoder; import feign.codec.DefaultDecoder; import feign.codec.DefaultEncoder; @@ -30,6 +31,7 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -38,8 +40,8 @@ public abstract class BaseBuilder, T> implements Clo private final B thisB; - protected final List requestInterceptors = new ArrayList<>(); - protected final List responseInterceptors = new ArrayList<>(); + protected List requestInterceptors = new ArrayList<>(); + protected List responseInterceptors = new ArrayList<>(); protected Logger.Level logLevel = Logger.Level.NONE; protected Contract contract = new DefaultContract(); protected Retryer retryer = new DefaultRetryer(); @@ -92,6 +94,12 @@ public B decoder(Decoder decoder) { return thisB; } + public B codec(Codec codec) { + this.encoder = codec.encoder(); + this.decoder = codec.decoder(); + return thisB; + } + /** * This flag indicates that the response should not be automatically closed upon completion of * decoding the message. This should be set if you plan on processing the response into a @@ -265,6 +273,38 @@ B enrich() { } }); + // enrich each request interceptor, then enrich the list as a whole + RequestInterceptor[] requestArray = + clone.requestInterceptors.toArray(new RequestInterceptor[0]); + for (int i = 0; i < requestArray.length; i++) { + requestArray[i] = + (RequestInterceptor) + Capability.enrich(requestArray[i], RequestInterceptor.class, capabilities); + } + RequestInterceptors requestInterceptors = + (RequestInterceptors) + Capability.enrich( + new RequestInterceptors(Arrays.asList(requestArray)), + RequestInterceptors.class, + capabilities); + clone.requestInterceptors = new ArrayList<>(requestInterceptors.interceptors()); + + // enrich each response interceptor, then enrich the list as a whole + ResponseInterceptor[] responseArray = + clone.responseInterceptors.toArray(new ResponseInterceptor[0]); + for (int i = 0; i < responseArray.length; i++) { + responseArray[i] = + (ResponseInterceptor) + Capability.enrich(responseArray[i], ResponseInterceptor.class, capabilities); + } + ResponseInterceptors responseInterceptors = + (ResponseInterceptors) + Capability.enrich( + new ResponseInterceptors(Arrays.asList(responseArray)), + ResponseInterceptors.class, + capabilities); + clone.responseInterceptors = new ArrayList<>(responseInterceptors.interceptors()); + return clone; } catch (CloneNotSupportedException e) { throw new AssertionError(e); @@ -279,6 +319,9 @@ List getFieldsToEnrich() { .filter(field -> !Objects.equals(field.getName(), "capabilities")) // and thisB helper field .filter(field -> !Objects.equals(field.getName(), "thisB")) + // interceptor lists are enriched per-element then as a whole via custom types + .filter(field -> !Objects.equals(field.getName(), "requestInterceptors")) + .filter(field -> !Objects.equals(field.getName(), "responseInterceptors")) // skip primitive types .filter(field -> !field.getType().isPrimitive()) // skip enumerations diff --git a/core/src/main/java/feign/Capability.java b/core/src/main/java/feign/Capability.java index 7fb7e5d131..554c2a1007 100644 --- a/core/src/main/java/feign/Capability.java +++ b/core/src/main/java/feign/Capability.java @@ -144,4 +144,12 @@ default AsyncContextSupplier enrich(AsyncContextSupplier asyncContextS default MethodInfoResolver enrich(MethodInfoResolver methodInfoResolver) { return methodInfoResolver; } + + default RequestInterceptors enrich(RequestInterceptors requestInterceptors) { + return requestInterceptors; + } + + default ResponseInterceptors enrich(ResponseInterceptors responseInterceptors) { + return responseInterceptors; + } } diff --git a/core/src/main/java/feign/RequestInterceptors.java b/core/src/main/java/feign/RequestInterceptors.java new file mode 100644 index 0000000000..dc7ea083c1 --- /dev/null +++ b/core/src/main/java/feign/RequestInterceptors.java @@ -0,0 +1,33 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class RequestInterceptors { + + private final List interceptors; + + public RequestInterceptors(List interceptors) { + this.interceptors = Collections.unmodifiableList(new ArrayList<>(interceptors)); + } + + public List interceptors() { + return interceptors; + } +} diff --git a/core/src/main/java/feign/ResponseInterceptors.java b/core/src/main/java/feign/ResponseInterceptors.java new file mode 100644 index 0000000000..977a97abd5 --- /dev/null +++ b/core/src/main/java/feign/ResponseInterceptors.java @@ -0,0 +1,33 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class ResponseInterceptors { + + private final List interceptors; + + public ResponseInterceptors(List interceptors) { + this.interceptors = Collections.unmodifiableList(new ArrayList<>(interceptors)); + } + + public List interceptors() { + return interceptors; + } +} diff --git a/core/src/main/java/feign/codec/Codec.java b/core/src/main/java/feign/codec/Codec.java new file mode 100644 index 0000000000..4e2a64c4b7 --- /dev/null +++ b/core/src/main/java/feign/codec/Codec.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.codec; + +import feign.Experimental; + +@Experimental +public interface Codec { + + Encoder encoder(); + + Decoder decoder(); +} diff --git a/core/src/main/java/feign/codec/JsonCodec.java b/core/src/main/java/feign/codec/JsonCodec.java new file mode 100644 index 0000000000..4ef6a88537 --- /dev/null +++ b/core/src/main/java/feign/codec/JsonCodec.java @@ -0,0 +1,28 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.codec; + +import feign.Experimental; + +@Experimental +public interface JsonCodec extends Codec { + + @Override + JsonEncoder encoder(); + + @Override + JsonDecoder decoder(); +} diff --git a/core/src/main/java/feign/codec/JsonEncoder.java b/core/src/main/java/feign/codec/JsonEncoder.java new file mode 100644 index 0000000000..47d800e74b --- /dev/null +++ b/core/src/main/java/feign/codec/JsonEncoder.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.codec; + +import feign.Experimental; + +@Experimental +public interface JsonEncoder extends Encoder {} diff --git a/core/src/test/java/feign/BaseBuilderTest.java b/core/src/test/java/feign/BaseBuilderTest.java index 11b9b7c089..30abf2d487 100644 --- a/core/src/test/java/feign/BaseBuilderTest.java +++ b/core/src/test/java/feign/BaseBuilderTest.java @@ -31,7 +31,7 @@ void checkEnrichTouchesAllAsyncBuilderFields() throws IllegalArgumentException, IllegalAccessException { test( AsyncFeign.builder().requestInterceptor(_ -> {}).responseInterceptor((ic, c) -> c.next(ic)), - 14); + 12); } private void test(BaseBuilder builder, int expectedFieldsCount) @@ -60,6 +60,6 @@ private void test(BaseBuilder builder, int expectedFieldsCount) void checkEnrichTouchesAllBuilderFields() throws IllegalArgumentException, IllegalAccessException { test( - Feign.builder().requestInterceptor(_ -> {}).responseInterceptor((ic, c) -> c.next(ic)), 12); + Feign.builder().requestInterceptor(_ -> {}).responseInterceptor((ic, c) -> c.next(ic)), 10); } } diff --git a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Codec.java b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Codec.java new file mode 100644 index 0000000000..9f1ec55a42 --- /dev/null +++ b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Codec.java @@ -0,0 +1,51 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.fastjson2; + +import com.alibaba.fastjson2.JSONReader; +import com.alibaba.fastjson2.JSONWriter; +import feign.Experimental; +import feign.codec.Codec; +import feign.codec.JsonCodec; +import feign.codec.JsonDecoder; +import feign.codec.JsonEncoder; + +@Experimental +public class Fastjson2Codec implements Codec, JsonCodec { + + private final Fastjson2Encoder encoder; + private final Fastjson2Decoder decoder; + + public Fastjson2Codec() { + this.encoder = new Fastjson2Encoder(); + this.decoder = new Fastjson2Decoder(); + } + + public Fastjson2Codec(JSONWriter.Feature[] writerFeatures, JSONReader.Feature[] readerFeatures) { + this.encoder = new Fastjson2Encoder(writerFeatures); + this.decoder = new Fastjson2Decoder(readerFeatures); + } + + @Override + public JsonEncoder encoder() { + return encoder; + } + + @Override + public JsonDecoder decoder() { + return decoder; + } +} diff --git a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java index 5e622c72f6..06a98e8dd2 100644 --- a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java +++ b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java @@ -21,12 +21,13 @@ import feign.Util; import feign.codec.EncodeException; import feign.codec.Encoder; +import feign.codec.JsonEncoder; import java.lang.reflect.Type; /** * @author changjin wei(魏昌进) */ -public class Fastjson2Encoder implements Encoder { +public class Fastjson2Encoder implements Encoder, JsonEncoder { private final JSONWriter.Feature[] features; diff --git a/graphql/README.md b/graphql/README.md index aefed1c47a..858c6a3fb5 100644 --- a/graphql/README.md +++ b/graphql/README.md @@ -57,33 +57,28 @@ The annotation processor generates a Java record for `User` at compile time: public record User(String id, String name, String email) {} ``` -Build the client with `GraphqlContract`, `GraphqlEncoder`, and `GraphqlDecoder`. The `GraphqlDecoder` takes any `JsonDecoder` — all existing Feign decoders implement it: +Build the client using `GraphqlCapability`, which wires the contract, encoder, decoder, and request interceptor automatically. It takes any Feign `Encoder` and any `JsonDecoder` — all existing Feign decoders implement it: ```java // Using Jackson UserApi api = Feign.builder() - .contract(new GraphqlContract()) - .encoder(new GraphqlEncoder(new JacksonEncoder())) - .decoder(new GraphqlDecoder(new JacksonDecoder())) + .addCapability(new GraphqlCapability(new JacksonEncoder(), new JacksonDecoder())) .target(UserApi.class, "https://api.example.com/graphql"); User user = api.getUser("123"); ``` -Any JSON decoder works the same way: +Any JSON encoder/decoder pair works the same way: ```java // Gson -new GraphqlDecoder(new GsonDecoder()) - -// Moshi -new GraphqlDecoder(new MoshiDecoder()) +new GraphqlCapability(new GsonEncoder(), new GsonDecoder()) // Jackson 3 -new GraphqlDecoder(new Jackson3Decoder()) +new GraphqlCapability(new Jackson3Encoder(), new Jackson3Decoder()) // Fastjson2 -new GraphqlDecoder(new Fastjson2Decoder()) +new GraphqlCapability(new Fastjson2Encoder(), new Fastjson2Decoder()) ``` ## Mutations with Variables diff --git a/graphql/src/main/java/feign/graphql/GraphqlCapability.java b/graphql/src/main/java/feign/graphql/GraphqlCapability.java new file mode 100644 index 0000000000..9ace756bd0 --- /dev/null +++ b/graphql/src/main/java/feign/graphql/GraphqlCapability.java @@ -0,0 +1,68 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import feign.Capability; +import feign.Contract; +import feign.Experimental; +import feign.RequestInterceptors; +import feign.codec.Decoder; +import feign.codec.Encoder; +import feign.codec.JsonCodec; +import feign.codec.JsonDecoder; +import feign.codec.JsonEncoder; +import java.util.ArrayList; + +@Experimental +public class GraphqlCapability implements Capability { + + private final GraphqlContract contract = new GraphqlContract(); + private final GraphqlEncoder graphqlEncoder; + private final GraphqlDecoder graphqlDecoder; + private final GraphqlRequestInterceptor interceptor; + + public GraphqlCapability(JsonCodec codec) { + this(codec.encoder(), codec.decoder()); + } + + public GraphqlCapability(JsonEncoder encoder, JsonDecoder decoder) { + this.graphqlEncoder = new GraphqlEncoder(encoder, contract); + this.graphqlDecoder = new GraphqlDecoder(decoder); + this.interceptor = new GraphqlRequestInterceptor(encoder, contract); + } + + @Override + public Contract enrich(Contract contract) { + return this.contract; + } + + @Override + public Encoder enrich(Encoder encoder) { + return graphqlEncoder; + } + + @Override + public Decoder enrich(Decoder decoder) { + return graphqlDecoder; + } + + @Override + public RequestInterceptors enrich(RequestInterceptors requestInterceptors) { + var enriched = new ArrayList<>(requestInterceptors.interceptors()); + enriched.add(interceptor); + return new RequestInterceptors(enriched); + } +} diff --git a/graphql/src/main/java/feign/graphql/GraphqlEncoder.java b/graphql/src/main/java/feign/graphql/GraphqlEncoder.java index 9a87426734..e1807d17f3 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlEncoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlEncoder.java @@ -16,7 +16,6 @@ package feign.graphql; import feign.Experimental; -import feign.RequestInterceptor; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -25,7 +24,7 @@ import java.util.Map; @Experimental -public class GraphqlEncoder implements Encoder, RequestInterceptor { +public class GraphqlEncoder implements Encoder { private final Encoder delegate; private final Map queryMetadata; @@ -56,23 +55,6 @@ public void encode(Object object, Type bodyType, RequestTemplate template) delegate.encode(graphqlBody, MAP_STRING_WILDCARD, template); } - @Override - public void apply(RequestTemplate template) { - if (template.body() != null) { - return; - } - - var meta = lookupMetadata(template); - if (meta == null) { - return; - } - - var graphqlBody = new LinkedHashMap(); - graphqlBody.put("query", meta.query); - - delegate.encode(graphqlBody, MAP_STRING_WILDCARD, template); - } - private GraphqlContract.QueryMetadata lookupMetadata(RequestTemplate template) { if (template.methodMetadata() == null) { return null; diff --git a/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java b/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java new file mode 100644 index 0000000000..21a74cf7e4 --- /dev/null +++ b/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java @@ -0,0 +1,59 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import feign.Experimental; +import feign.RequestInterceptor; +import feign.RequestTemplate; +import feign.codec.Encoder; +import java.util.LinkedHashMap; +import java.util.Map; + +@Experimental +public class GraphqlRequestInterceptor implements RequestInterceptor { + + private final Encoder delegate; + private final Map queryMetadata; + + public GraphqlRequestInterceptor(Encoder delegate, GraphqlContract contract) { + this.delegate = delegate; + this.queryMetadata = contract.queryMetadata(); + } + + @Override + public void apply(RequestTemplate template) { + if (template.body() != null) { + return; + } + + var meta = lookupMetadata(template); + if (meta == null) { + return; + } + + var graphqlBody = new LinkedHashMap(); + graphqlBody.put("query", meta.query); + + delegate.encode(graphqlBody, Encoder.MAP_STRING_WILDCARD, template); + } + + private GraphqlContract.QueryMetadata lookupMetadata(RequestTemplate template) { + if (template.methodMetadata() == null) { + return null; + } + return queryMetadata.get(template.methodMetadata().configKey()); + } +} diff --git a/graphql/src/test/java/feign/graphql/GraphqlClientTest.java b/graphql/src/test/java/feign/graphql/GraphqlClientTest.java index 21a40eb489..11755fbe19 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlClientTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlClientTest.java @@ -93,13 +93,9 @@ void tearDown() throws Exception { } private TestApi buildClient() { - var contract = new GraphqlContract(); - var graphqlEncoder = new GraphqlEncoder(new JacksonEncoder(mapper), contract); return Feign.builder() - .contract(contract) - .encoder(graphqlEncoder) - .decoder(new GraphqlDecoder(new JacksonDecoder(mapper))) - .requestInterceptor(graphqlEncoder) + .addCapability( + new GraphqlCapability(new JacksonEncoder(mapper), new JacksonDecoder(mapper))) .target(TestApi.class, server.url("/graphql").toString()); } diff --git a/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java index a8b8f0eeb7..07a22ed8a9 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java @@ -27,7 +27,10 @@ class GraphqlEncoderTest { private final ObjectMapper mapper = new ObjectMapper(); private final GraphqlContract contract = new GraphqlContract(); - private final GraphqlEncoder encoder = new GraphqlEncoder(new JacksonEncoder(mapper), contract); + private final JacksonEncoder jacksonEncoder = new JacksonEncoder(mapper); + private final GraphqlEncoder encoder = new GraphqlEncoder(jacksonEncoder, contract); + private final GraphqlRequestInterceptor interceptor = + new GraphqlRequestInterceptor(jacksonEncoder, contract); interface MutationApi { @GraphqlQuery( @@ -72,7 +75,7 @@ void delegatesToWrappedEncoderForNonGraphql() { @Test void interceptorSetsBodyForNoVariableQuery() throws Exception { var template = templateFor(NoVariableApi.class); - encoder.apply(template); + interceptor.apply(template); var result = mapper.readTree(template.body()); assertThat(result.get("query").asText()).contains("pending"); @@ -83,7 +86,7 @@ void interceptorSetsBodyForNoVariableQuery() throws Exception { void interceptorSkipsWhenBodyAlreadySet() { var template = templateFor(MutationApi.class); template.body("already set"); - encoder.apply(template); + interceptor.apply(template); assertThat(new String(template.body())).isEqualTo("already set"); } @@ -91,7 +94,7 @@ void interceptorSkipsWhenBodyAlreadySet() { void interceptorSkipsForNonGraphql() { var template = new RequestTemplate(); template.body("some body"); - encoder.apply(template); + interceptor.apply(template); assertThat(new String(template.body())).isEqualTo("some body"); } } diff --git a/gson/src/main/java/feign/gson/GsonCodec.java b/gson/src/main/java/feign/gson/GsonCodec.java new file mode 100644 index 0000000000..8975b0648f --- /dev/null +++ b/gson/src/main/java/feign/gson/GsonCodec.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.gson; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import feign.Experimental; +import feign.codec.Codec; +import feign.codec.JsonCodec; +import feign.codec.JsonDecoder; +import feign.codec.JsonEncoder; + +@Experimental +public class GsonCodec implements Codec, JsonCodec { + + private final GsonEncoder encoder; + private final GsonDecoder decoder; + + public GsonCodec() { + this(new Gson()); + } + + public GsonCodec(Iterable> adapters) { + this.encoder = new GsonEncoder(adapters); + this.decoder = new GsonDecoder(adapters); + } + + public GsonCodec(Gson gson) { + this.encoder = new GsonEncoder(gson); + this.decoder = new GsonDecoder(gson); + } + + @Override + public JsonEncoder encoder() { + return encoder; + } + + @Override + public JsonDecoder decoder() { + return decoder; + } +} diff --git a/gson/src/main/java/feign/gson/GsonEncoder.java b/gson/src/main/java/feign/gson/GsonEncoder.java index d1f25d4d11..c4484bc6eb 100644 --- a/gson/src/main/java/feign/gson/GsonEncoder.java +++ b/gson/src/main/java/feign/gson/GsonEncoder.java @@ -19,10 +19,11 @@ import com.google.gson.TypeAdapter; import feign.RequestTemplate; import feign.codec.Encoder; +import feign.codec.JsonEncoder; import java.lang.reflect.Type; import java.util.Collections; -public class GsonEncoder implements Encoder { +public class GsonEncoder implements Encoder, JsonEncoder { private final Gson gson; diff --git a/jackson/src/main/java/feign/jackson/JacksonCodec.java b/jackson/src/main/java/feign/jackson/JacksonCodec.java new file mode 100644 index 0000000000..bb851b23f6 --- /dev/null +++ b/jackson/src/main/java/feign/jackson/JacksonCodec.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.jackson; + +import com.fasterxml.jackson.databind.Module; +import com.fasterxml.jackson.databind.ObjectMapper; +import feign.Experimental; +import feign.codec.Codec; +import feign.codec.JsonCodec; +import feign.codec.JsonDecoder; +import feign.codec.JsonEncoder; + +@Experimental +public class JacksonCodec implements Codec, JsonCodec { + + private final JacksonEncoder encoder; + private final JacksonDecoder decoder; + + public JacksonCodec() { + this(new ObjectMapper()); + } + + public JacksonCodec(Iterable modules) { + this.encoder = new JacksonEncoder(modules); + this.decoder = new JacksonDecoder(modules); + } + + public JacksonCodec(ObjectMapper mapper) { + this.encoder = new JacksonEncoder(mapper); + this.decoder = new JacksonDecoder(mapper); + } + + @Override + public JsonEncoder encoder() { + return encoder; + } + + @Override + public JsonDecoder decoder() { + return decoder; + } +} diff --git a/jackson/src/main/java/feign/jackson/JacksonEncoder.java b/jackson/src/main/java/feign/jackson/JacksonEncoder.java index 6158541765..48b169a8d3 100644 --- a/jackson/src/main/java/feign/jackson/JacksonEncoder.java +++ b/jackson/src/main/java/feign/jackson/JacksonEncoder.java @@ -25,10 +25,11 @@ import feign.Util; import feign.codec.EncodeException; import feign.codec.Encoder; +import feign.codec.JsonEncoder; import java.lang.reflect.Type; import java.util.Collections; -public class JacksonEncoder implements Encoder { +public class JacksonEncoder implements Encoder, JsonEncoder { private final ObjectMapper mapper; diff --git a/jackson3/src/main/java/feign/jackson3/Jackson3Codec.java b/jackson3/src/main/java/feign/jackson3/Jackson3Codec.java new file mode 100644 index 0000000000..4413d1031f --- /dev/null +++ b/jackson3/src/main/java/feign/jackson3/Jackson3Codec.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.jackson3; + +import feign.Experimental; +import feign.codec.Codec; +import feign.codec.JsonCodec; +import feign.codec.JsonDecoder; +import feign.codec.JsonEncoder; +import tools.jackson.databind.JacksonModule; +import tools.jackson.databind.json.JsonMapper; + +@Experimental +public class Jackson3Codec implements Codec, JsonCodec { + + private final Jackson3Encoder encoder; + private final Jackson3Decoder decoder; + + public Jackson3Codec() { + this(JsonMapper.builder().build()); + } + + public Jackson3Codec(Iterable modules) { + this.encoder = new Jackson3Encoder(modules); + this.decoder = new Jackson3Decoder(modules); + } + + public Jackson3Codec(JsonMapper mapper) { + this.encoder = new Jackson3Encoder(mapper); + this.decoder = new Jackson3Decoder(mapper); + } + + @Override + public JsonEncoder encoder() { + return encoder; + } + + @Override + public JsonDecoder decoder() { + return decoder; + } +} diff --git a/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java b/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java index d6455000a0..90342c0162 100644 --- a/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java +++ b/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java @@ -20,6 +20,7 @@ import feign.Util; import feign.codec.EncodeException; import feign.codec.Encoder; +import feign.codec.JsonEncoder; import java.lang.reflect.Type; import java.util.Collections; import tools.jackson.core.JacksonException; @@ -28,7 +29,7 @@ import tools.jackson.databind.SerializationFeature; import tools.jackson.databind.json.JsonMapper; -public class Jackson3Encoder implements Encoder { +public class Jackson3Encoder implements Encoder, JsonEncoder { private final JsonMapper mapper; diff --git a/jaxb-jakarta/src/main/java/feign/jaxb/JAXBCodec.java b/jaxb-jakarta/src/main/java/feign/jaxb/JAXBCodec.java new file mode 100644 index 0000000000..4c351c0080 --- /dev/null +++ b/jaxb-jakarta/src/main/java/feign/jaxb/JAXBCodec.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.jaxb; + +import feign.Experimental; +import feign.codec.Codec; +import feign.codec.Decoder; +import feign.codec.Encoder; + +@Experimental +public class JAXBCodec implements Codec { + + private final JAXBEncoder encoder; + private final JAXBDecoder decoder; + + public JAXBCodec(JAXBContextFactory jaxbContextFactory) { + this.encoder = new JAXBEncoder(jaxbContextFactory); + this.decoder = new JAXBDecoder(jaxbContextFactory); + } + + @Override + public Encoder encoder() { + return encoder; + } + + @Override + public Decoder decoder() { + return decoder; + } +} diff --git a/jaxb/src/main/java/feign/jaxb/JAXBCodec.java b/jaxb/src/main/java/feign/jaxb/JAXBCodec.java new file mode 100644 index 0000000000..4c351c0080 --- /dev/null +++ b/jaxb/src/main/java/feign/jaxb/JAXBCodec.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.jaxb; + +import feign.Experimental; +import feign.codec.Codec; +import feign.codec.Decoder; +import feign.codec.Encoder; + +@Experimental +public class JAXBCodec implements Codec { + + private final JAXBEncoder encoder; + private final JAXBDecoder decoder; + + public JAXBCodec(JAXBContextFactory jaxbContextFactory) { + this.encoder = new JAXBEncoder(jaxbContextFactory); + this.decoder = new JAXBDecoder(jaxbContextFactory); + } + + @Override + public Encoder encoder() { + return encoder; + } + + @Override + public Decoder decoder() { + return decoder; + } +} diff --git a/moshi/src/main/java/feign/moshi/MoshiCodec.java b/moshi/src/main/java/feign/moshi/MoshiCodec.java new file mode 100644 index 0000000000..e5270d22d7 --- /dev/null +++ b/moshi/src/main/java/feign/moshi/MoshiCodec.java @@ -0,0 +1,55 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.moshi; + +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; +import feign.Experimental; +import feign.codec.Codec; +import feign.codec.JsonCodec; +import feign.codec.JsonDecoder; +import feign.codec.JsonEncoder; + +@Experimental +public class MoshiCodec implements Codec, JsonCodec { + + private final MoshiEncoder encoder; + private final MoshiDecoder decoder; + + public MoshiCodec() { + this(new Moshi.Builder().build()); + } + + public MoshiCodec(Iterable> adapters) { + this.encoder = new MoshiEncoder(adapters); + this.decoder = new MoshiDecoder(adapters); + } + + public MoshiCodec(Moshi moshi) { + this.encoder = new MoshiEncoder(moshi); + this.decoder = new MoshiDecoder(moshi); + } + + @Override + public JsonEncoder encoder() { + return encoder; + } + + @Override + public JsonDecoder decoder() { + return decoder; + } +} diff --git a/moshi/src/main/java/feign/moshi/MoshiEncoder.java b/moshi/src/main/java/feign/moshi/MoshiEncoder.java index 3e998b286c..b65f705e27 100644 --- a/moshi/src/main/java/feign/moshi/MoshiEncoder.java +++ b/moshi/src/main/java/feign/moshi/MoshiEncoder.java @@ -19,9 +19,10 @@ import com.squareup.moshi.Moshi; import feign.RequestTemplate; import feign.codec.Encoder; +import feign.codec.JsonEncoder; import java.lang.reflect.Type; -public class MoshiEncoder implements Encoder { +public class MoshiEncoder implements Encoder, JsonEncoder { private final Moshi moshi; diff --git a/soap-jakarta/src/main/java/feign/soap/SOAPCodec.java b/soap-jakarta/src/main/java/feign/soap/SOAPCodec.java new file mode 100644 index 0000000000..9295506e97 --- /dev/null +++ b/soap-jakarta/src/main/java/feign/soap/SOAPCodec.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.soap; + +import feign.Experimental; +import feign.codec.Codec; +import feign.codec.Decoder; +import feign.codec.Encoder; +import feign.jaxb.JAXBContextFactory; + +@Experimental +public class SOAPCodec implements Codec { + + private final SOAPEncoder encoder; + private final SOAPDecoder decoder; + + public SOAPCodec(JAXBContextFactory jaxbContextFactory) { + this.encoder = new SOAPEncoder(jaxbContextFactory); + this.decoder = new SOAPDecoder(jaxbContextFactory); + } + + @Override + public Encoder encoder() { + return encoder; + } + + @Override + public Decoder decoder() { + return decoder; + } +} diff --git a/soap/src/main/java/feign/soap/SOAPCodec.java b/soap/src/main/java/feign/soap/SOAPCodec.java new file mode 100644 index 0000000000..9295506e97 --- /dev/null +++ b/soap/src/main/java/feign/soap/SOAPCodec.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.soap; + +import feign.Experimental; +import feign.codec.Codec; +import feign.codec.Decoder; +import feign.codec.Encoder; +import feign.jaxb.JAXBContextFactory; + +@Experimental +public class SOAPCodec implements Codec { + + private final SOAPEncoder encoder; + private final SOAPDecoder decoder; + + public SOAPCodec(JAXBContextFactory jaxbContextFactory) { + this.encoder = new SOAPEncoder(jaxbContextFactory); + this.decoder = new SOAPDecoder(jaxbContextFactory); + } + + @Override + public Encoder encoder() { + return encoder; + } + + @Override + public Decoder decoder() { + return decoder; + } +} From ab2930e8dd8bd711b257c18edb8f10a8cfb3c17a Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 06:48:26 -0300 Subject: [PATCH 445/615] Add release plugin generated files to .gitignore Signed-off-by: Marvin Froeder --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 6b1a07cf66..53adc16165 100644 --- a/.gitignore +++ b/.gitignore @@ -70,5 +70,9 @@ atlassian-ide-plugin.xml # maven versions *.versionsBackup + +# maven-release-plugin +release.properties +pom.xml.releaseBackup .mvn/.develocity/develocity-workspace-id .sdkmanrc From 99428cabd70edb88b3f24d6db6503c724dde5f63 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 06:50:55 -0300 Subject: [PATCH 446/615] Update GraphqlCapability README and test to use JsonCodec Signed-off-by: Marvin Froeder --- graphql/README.md | 12 ++++++------ .../test/java/feign/graphql/GraphqlClientTest.java | 6 ++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/graphql/README.md b/graphql/README.md index 858c6a3fb5..626348301f 100644 --- a/graphql/README.md +++ b/graphql/README.md @@ -57,28 +57,28 @@ The annotation processor generates a Java record for `User` at compile time: public record User(String id, String name, String email) {} ``` -Build the client using `GraphqlCapability`, which wires the contract, encoder, decoder, and request interceptor automatically. It takes any Feign `Encoder` and any `JsonDecoder` — all existing Feign decoders implement it: +Build the client using `GraphqlCapability`, which wires the contract, encoder, decoder, and request interceptor automatically. It takes any `JsonCodec`: ```java // Using Jackson UserApi api = Feign.builder() - .addCapability(new GraphqlCapability(new JacksonEncoder(), new JacksonDecoder())) + .addCapability(new GraphqlCapability(new JacksonCodec())) .target(UserApi.class, "https://api.example.com/graphql"); User user = api.getUser("123"); ``` -Any JSON encoder/decoder pair works the same way: +Any JSON codec works the same way: ```java // Gson -new GraphqlCapability(new GsonEncoder(), new GsonDecoder()) +new GraphqlCapability(new GsonCodec()) // Jackson 3 -new GraphqlCapability(new Jackson3Encoder(), new Jackson3Decoder()) +new GraphqlCapability(new Jackson3Codec()) // Fastjson2 -new GraphqlCapability(new Fastjson2Encoder(), new Fastjson2Decoder()) +new GraphqlCapability(new Fastjson2Codec()) ``` ## Mutations with Variables diff --git a/graphql/src/test/java/feign/graphql/GraphqlClientTest.java b/graphql/src/test/java/feign/graphql/GraphqlClientTest.java index 11755fbe19..2de395de00 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlClientTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlClientTest.java @@ -23,8 +23,7 @@ import feign.Feign; import feign.Headers; import feign.Param; -import feign.jackson.JacksonDecoder; -import feign.jackson.JacksonEncoder; +import feign.jackson.JacksonCodec; import java.util.List; import java.util.Optional; import okhttp3.mockwebserver.MockResponse; @@ -94,8 +93,7 @@ void tearDown() throws Exception { private TestApi buildClient() { return Feign.builder() - .addCapability( - new GraphqlCapability(new JacksonEncoder(mapper), new JacksonDecoder(mapper))) + .addCapability(new GraphqlCapability(new JacksonCodec(mapper))) .target(TestApi.class, server.url("/graphql").toString()); } From 8d67ceb102ededb194958fd8380717c670a5e4dc Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 06:54:21 -0300 Subject: [PATCH 447/615] Update all module READMEs to show Codec usage first Signed-off-by: Marvin Froeder --- README.md | 130 ++++++++++++++++++++++------------------- fastjson2/README.md | 17 ++++-- gson/README.md | 10 +++- jackson/README.md | 19 ++++-- jackson3/README.md | 19 ++++-- jaxb/README.md | 10 +++- moshi/README.md | 10 +++- soap-jakarta/README.md | 21 ++++--- soap/README.md | 21 ++++--- 9 files changed, 165 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index 9f4115cbcb..6e31ab89f0 100644 --- a/README.md +++ b/README.md @@ -374,44 +374,54 @@ Feign intends to work well with other Open Source tools. Modules are welcome to ### Encoder/Decoder #### Gson -[Gson](./gson) includes an encoder and decoder you can use with a JSON API. +[Gson](./gson) includes a codec you can use with a JSON API. -Add `GsonEncoder` and/or `GsonDecoder` to your `Feign.Builder` like so: +```java +GitHub github = Feign.builder() + .codec(new GsonCodec()) + .target(GitHub.class, "https://api.github.com"); +``` + +You can also configure the encoder and decoder separately: ```java -public class Example { - public static void main(String[] args) { - GsonCodec codec = new GsonCodec(); - GitHub github = Feign.builder() - .encoder(new GsonEncoder()) - .decoder(new GsonDecoder()) - .target(GitHub.class, "https://api.github.com"); - } -} +GitHub github = Feign.builder() + .encoder(new GsonEncoder()) + .decoder(new GsonDecoder()) + .target(GitHub.class, "https://api.github.com"); ``` #### Jackson -[Jackson](./jackson) includes an encoder and decoder you can use with a JSON API. +[Jackson](./jackson) includes a codec you can use with a JSON API. -Add `JacksonEncoder` and/or `JacksonDecoder` to your `Feign.Builder` like so: +```java +GitHub github = Feign.builder() + .codec(new JacksonCodec()) + .target(GitHub.class, "https://api.github.com"); +``` + +You can also configure the encoder and decoder separately: ```java -public class Example { - public static void main(String[] args) { - GitHub github = Feign.builder() +GitHub github = Feign.builder() .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) .target(GitHub.class, "https://api.github.com"); - } -} ``` For the lighter weight Jackson Jr, use `JacksonJrEncoder` and `JacksonJrDecoder` from the [Jackson Jr Module](./jackson-jr). #### Moshi -[Moshi](./moshi) includes an encoder and decoder you can use with a JSON API. -Add `MoshiEncoder` and/or `MoshiDecoder` to your `Feign.Builder` like so: +[Moshi](./moshi) includes a codec you can use with a JSON API. + +```java +GitHub github = Feign.builder() + .codec(new MoshiCodec()) + .target(GitHub.class, "https://api.github.com"); +``` + +You can also configure the encoder and decoder separately: ```java GitHub github = Feign.builder() @@ -425,70 +435,72 @@ GitHub github = Feign.builder() Here's an example of how to configure Sax response parsing: ```java -public class Example { - public static void main(String[] args) { - Api api = Feign.builder() - .decoder(SAXDecoder.builder() - .registerContentHandler(UserIdHandler.class) - .build()) - .target(Api.class, "https://apihost"); - } -} +Api api = Feign.builder() + .decoder(SAXDecoder.builder() + .registerContentHandler(UserIdHandler.class) + .build()) + .target(Api.class, "https://apihost"); ``` #### JAXB -[JAXB](./jaxb) includes an encoder and decoder you can use with an XML API. +[JAXB](./jaxb) includes a codec you can use with an XML API. -Add `JAXBEncoder` and/or `JAXBDecoder` to your `Feign.Builder` like so: +```java +Api api = Feign.builder() + .codec(new JAXBCodec(jaxbFactory)) + .target(Api.class, "https://apihost"); +``` + +You can also configure the encoder and decoder separately: ```java -public class Example { - public static void main(String[] args) { - Api api = Feign.builder() - .encoder(new JAXBEncoder()) - .decoder(new JAXBDecoder()) - .target(Api.class, "https://apihost"); - } -} +Api api = Feign.builder() + .encoder(new JAXBEncoder(jaxbFactory)) + .decoder(new JAXBDecoder(jaxbFactory)) + .target(Api.class, "https://apihost"); ``` #### SOAP -[SOAP](./soap) includes an encoder and decoder you can use with an XML API. - +[SOAP](./soap) includes a codec you can use with an XML API. This module adds support for encoding and decoding SOAP Body objects via JAXB and SOAPMessage. It also provides SOAPFault decoding capabilities by wrapping them into the original `javax.xml.ws.soap.SOAPFaultException`, so that you'll only need to catch `SOAPFaultException` in order to handle SOAPFault. -Add `SOAPEncoder` and/or `SOAPDecoder` to your `Feign.Builder` like so: +```java +Api api = Feign.builder() + .codec(new SOAPCodec(jaxbFactory)) + .errorDecoder(new SOAPErrorDecoder()) + .target(MyApi.class, "http://api"); +``` + +You can also configure the encoder and decoder separately: ```java -public class Example { - public static void main(String[] args) { - Api api = Feign.builder() - .encoder(new SOAPEncoder(jaxbFactory)) - .decoder(new SOAPDecoder(jaxbFactory)) - .errorDecoder(new SOAPErrorDecoder()) - .target(MyApi.class, "http://api"); - } -} +Api api = Feign.builder() + .encoder(new SOAPEncoder(jaxbFactory)) + .decoder(new SOAPDecoder(jaxbFactory)) + .errorDecoder(new SOAPErrorDecoder()) + .target(MyApi.class, "http://api"); ``` NB: you may also need to add `SOAPErrorDecoder` if SOAP Faults are returned in response with error http codes (4xx, 5xx, ...) -#### Fastjson2 +#### Fastjson2 -[fastjson2](./fastjson2) includes an encoder and decoder you can use with a JSON API. +[fastjson2](./fastjson2) includes a codec you can use with a JSON API. -Add `Fastjson2Encoder` and/or `Fastjson2Decoder` to your `Feign.Builder` like so: +```java +GitHub github = Feign.builder() + .codec(new Fastjson2Codec()) + .target(GitHub.class, "https://api.github.com"); +``` + +You can also configure the encoder and decoder separately: ```java -public class Example { - public static void main(String[] args) { - GitHub github = Feign.builder() +GitHub github = Feign.builder() .encoder(new Fastjson2Encoder()) .decoder(new Fastjson2Decoder()) .target(GitHub.class, "https://api.github.com"); - } -} ``` ### Contract diff --git a/fastjson2/README.md b/fastjson2/README.md index 8d283ea307..714995dbad 100644 --- a/fastjson2/README.md +++ b/fastjson2/README.md @@ -3,7 +3,15 @@ Fastjson2 Codec This module adds support for encoding and decoding JSON via Fastjson2. -Add `Fastjson2Encoder` and/or `Fastjson2Decoder` to your `Feign.Builder` like so: +Add `Fastjson2Codec` to your `Feign.Builder` like so: + +```java +GitHub github = Feign.builder() + .codec(new Fastjson2Codec()) + .target(GitHub.class, "https://api.github.com"); +``` + +You can also configure the encoder and decoder separately: ```java GitHub github = Feign.builder() @@ -12,11 +20,12 @@ GitHub github = Feign.builder() .target(GitHub.class, "https://api.github.com"); ``` -If you want to customize, provide it to the `Fastjson2Encoder` and `Fastjson2Decoder`: +If you want to customize, provide features to the `Fastjson2Codec`: ```java GitHub github = Feign.builder() - .encoder(new Fastjson2Encoder(new JSONWriter.Feature[]{JSONWriter.Feature.WriteNonStringValueAsString}) - .decoder(new Fastjson2Decoder(new JSONReader.Feature[]{JSONReader.Feature.EmptyStringAsNull})) + .codec(new Fastjson2Codec( + new JSONWriter.Feature[]{JSONWriter.Feature.WriteNonStringValueAsString}, + new JSONReader.Feature[]{JSONReader.Feature.EmptyStringAsNull})) .target(GitHub.class, "https://api.github.com"); ``` diff --git a/gson/README.md b/gson/README.md index d26c16470d..c005699bec 100644 --- a/gson/README.md +++ b/gson/README.md @@ -3,7 +3,15 @@ Gson Codec This module adds support for encoding and decoding JSON via the Gson library. -Add `GsonEncoder` and/or `GsonDecoder` to your `Feign.Builder` like so: +Add `GsonCodec` to your `Feign.Builder` like so: + +```java +GitHub github = Feign.builder() + .codec(new GsonCodec()) + .target(GitHub.class, "https://api.github.com"); +``` + +You can also configure the encoder and decoder separately: ```java GitHub github = Feign.builder() diff --git a/jackson/README.md b/jackson/README.md index 8be632779e..31e8cbd43c 100644 --- a/jackson/README.md +++ b/jackson/README.md @@ -3,16 +3,15 @@ Jackson Codec This module adds support for encoding and decoding JSON via Jackson. -Add `JacksonEncoder` and/or `JacksonDecoder` to your `Feign.Builder` like so: +Add `JacksonCodec` to your `Feign.Builder` like so: ```java GitHub github = Feign.builder() - .encoder(new JacksonEncoder()) - .decoder(new JacksonDecoder()) + .codec(new JacksonCodec()) .target(GitHub.class, "https://api.github.com"); ``` -If you want to customize the `ObjectMapper` that is used, provide it to the `JacksonEncoder` and `JacksonDecoder`: +If you want to customize the `ObjectMapper` that is used, provide it to the `JacksonCodec`: ```java ObjectMapper mapper = new ObjectMapper() @@ -21,7 +20,15 @@ ObjectMapper mapper = new ObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); GitHub github = Feign.builder() - .encoder(new JacksonEncoder(mapper)) - .decoder(new JacksonDecoder(mapper)) + .codec(new JacksonCodec(mapper)) + .target(GitHub.class, "https://api.github.com"); +``` + +You can also configure the encoder and decoder separately: + +```java +GitHub github = Feign.builder() + .encoder(new JacksonEncoder()) + .decoder(new JacksonDecoder()) .target(GitHub.class, "https://api.github.com"); ``` diff --git a/jackson3/README.md b/jackson3/README.md index 0a1107020b..457fd6cce8 100644 --- a/jackson3/README.md +++ b/jackson3/README.md @@ -5,16 +5,15 @@ This module adds support for encoding and decoding JSON via Jackson 3. **Note:** Jackson 3 requires Java 17 or higher. -Add `Jackson3Encoder` and/or `Jackson3Decoder` to your `Feign.Builder` like so: +Add `Jackson3Codec` to your `Feign.Builder` like so: ```java GitHub github = Feign.builder() - .encoder(new Jackson3Encoder()) - .decoder(new Jackson3Decoder()) + .codec(new Jackson3Codec()) .target(GitHub.class, "https://api.github.com"); ``` -If you want to customize the `JsonMapper` that is used, provide it to the `Jackson3Encoder` and `Jackson3Decoder`: +If you want to customize the `JsonMapper` that is used, provide it to the `Jackson3Codec`: ```java JsonMapper mapper = JsonMapper.builder() @@ -24,8 +23,16 @@ JsonMapper mapper = JsonMapper.builder() .build(); GitHub github = Feign.builder() - .encoder(new Jackson3Encoder(mapper)) - .decoder(new Jackson3Decoder(mapper)) + .codec(new Jackson3Codec(mapper)) + .target(GitHub.class, "https://api.github.com"); +``` + +You can also configure the encoder and decoder separately: + +```java +GitHub github = Feign.builder() + .encoder(new Jackson3Encoder()) + .decoder(new Jackson3Decoder()) .target(GitHub.class, "https://api.github.com"); ``` diff --git a/jaxb/README.md b/jaxb/README.md index 1d36725f1d..8ba82407ae 100644 --- a/jaxb/README.md +++ b/jaxb/README.md @@ -3,7 +3,7 @@ JAXB Codec This module adds support for encoding and decoding XML via JAXB. -Add `JAXBEncoder` and/or `JAXBDecoder` to your `Feign.Builder` like so: +Add `JAXBCodec` to your `Feign.Builder` like so: ```java JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder() @@ -11,6 +11,14 @@ JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder() .withMarshallerSchemaLocation("http://apihost http://apihost/schema.xsd") .build(); +Response response = Feign.builder() + .codec(new JAXBCodec(jaxbFactory)) + .target(Response.class, "https://apihost"); +``` + +You can also configure the encoder and decoder separately: + +```java Response response = Feign.builder() .encoder(new JAXBEncoder(jaxbFactory)) .decoder(new JAXBDecoder(jaxbFactory)) diff --git a/moshi/README.md b/moshi/README.md index 1ffdb6fae3..6715ad4e79 100644 --- a/moshi/README.md +++ b/moshi/README.md @@ -3,7 +3,15 @@ Moshi Codec This module adds support for encoding and decoding JSON via the Moshi library. -Add `MoshiEncoder` and/or `MoshiDecoder` to your `Feign.Builder` like so: +Add `MoshiCodec` to your `Feign.Builder` like so: + +```java +GitHub github = Feign.builder() + .codec(new MoshiCodec()) + .target(GitHub.class, "https://api.github.com"); +``` + +You can also configure the encoder and decoder separately: ```java GitHub github = Feign.builder() diff --git a/soap-jakarta/README.md b/soap-jakarta/README.md index 6bcb5ce2cc..dfac4cc434 100644 --- a/soap-jakarta/README.md +++ b/soap-jakarta/README.md @@ -3,18 +3,18 @@ SOAP Codec This module adds support for encoding and decoding SOAP Body objects via JAXB and SOAPMessage. It also provides SOAPFault decoding capabilities by wrapping them into the original `javax.xml.ws.soap.SOAPFaultException`, so that you'll only need to catch `SOAPFaultException` in order to handle SOAPFault. -Add `SOAPEncoder` and/or `SOAPDecoder` to your `Feign.Builder` like so: +Add `SOAPCodec` to your `Feign.Builder` like so: ```java public interface MyApi { - + @RequestLine("POST /getObject") @Headers({ "SOAPAction: getObject", "Content-Type: text/xml" }) MyJaxbObjectResponse getObject(MyJaxbObjectRequest request); - + } ... @@ -25,8 +25,7 @@ public interface MyApi { .build(); api = Feign.builder() - .encoder(new SOAPEncoder(jaxbFactory)) - .decoder(new SOAPDecoder(jaxbFactory)) + .codec(new SOAPCodec(jaxbFactory)) .target(MyApi.class, "http://api"); ... @@ -36,15 +35,23 @@ public interface MyApi { } catch (SOAPFaultException faultException) { log.info(faultException.getFault().getFaultString()); } - + ``` -Because a SOAP Fault can be returned as well with a 200 http code than a 4xx or 5xx HTTP error code (depending on the used API), you may also use `SOAPErrorDecoder` in your API configuration, in order to be able to catch `SOAPFaultException` in case of SOAP Fault. Add it, like below: +You can also configure the encoder and decoder separately: ```java api = Feign.builder() .encoder(new SOAPEncoder(jaxbFactory)) .decoder(new SOAPDecoder(jaxbFactory)) + .target(MyApi.class, "http://api"); +``` + +Because a SOAP Fault can be returned as well with a 200 http code than a 4xx or 5xx HTTP error code (depending on the used API), you may also use `SOAPErrorDecoder` in your API configuration, in order to be able to catch `SOAPFaultException` in case of SOAP Fault. Add it, like below: + +```java +api = Feign.builder() + .codec(new SOAPCodec(jaxbFactory)) .errorDecoder(new SOAPErrorDecoder()) .target(MyApi.class, "http://api"); ``` diff --git a/soap/README.md b/soap/README.md index 6bcb5ce2cc..dfac4cc434 100644 --- a/soap/README.md +++ b/soap/README.md @@ -3,18 +3,18 @@ SOAP Codec This module adds support for encoding and decoding SOAP Body objects via JAXB and SOAPMessage. It also provides SOAPFault decoding capabilities by wrapping them into the original `javax.xml.ws.soap.SOAPFaultException`, so that you'll only need to catch `SOAPFaultException` in order to handle SOAPFault. -Add `SOAPEncoder` and/or `SOAPDecoder` to your `Feign.Builder` like so: +Add `SOAPCodec` to your `Feign.Builder` like so: ```java public interface MyApi { - + @RequestLine("POST /getObject") @Headers({ "SOAPAction: getObject", "Content-Type: text/xml" }) MyJaxbObjectResponse getObject(MyJaxbObjectRequest request); - + } ... @@ -25,8 +25,7 @@ public interface MyApi { .build(); api = Feign.builder() - .encoder(new SOAPEncoder(jaxbFactory)) - .decoder(new SOAPDecoder(jaxbFactory)) + .codec(new SOAPCodec(jaxbFactory)) .target(MyApi.class, "http://api"); ... @@ -36,15 +35,23 @@ public interface MyApi { } catch (SOAPFaultException faultException) { log.info(faultException.getFault().getFaultString()); } - + ``` -Because a SOAP Fault can be returned as well with a 200 http code than a 4xx or 5xx HTTP error code (depending on the used API), you may also use `SOAPErrorDecoder` in your API configuration, in order to be able to catch `SOAPFaultException` in case of SOAP Fault. Add it, like below: +You can also configure the encoder and decoder separately: ```java api = Feign.builder() .encoder(new SOAPEncoder(jaxbFactory)) .decoder(new SOAPDecoder(jaxbFactory)) + .target(MyApi.class, "http://api"); +``` + +Because a SOAP Fault can be returned as well with a 200 http code than a 4xx or 5xx HTTP error code (depending on the used API), you may also use `SOAPErrorDecoder` in your API configuration, in order to be able to catch `SOAPFaultException` in case of SOAP Fault. Add it, like below: + +```java +api = Feign.builder() + .codec(new SOAPCodec(jaxbFactory)) .errorDecoder(new SOAPErrorDecoder()) .target(MyApi.class, "http://api"); ``` From 7e412616947270e6ece202c1df45a91708996680 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 07:02:03 -0300 Subject: [PATCH 448/615] Consolidate lookupMetadata into GraphqlContract, simplify interceptor wrappers Signed-off-by: Marvin Froeder --- core/src/main/java/feign/BaseBuilder.java | 4 ++-- core/src/main/java/feign/RequestInterceptors.java | 4 ++-- core/src/main/java/feign/ResponseInterceptors.java | 4 ++-- .../main/java/feign/graphql/GraphqlContract.java | 8 ++++++++ .../main/java/feign/graphql/GraphqlEncoder.java | 14 +++----------- .../feign/graphql/GraphqlRequestInterceptor.java | 14 +++----------- 6 files changed, 20 insertions(+), 28 deletions(-) diff --git a/core/src/main/java/feign/BaseBuilder.java b/core/src/main/java/feign/BaseBuilder.java index 850fb47f63..354f01fab7 100644 --- a/core/src/main/java/feign/BaseBuilder.java +++ b/core/src/main/java/feign/BaseBuilder.java @@ -287,7 +287,7 @@ B enrich() { new RequestInterceptors(Arrays.asList(requestArray)), RequestInterceptors.class, capabilities); - clone.requestInterceptors = new ArrayList<>(requestInterceptors.interceptors()); + clone.requestInterceptors = requestInterceptors.interceptors(); // enrich each response interceptor, then enrich the list as a whole ResponseInterceptor[] responseArray = @@ -303,7 +303,7 @@ B enrich() { new ResponseInterceptors(Arrays.asList(responseArray)), ResponseInterceptors.class, capabilities); - clone.responseInterceptors = new ArrayList<>(responseInterceptors.interceptors()); + clone.responseInterceptors = responseInterceptors.interceptors(); return clone; } catch (CloneNotSupportedException e) { diff --git a/core/src/main/java/feign/RequestInterceptors.java b/core/src/main/java/feign/RequestInterceptors.java index dc7ea083c1..3376a7f526 100644 --- a/core/src/main/java/feign/RequestInterceptors.java +++ b/core/src/main/java/feign/RequestInterceptors.java @@ -24,10 +24,10 @@ public final class RequestInterceptors { private final List interceptors; public RequestInterceptors(List interceptors) { - this.interceptors = Collections.unmodifiableList(new ArrayList<>(interceptors)); + this.interceptors = new ArrayList<>(interceptors); } public List interceptors() { - return interceptors; + return Collections.unmodifiableList(interceptors); } } diff --git a/core/src/main/java/feign/ResponseInterceptors.java b/core/src/main/java/feign/ResponseInterceptors.java index 977a97abd5..52c943da3b 100644 --- a/core/src/main/java/feign/ResponseInterceptors.java +++ b/core/src/main/java/feign/ResponseInterceptors.java @@ -24,10 +24,10 @@ public final class ResponseInterceptors { private final List interceptors; public ResponseInterceptors(List interceptors) { - this.interceptors = Collections.unmodifiableList(new ArrayList<>(interceptors)); + this.interceptors = new ArrayList<>(interceptors); } public List interceptors() { - return interceptors; + return Collections.unmodifiableList(interceptors); } } diff --git a/graphql/src/main/java/feign/graphql/GraphqlContract.java b/graphql/src/main/java/feign/graphql/GraphqlContract.java index 3a84bf40e4..7e882fcfa0 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlContract.java +++ b/graphql/src/main/java/feign/graphql/GraphqlContract.java @@ -18,6 +18,7 @@ import feign.DefaultContract; import feign.Experimental; import feign.Request.HttpMethod; +import feign.RequestTemplate; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; @@ -52,6 +53,13 @@ Map queryMetadata() { return metadata; } + QueryMetadata lookupMetadata(RequestTemplate template) { + if (template.methodMetadata() == null) { + return null; + } + return metadata.get(template.methodMetadata().configKey()); + } + static String extractOperationField(String query) { int braceCount = 0; boolean inOperation = false; diff --git a/graphql/src/main/java/feign/graphql/GraphqlEncoder.java b/graphql/src/main/java/feign/graphql/GraphqlEncoder.java index e1807d17f3..4370a26220 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlEncoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlEncoder.java @@ -21,23 +21,22 @@ import feign.codec.Encoder; import java.lang.reflect.Type; import java.util.LinkedHashMap; -import java.util.Map; @Experimental public class GraphqlEncoder implements Encoder { private final Encoder delegate; - private final Map queryMetadata; + private final GraphqlContract contract; public GraphqlEncoder(Encoder delegate, GraphqlContract contract) { this.delegate = delegate; - this.queryMetadata = contract.queryMetadata(); + this.contract = contract; } @Override public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { - var meta = lookupMetadata(template); + var meta = contract.lookupMetadata(template); if (meta == null) { delegate.encode(object, bodyType, template); return; @@ -54,11 +53,4 @@ public void encode(Object object, Type bodyType, RequestTemplate template) delegate.encode(graphqlBody, MAP_STRING_WILDCARD, template); } - - private GraphqlContract.QueryMetadata lookupMetadata(RequestTemplate template) { - if (template.methodMetadata() == null) { - return null; - } - return queryMetadata.get(template.methodMetadata().configKey()); - } } diff --git a/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java b/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java index 21a74cf7e4..252834fc3d 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java +++ b/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java @@ -20,17 +20,16 @@ import feign.RequestTemplate; import feign.codec.Encoder; import java.util.LinkedHashMap; -import java.util.Map; @Experimental public class GraphqlRequestInterceptor implements RequestInterceptor { private final Encoder delegate; - private final Map queryMetadata; + private final GraphqlContract contract; public GraphqlRequestInterceptor(Encoder delegate, GraphqlContract contract) { this.delegate = delegate; - this.queryMetadata = contract.queryMetadata(); + this.contract = contract; } @Override @@ -39,7 +38,7 @@ public void apply(RequestTemplate template) { return; } - var meta = lookupMetadata(template); + var meta = contract.lookupMetadata(template); if (meta == null) { return; } @@ -49,11 +48,4 @@ public void apply(RequestTemplate template) { delegate.encode(graphqlBody, Encoder.MAP_STRING_WILDCARD, template); } - - private GraphqlContract.QueryMetadata lookupMetadata(RequestTemplate template) { - if (template.methodMetadata() == null) { - return null; - } - return queryMetadata.get(template.methodMetadata().configKey()); - } } From e58128516240dcd4298f436411fb8fd0c42c98bd Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 07:07:15 -0300 Subject: [PATCH 449/615] Fix pom.xml formatting Signed-off-by: Marvin Froeder --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 082fc8ccc1..7658ef159f 100644 --- a/pom.xml +++ b/pom.xml @@ -568,7 +568,7 @@ false ${jvm.options} - + From e522bfb9cd5c4091ad7c4201ac58736ef2b55dad Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 07:18:44 -0300 Subject: [PATCH 450/615] Fix GraphqlDecoder: Optional record fields return empty instead of null, non-nullable lists never return null Signed-off-by: Marvin Froeder --- .../java/feign/graphql/GraphqlDecoder.java | 75 +++++++++++++- .../feign/graphql/GraphqlDecoderTest.java | 98 +++++++++++++++++++ 2 files changed, 171 insertions(+), 2 deletions(-) diff --git a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java index 8adc726957..a85c391ad2 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java @@ -22,6 +22,7 @@ import feign.codec.JsonDecoder; import java.io.IOException; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.RecordComponent; import java.lang.reflect.Type; import java.util.Collections; import java.util.List; @@ -46,6 +47,9 @@ public Object decode(Response response, Type type) throws IOException { } var result = doDecode(response, targetType); + if (result == null && isCollectionOrArrayType(targetType)) { + result = Util.emptyValueOf(targetType); + } return optional ? Optional.ofNullable(result) : result; } @@ -55,7 +59,7 @@ private Object doDecode(Response response, Type type) throws IOException { return Util.emptyValueOf(type); } if (response.body() == null) { - return null; + return Util.emptyValueOf(type); } var root = (Map) jsonDecoder.decode(response, Map.class); @@ -94,7 +98,74 @@ private Object doDecode(Response response, Type type) throws IOException { operationData = list.get(0); } - return jsonDecoder.convert(operationData, type); + return convertWithOptionalSupport(operationData, type); + } + + @SuppressWarnings("unchecked") + private Object convertWithOptionalSupport(Object data, Type type) throws IOException { + if (data == null) { + return null; + } + + Class rawClass = rawClass(type); + if (rawClass == null || !rawClass.isRecord() || !(data instanceof Map)) { + return jsonDecoder.convert(data, type); + } + + if (!hasOptionalOrNestedRecordComponents(rawClass)) { + return jsonDecoder.convert(data, type); + } + + Map map = (Map) data; + RecordComponent[] components = rawClass.getRecordComponents(); + Object[] args = new Object[components.length]; + Class[] paramTypes = new Class[components.length]; + + for (int i = 0; i < components.length; i++) { + paramTypes[i] = components[i].getType(); + Object value = map.get(components[i].getName()); + + if (components[i].getType() == Optional.class) { + if (value == null) { + args[i] = Optional.empty(); + } else { + Type genericType = components[i].getGenericType(); + if (genericType instanceof ParameterizedType pt) { + Type innerType = pt.getActualTypeArguments()[0]; + args[i] = Optional.of(convertWithOptionalSupport(value, innerType)); + } else { + args[i] = Optional.of(value); + } + } + } else if (value != null) { + args[i] = convertWithOptionalSupport(value, components[i].getGenericType()); + } + } + + try { + return rawClass.getDeclaredConstructor(paramTypes).newInstance(args); + } catch (ReflectiveOperationException e) { + return jsonDecoder.convert(data, type); + } + } + + private boolean hasOptionalOrNestedRecordComponents(Class recordClass) { + for (RecordComponent c : recordClass.getRecordComponents()) { + if (c.getType() == Optional.class || c.getType().isRecord()) { + return true; + } + } + return false; + } + + private Class rawClass(Type type) { + if (type instanceof Class cls) { + return cls; + } + if (type instanceof ParameterizedType pt && pt.getRawType() instanceof Class cls) { + return cls; + } + return null; } @SuppressWarnings("unchecked") diff --git a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java index 97b289edd3..f3ac6b26bb 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java @@ -43,6 +43,14 @@ public static class User { public String name; } + public record UserRecord(String id, String name, Optional email) {} + + public record Address(String city, Optional zip) {} + + public record UserWithAddress(String id, Optional
address) {} + + public record DeeplyNested(String value, Optional nested) {} + @Test void decodesDataField() throws Exception { var json = "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Alice\"}}}"; @@ -220,6 +228,96 @@ void returnsOptionalEmptyForEmptyArray() throws Exception { assertThat(result).isEmpty(); } + @Test + void decodesRecordWithOptionalFieldPresent() throws Exception { + var json = + "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Alice\",\"email\":\"alice@test.com\"}}}"; + var response = buildResponse(json); + + var result = (UserRecord) decoder.decode(response, UserRecord.class); + + assertThat(result.id()).isEqualTo("1"); + assertThat(result.email()).isPresent(); + assertThat(result.email().get()).isEqualTo("alice@test.com"); + } + + @Test + void decodesRecordWithOptionalFieldNull() throws Exception { + var json = "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Alice\",\"email\":null}}}"; + var response = buildResponse(json); + + var result = (UserRecord) decoder.decode(response, UserRecord.class); + + assertThat(result.id()).isEqualTo("1"); + assertThat(result.email()).isEmpty(); + } + + @Test + void decodesRecordWithOptionalFieldMissing() throws Exception { + var json = "{\"data\":{\"getUser\":{\"id\":\"1\",\"name\":\"Alice\"}}}"; + var response = buildResponse(json); + + var result = (UserRecord) decoder.decode(response, UserRecord.class); + + assertThat(result.id()).isEqualTo("1"); + assertThat(result.email()).isEmpty(); + } + + @Test + void decodesNestedRecordWithOptionalFields() throws Exception { + var json = + "{\"data\":{\"getUser\":{\"id\":\"1\",\"address\":{\"city\":\"NYC\",\"zip\":null}}}}"; + var response = buildResponse(json); + + var result = (UserWithAddress) decoder.decode(response, UserWithAddress.class); + + assertThat(result.id()).isEqualTo("1"); + assertThat(result.address()).isPresent(); + assertThat(result.address().get().city()).isEqualTo("NYC"); + assertThat(result.address().get().zip()).isEmpty(); + } + + @Test + void decodesDeeplyNestedRecordWithOptionalFields() throws Exception { + var json = + "{\"data\":{\"get\":{\"value\":\"top\",\"nested\":{\"id\":\"1\",\"address\":{\"city\":\"NYC\",\"zip\":null}}}}}"; + var response = buildResponse(json); + + var result = (DeeplyNested) decoder.decode(response, DeeplyNested.class); + + assertThat(result.value()).isEqualTo("top"); + assertThat(result.nested()).isPresent(); + assertThat(result.nested().get().address()).isPresent(); + assertThat(result.nested().get().address().get().zip()).isEmpty(); + } + + @Test + void returnsEmptyListForNullBody() throws Exception { + var response = + Response.builder() + .status(200) + .reason("OK") + .headers(Collections.emptyMap()) + .request(buildRequest()) + .build(); + + @SuppressWarnings("unchecked") + var result = (List) decoder.decode(response, parameterizedType(List.class, User.class)); + + assertThat(result).isEmpty(); + } + + @Test + void returnsEmptyListForNullOperationDataWithListType() throws Exception { + var json = "{\"data\":{\"listUsers\":null}}"; + var response = buildResponse(json); + + @SuppressWarnings("unchecked") + var result = (List) decoder.decode(response, parameterizedType(List.class, User.class)); + + assertThat(result).isEmpty(); + } + private Response buildResponse(String body) { return Response.builder() .status(200) From a359645e337f1e1e13b1c4998031c9083808b27c Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 07:38:12 -0300 Subject: [PATCH 451/615] Simplify GraphqlDecoder convertWithOptionalSupport: use Types.getRawType, eliminate double-scan, use canonical constructor Signed-off-by: Marvin Froeder --- .../java/feign/graphql/GraphqlDecoder.java | 56 +++++++------------ 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java index a85c391ad2..f01768e978 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java @@ -17,6 +17,7 @@ import feign.Experimental; import feign.Response; +import feign.Types; import feign.Util; import feign.codec.Decoder; import feign.codec.JsonDecoder; @@ -107,65 +108,50 @@ private Object convertWithOptionalSupport(Object data, Type type) throws IOExcep return null; } - Class rawClass = rawClass(type); - if (rawClass == null || !rawClass.isRecord() || !(data instanceof Map)) { - return jsonDecoder.convert(data, type); - } - - if (!hasOptionalOrNestedRecordComponents(rawClass)) { + Class rawClass = Types.getRawType(type); + if (!rawClass.isRecord() || !(data instanceof Map)) { return jsonDecoder.convert(data, type); } Map map = (Map) data; RecordComponent[] components = rawClass.getRecordComponents(); Object[] args = new Object[components.length]; - Class[] paramTypes = new Class[components.length]; + boolean needsCustomConstruction = false; for (int i = 0; i < components.length; i++) { - paramTypes[i] = components[i].getType(); - Object value = map.get(components[i].getName()); + RecordComponent comp = components[i]; + Object value = map.get(comp.getName()); - if (components[i].getType() == Optional.class) { + if (comp.getType() == Optional.class) { + needsCustomConstruction = true; if (value == null) { args[i] = Optional.empty(); } else { - Type genericType = components[i].getGenericType(); + Type genericType = comp.getGenericType(); if (genericType instanceof ParameterizedType pt) { - Type innerType = pt.getActualTypeArguments()[0]; - args[i] = Optional.of(convertWithOptionalSupport(value, innerType)); + args[i] = + Optional.of(convertWithOptionalSupport(value, pt.getActualTypeArguments()[0])); } else { args[i] = Optional.of(value); } } - } else if (value != null) { - args[i] = convertWithOptionalSupport(value, components[i].getGenericType()); + } else if (comp.getType().isRecord()) { + needsCustomConstruction = true; + args[i] = value != null ? convertWithOptionalSupport(value, comp.getGenericType()) : null; + } else { + args[i] = value != null ? jsonDecoder.convert(value, comp.getGenericType()) : null; } } - try { - return rawClass.getDeclaredConstructor(paramTypes).newInstance(args); - } catch (ReflectiveOperationException e) { + if (!needsCustomConstruction) { return jsonDecoder.convert(data, type); } - } - private boolean hasOptionalOrNestedRecordComponents(Class recordClass) { - for (RecordComponent c : recordClass.getRecordComponents()) { - if (c.getType() == Optional.class || c.getType().isRecord()) { - return true; - } - } - return false; - } - - private Class rawClass(Type type) { - if (type instanceof Class cls) { - return cls; - } - if (type instanceof ParameterizedType pt && pt.getRawType() instanceof Class cls) { - return cls; + try { + return rawClass.getDeclaredConstructors()[0].newInstance(args); + } catch (ReflectiveOperationException e) { + return jsonDecoder.convert(data, type); } - return null; } @SuppressWarnings("unchecked") From eb5245b813c1774aa04892d6bcc1e4cf2fe4d822 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 11:08:02 -0300 Subject: [PATCH 452/615] Delegate Optional record field handling to Jackson instead of custom reflection Signed-off-by: Marvin Froeder --- graphql/README.md | 9 +++ graphql/pom.xml | 6 ++ .../java/feign/graphql/GraphqlDecoder.java | 56 +------------------ .../feign/graphql/GraphqlDecoderTest.java | 4 +- 4 files changed, 19 insertions(+), 56 deletions(-) diff --git a/graphql/README.md b/graphql/README.md index 626348301f..6f9ba883e2 100644 --- a/graphql/README.md +++ b/graphql/README.md @@ -161,6 +161,15 @@ Optional findTopUser(int limit); ## Optional Fields +When using `Optional<>` fields in records, your JSON codec must support `java.util.Optional`. For Jackson, add `jackson-datatype-jdk8` and register it: + +```java +ObjectMapper mapper = new ObjectMapper().findAndRegisterModules(); +UserApi api = Feign.builder() + .addCapability(new GraphqlCapability(new JacksonCodec(mapper))) + .target(UserApi.class, "https://api.example.com/graphql"); +``` + By default, nullable GraphQL fields (without `!`) are wrapped in `Optional<>` in generated records: ```graphql diff --git a/graphql/pom.xml b/graphql/pom.xml index 77dfe35763..6340e1a2c6 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -58,5 +58,11 @@ ${project.version} test + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + test + diff --git a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java index f01768e978..4486a239f4 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java @@ -17,13 +17,11 @@ import feign.Experimental; import feign.Response; -import feign.Types; import feign.Util; import feign.codec.Decoder; import feign.codec.JsonDecoder; import java.io.IOException; import java.lang.reflect.ParameterizedType; -import java.lang.reflect.RecordComponent; import java.lang.reflect.Type; import java.util.Collections; import java.util.List; @@ -99,59 +97,7 @@ private Object doDecode(Response response, Type type) throws IOException { operationData = list.get(0); } - return convertWithOptionalSupport(operationData, type); - } - - @SuppressWarnings("unchecked") - private Object convertWithOptionalSupport(Object data, Type type) throws IOException { - if (data == null) { - return null; - } - - Class rawClass = Types.getRawType(type); - if (!rawClass.isRecord() || !(data instanceof Map)) { - return jsonDecoder.convert(data, type); - } - - Map map = (Map) data; - RecordComponent[] components = rawClass.getRecordComponents(); - Object[] args = new Object[components.length]; - boolean needsCustomConstruction = false; - - for (int i = 0; i < components.length; i++) { - RecordComponent comp = components[i]; - Object value = map.get(comp.getName()); - - if (comp.getType() == Optional.class) { - needsCustomConstruction = true; - if (value == null) { - args[i] = Optional.empty(); - } else { - Type genericType = comp.getGenericType(); - if (genericType instanceof ParameterizedType pt) { - args[i] = - Optional.of(convertWithOptionalSupport(value, pt.getActualTypeArguments()[0])); - } else { - args[i] = Optional.of(value); - } - } - } else if (comp.getType().isRecord()) { - needsCustomConstruction = true; - args[i] = value != null ? convertWithOptionalSupport(value, comp.getGenericType()) : null; - } else { - args[i] = value != null ? jsonDecoder.convert(value, comp.getGenericType()) : null; - } - } - - if (!needsCustomConstruction) { - return jsonDecoder.convert(data, type); - } - - try { - return rawClass.getDeclaredConstructors()[0].newInstance(args); - } catch (ReflectiveOperationException e) { - return jsonDecoder.convert(data, type); - } + return jsonDecoder.convert(operationData, type); } @SuppressWarnings("unchecked") diff --git a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java index f3ac6b26bb..b796a68612 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java @@ -35,7 +35,9 @@ class GraphqlDecoderTest { private final ObjectMapper mapper = - new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .findAndRegisterModules(); private final GraphqlDecoder decoder = new GraphqlDecoder(new JacksonDecoder(mapper)); public static class User { From 8ea64555d46a26203c085b6df79460f31b5557cb Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 12:36:15 -0300 Subject: [PATCH 453/615] Add parameterized test for GraphQL Optional field decoding across codecs Signed-off-by: Marvin Froeder --- graphql/pom.xml | 15 +++ .../GraphqlDecoderOptionalFieldCodecTest.java | 111 ++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java diff --git a/graphql/pom.xml b/graphql/pom.xml index 6340e1a2c6..354151b88b 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -64,5 +64,20 @@ jackson-datatype-jdk8 test + + + ${project.groupId} + feign-mock + ${project.version} + test + + + + ${project.groupId} + feign-jackson3 + ${project.version} + test + + diff --git a/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java b/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java new file mode 100644 index 0000000000..802a8479b2 --- /dev/null +++ b/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java @@ -0,0 +1,111 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.graphql; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import feign.Feign; +import feign.Headers; +import feign.codec.JsonCodec; +import feign.jackson.JacksonCodec; +import feign.jackson3.Jackson3Codec; +import feign.mock.HttpMethod; +import feign.mock.MockClient; +import feign.mock.MockTarget; +import java.util.Optional; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import tools.jackson.databind.json.JsonMapper; + +// Gson, Moshi, and Fastjson2 don't support Optional fields in records +class GraphqlDecoderOptionalFieldCodecTest { + + public record Item(String name, Optional step) {} + + @Headers("Content-Type: application/json") + interface ItemApi { + + @GraphqlQuery("query { item(id: \"1\") { name step } }") + Item getItem(); + } + + static Stream codecs() { + var jackson = + new JacksonCodec( + new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .findAndRegisterModules()); + + var jackson3 = + new Jackson3Codec( + JsonMapper.builder() + .disable(tools.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .build()); + + return Stream.of(Arguments.of("jackson", jackson), Arguments.of("jackson3", jackson3)); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("codecs") + void stepExplicitNull(String name, JsonCodec codec) { + var mockClient = new MockClient(); + mockClient.ok(HttpMethod.POST, "/", "{\"data\":{\"item\":{\"name\":\"test\",\"step\":null}}}"); + + var api = buildClient(mockClient, codec); + var item = api.getItem(); + + assertThat(item.name()).isEqualTo("test"); + assertThat(item.step()).isEmpty(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("codecs") + void stepMissing(String name, JsonCodec codec) { + var mockClient = new MockClient(); + mockClient.ok(HttpMethod.POST, "/", "{\"data\":{\"item\":{\"name\":\"test\"}}}"); + + var api = buildClient(mockClient, codec); + var item = api.getItem(); + + assertThat(item.name()).isEqualTo("test"); + assertThat(item.step()).isEmpty(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("codecs") + void stepPresent(String name, JsonCodec codec) { + var mockClient = new MockClient(); + mockClient.ok( + HttpMethod.POST, "/", "{\"data\":{\"item\":{\"name\":\"test\",\"step\":\"foo\"}}}"); + + var api = buildClient(mockClient, codec); + var item = api.getItem(); + + assertThat(item.name()).isEqualTo("test"); + assertThat(item.step()).isPresent().hasValue("foo"); + } + + private ItemApi buildClient(MockClient mockClient, JsonCodec codec) { + return Feign.builder() + .addCapability(new GraphqlCapability(codec)) + .client(mockClient) + .target(new MockTarget<>(ItemApi.class)); + } +} From ae1c7c8ae2c232b17922f9330804f5b166b05bfe Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 12:39:08 -0300 Subject: [PATCH 454/615] Use text blocks for JSON payloads and GraphQL query Signed-off-by: Marvin Froeder --- .../GraphqlDecoderOptionalFieldCodecTest.java | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java b/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java index 802a8479b2..6dc11c6625 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java @@ -42,7 +42,15 @@ public record Item(String name, Optional step) {} @Headers("Content-Type: application/json") interface ItemApi { - @GraphqlQuery("query { item(id: \"1\") { name step } }") + @GraphqlQuery( + """ + query { + item(id: "1") { + name + step + } + } + """) Item getItem(); } @@ -66,7 +74,19 @@ static Stream codecs() { @MethodSource("codecs") void stepExplicitNull(String name, JsonCodec codec) { var mockClient = new MockClient(); - mockClient.ok(HttpMethod.POST, "/", "{\"data\":{\"item\":{\"name\":\"test\",\"step\":null}}}"); + mockClient.ok( + HttpMethod.POST, + "/", + """ + { + "data": { + "item": { + "name": "test", + "step": null + } + } + } + """); var api = buildClient(mockClient, codec); var item = api.getItem(); @@ -79,7 +99,18 @@ void stepExplicitNull(String name, JsonCodec codec) { @MethodSource("codecs") void stepMissing(String name, JsonCodec codec) { var mockClient = new MockClient(); - mockClient.ok(HttpMethod.POST, "/", "{\"data\":{\"item\":{\"name\":\"test\"}}}"); + mockClient.ok( + HttpMethod.POST, + "/", + """ + { + "data": { + "item": { + "name": "test" + } + } + } + """); var api = buildClient(mockClient, codec); var item = api.getItem(); @@ -93,7 +124,18 @@ void stepMissing(String name, JsonCodec codec) { void stepPresent(String name, JsonCodec codec) { var mockClient = new MockClient(); mockClient.ok( - HttpMethod.POST, "/", "{\"data\":{\"item\":{\"name\":\"test\",\"step\":\"foo\"}}}"); + HttpMethod.POST, + "/", + """ + { + "data": { + "item": { + "name": "test", + "step": "foo" + } + } + } + """); var api = buildClient(mockClient, codec); var item = api.getItem(); From 0e44c31b34a4d372ea07b1fd68766937add84af5 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Tue, 17 Mar 2026 12:39:54 -0300 Subject: [PATCH 455/615] Remove unnecessary comment Signed-off-by: Marvin Froeder --- .../java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java b/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java index 6dc11c6625..2b0dced355 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlDecoderOptionalFieldCodecTest.java @@ -34,7 +34,6 @@ import org.junit.jupiter.params.provider.MethodSource; import tools.jackson.databind.json.JsonMapper; -// Gson, Moshi, and Fastjson2 don't support Optional fields in records class GraphqlDecoderOptionalFieldCodecTest { public record Item(String name, Optional step) {} From 81216a792632d4ec71bddd8f4d3c8b7094cdd31f Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Wed, 18 Mar 2026 06:36:57 -0300 Subject: [PATCH 456/615] Add useAliasForFieldNames config to graphql-apt for alias-aware record naming Signed-off-by: Marvin Froeder --- .../graphql/apt/GraphqlSchemaProcessor.java | 30 ++++- .../graphql/apt/TypeAnnotationConfig.java | 26 +++- .../java/feign/graphql/apt/TypeGenerator.java | 16 ++- .../apt/GraphqlSchemaProcessorTest.java | 123 ++++++++++++++++++ .../main/java/feign/graphql/GraphqlQuery.java | 2 + .../java/feign/graphql/GraphqlSchema.java | 2 + 6 files changed, 187 insertions(+), 12 deletions(-) diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java index 00ade4099c..575d89a001 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java @@ -418,6 +418,7 @@ private TypeAnnotationConfig resolveClassConfig( fqns, rawAnnotations, annotation.useOptional(), + annotation.useAliasForFieldNames(), classFieldAnnotations, nonNullFqns, nonNullRaw); @@ -434,6 +435,7 @@ private TypeAnnotationConfig resolveClassConfig( mergedImports, config.annotations(), config.useOptional(), + config.useAliasForFieldNames(), config.fieldAnnotations(), config.nonNullAnnotations()); } @@ -451,10 +453,17 @@ private TypeAnnotationConfig resolveMethodConfig( ExecutableElement method, GraphqlQuery annotation, TypeAnnotationConfig classConfig) { var methodFqns = extractClassFqns(annotation::typeAnnotations); var methodRaw = annotation.rawTypeAnnotations(); - var methodToggle = annotation.useOptional(); + var methodOptionalToggle = annotation.useOptional(); + var methodAliasToggle = annotation.useAliasForFieldNames(); var useOptional = - methodToggle == Toggle.INHERIT ? classConfig.useOptional() : methodToggle == Toggle.TRUE; + methodOptionalToggle == Toggle.INHERIT + ? classConfig.useOptional() + : methodOptionalToggle == Toggle.TRUE; + var useAliasForFieldNames = + methodAliasToggle == Toggle.INHERIT + ? classConfig.useAliasForFieldNames() + : methodAliasToggle == Toggle.TRUE; var methodFieldAnnotations = extractFieldAnnotations(method); var fieldAnnotations = @@ -469,6 +478,7 @@ private TypeAnnotationConfig resolveMethodConfig( boolean hasMethodAnnotations = !methodFqns.isEmpty() || methodRaw.length > 0; if (!hasMethodAnnotations && !hasMethodNonNull) { if (useOptional == classConfig.useOptional() + && useAliasForFieldNames == classConfig.useAliasForFieldNames() && fieldAnnotations.equals(classConfig.fieldAnnotations())) { return classConfig; } @@ -480,6 +490,7 @@ private TypeAnnotationConfig resolveMethodConfig( mergedImports, classConfig.annotations(), useOptional, + useAliasForFieldNames, fieldAnnotations, classConfig.nonNullAnnotations()); } @@ -488,13 +499,24 @@ private TypeAnnotationConfig resolveMethodConfig( var nonNullRaw = hasMethodNonNull ? methodNonNullRaw : new String[0]; var config = TypeAnnotationConfig.resolve( - methodFqns, methodRaw, useOptional, fieldAnnotations, nonNullFqns, nonNullRaw); + methodFqns, + methodRaw, + useOptional, + useAliasForFieldNames, + fieldAnnotations, + nonNullFqns, + nonNullRaw); if (resolvedNonNull != null && !resolvedNonNull.isEmpty()) { var mergedImports = new TreeSet<>(config.imports()); mergedImports.addAll(classConfig.imports()); return new TypeAnnotationConfig( - mergedImports, config.annotations(), useOptional, fieldAnnotations, resolvedNonNull); + mergedImports, + config.annotations(), + useOptional, + useAliasForFieldNames, + fieldAnnotations, + resolvedNonNull); } return config; diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java index a1d17e0f1b..4cb94b7787 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java @@ -27,27 +27,39 @@ record TypeAnnotationConfig( Set imports, List annotations, boolean useOptional, + boolean useAliasForFieldNames, Map fieldAnnotations, List nonNullAnnotations) { static final TypeAnnotationConfig EMPTY = - new TypeAnnotationConfig(Set.of(), List.of(), false, Map.of(), List.of()); + new TypeAnnotationConfig(Set.of(), List.of(), false, true, Map.of(), List.of()); static TypeAnnotationConfig resolve( - List typeAnnotationFqns, String[] rawTypeAnnotations, boolean useOptional) { + List typeAnnotationFqns, + String[] rawTypeAnnotations, + boolean useOptional, + boolean useAliasForFieldNames) { return resolve( - typeAnnotationFqns, rawTypeAnnotations, useOptional, Map.of(), List.of(), new String[0]); + typeAnnotationFqns, + rawTypeAnnotations, + useOptional, + useAliasForFieldNames, + Map.of(), + List.of(), + new String[0]); } static TypeAnnotationConfig resolve( List typeAnnotationFqns, String[] rawTypeAnnotations, boolean useOptional, + boolean useAliasForFieldNames, Map fieldAnnotations) { return resolve( typeAnnotationFqns, rawTypeAnnotations, useOptional, + useAliasForFieldNames, fieldAnnotations, List.of(), new String[0]); @@ -57,6 +69,7 @@ static TypeAnnotationConfig resolve( List typeAnnotationFqns, String[] rawTypeAnnotations, boolean useOptional, + boolean useAliasForFieldNames, Map fieldAnnotations, List nonNullFqns, String[] nonNullRawAnnotations) { @@ -71,7 +84,12 @@ static TypeAnnotationConfig resolve( var nonNullResolved = resolveAnnotationList(nonNullFqns, nonNullRawAnnotations, imports); return new TypeAnnotationConfig( - imports, annotations, useOptional, fieldAnnotations, nonNullResolved); + imports, + annotations, + useOptional, + useAliasForFieldNames, + fieldAnnotations, + nonNullResolved); } static List resolveAnnotationList( diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java index 87341b1709..05e3064ada 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java @@ -139,11 +139,12 @@ private ResultTypeDefinition buildResultType( if (!(selection instanceof Field field)) { continue; } - var fieldName = field.getName(); - var schemaDef = GraphqlTypeMapper.findFieldDefinition(parentType, fieldName); + var schemaFieldName = field.getName(); + var schemaDef = GraphqlTypeMapper.findFieldDefinition(parentType, schemaFieldName); if (schemaDef == null) { continue; } + var fieldName = responseKey(field); var fieldType = schemaDef.getType(); var rawTypeName = GraphqlTypeMapper.unwrapTypeName(fieldType); @@ -243,13 +244,20 @@ private void collectAllImports(ResultTypeDefinition tree, Set imports) { } } + private String responseKey(Field field) { + if (annotationConfig.useAliasForFieldNames() && field.getAlias() != null) { + return field.getAlias(); + } + return field.getName(); + } + private String canonicalize(SelectionSet selectionSet) { var entries = new ArrayList(); for (var selection : selectionSet.getSelections()) { if (!(selection instanceof Field field)) { continue; } - var name = field.getName(); + var name = responseKey(field); if (field.getSelectionSet() != null && !field.getSelectionSet().getSelections().isEmpty()) { entries.add(name + "{" + canonicalize(field.getSelectionSet()) + "}"); } else { @@ -266,7 +274,7 @@ private String describeFields(SelectionSet selectionSet) { if (!(selection instanceof Field field)) { continue; } - var name = field.getName(); + var name = responseKey(field); if (field.getSelectionSet() != null && !field.getSelectionSet().getSelections().isEmpty()) { entries.add(name + " { " + describeFields(field.getSelectionSet()) + " }"); } else { diff --git a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java index 180c223ad0..f60c6e22b2 100644 --- a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java +++ b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java @@ -1790,4 +1790,127 @@ interface NonNullFieldComboApi { contents.contains("@Deprecated String id"); contents.contains("String email"); } + + @Test + void useAliasForFieldNamesGeneratesAliasedInnerRecords() { + var source = + JavaFileObjects.forSourceString( + "test.AliasApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useAliasForFieldNames = true) + interface AliasApi { + @GraphqlQuery(\""" + { + starship(id: "1") { + id name + specification: specs { lengthMeters classification } + currentLocation: location { planet sector } + } + }\""") + StarshipResult getStarship(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.StarshipResult").contentsAsUtf8String(); + contents.contains("Optional specification"); + contents.contains("Optional currentLocation"); + contents.contains("public record Specification("); + contents.contains("public record CurrentLocation("); + } + + @Test + void useAliasForFieldNamesDisabledUsesFieldName() { + var source = + JavaFileObjects.forSourceString( + "test.NoAliasApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "test-schema.graphql", useAliasForFieldNames = false) + interface NoAliasApi { + @GraphqlQuery(\""" + { + starship(id: "1") { + id name + specification: specs { lengthMeters classification } + currentLocation: location { planet sector } + } + }\""") + StarshipResult getStarship(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var contents = + assertThat(compilation).generatedSourceFile("test.StarshipResult").contentsAsUtf8String(); + contents.contains("Optional specs"); + contents.contains("Optional location"); + contents.contains("public record Specs("); + contents.contains("public record Location("); + } + + @Test + void useAliasForFieldNamesMethodOverridesClassLevel() { + var source = + JavaFileObjects.forSourceString( + "test.AliasOverrideApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.Toggle; + + @GraphqlSchema(value = "test-schema.graphql", useAliasForFieldNames = false) + interface AliasOverrideApi { + @GraphqlQuery(value = \""" + { + starship(id: "1") { + id name + specification: specs { lengthMeters classification } + } + }\""", useAliasForFieldNames = Toggle.TRUE) + AliasedResult getAliased(); + + @GraphqlQuery(\""" + { + starship(id: "1") { + id name + specification: specs { lengthMeters classification } + } + }\""") + PlainResult getPlain(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + + var aliased = + assertThat(compilation).generatedSourceFile("test.AliasedResult").contentsAsUtf8String(); + aliased.contains("Optional specification"); + aliased.contains("public record Specification("); + + var plain = + assertThat(compilation).generatedSourceFile("test.PlainResult").contentsAsUtf8String(); + plain.contains("Optional specs"); + plain.contains("public record Specs("); + } } diff --git a/graphql/src/main/java/feign/graphql/GraphqlQuery.java b/graphql/src/main/java/feign/graphql/GraphqlQuery.java index 4cc896d6d0..964c70ddd7 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlQuery.java +++ b/graphql/src/main/java/feign/graphql/GraphqlQuery.java @@ -30,6 +30,8 @@ Toggle useOptional() default Toggle.INHERIT; + Toggle useAliasForFieldNames() default Toggle.INHERIT; + Class[] typeAnnotations() default {}; String[] rawTypeAnnotations() default {}; diff --git a/graphql/src/main/java/feign/graphql/GraphqlSchema.java b/graphql/src/main/java/feign/graphql/GraphqlSchema.java index 5d97e983c4..4f5799b41e 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlSchema.java +++ b/graphql/src/main/java/feign/graphql/GraphqlSchema.java @@ -32,6 +32,8 @@ boolean useOptional() default true; + boolean useAliasForFieldNames() default true; + Class[] uses() default {}; Class[] typeAnnotations() default {}; From e8df6b6ce38a5906f939fdfd2bcaaaf0d18e04af Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Wed, 18 Mar 2026 06:52:59 -0300 Subject: [PATCH 457/615] prepare release 13.11 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index aaa366a863..ae6d7ef143 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index ab4d29905f..f892884c22 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 62b34d6b53..0e02d062a5 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index b9a0dff4cb..eb576aae3f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 9bf372e8a4..cd8442b6ba 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 238c14cd5b..7185b9e5f2 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 482e16f1f5..ee22291b25 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 7f32e7e1c3..1d2ebc032a 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 5f6b3e92fa..db28da934b 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 61796147dc..e0e5cde036 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 40c9b2ebca..1a6a478e96 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 9e466d206d..051e6b0f7c 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index bda2640041..61e63e66b1 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 875eb2941e..a552d0eae2 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index c48d8c7037..84478870ad 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 354151b88b..53453d8a95 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index e32b9c6618..b41d6c3803 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 1f4e15b80a..6043c42555 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 43c68c9794..130db39198 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 00bfda8513..b4dd8e1785 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 554078bff4..67042ea4a8 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index 12311225c1..bfae09ce6f 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 31449fc855..cdb28a0338 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 1d3a815680..6b7c55d11d 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 54239a0606..6586905fa7 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 2512723fcc..42c01e75c1 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 364782bb80..0a00fbf7b7 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 51a73c3d7d..76d614db4b 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index e574d20fb3..dfb591442d 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 6b4b605b5b..36356aae17 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 99dace963c..3a3ce9dcdf 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 47738dbac6..f0adaa79d0 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index ee6492da48..03e8a9eb5d 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index c454a26032..5a705cd8f5 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 76fa9f1170..40567fe5bf 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 90391bc993..26e6cc0f82 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index b6104e9063..425a5988a8 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index bc886c8f8a..bb9f57fe2e 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-okhttp diff --git a/pom.xml b/pom.xml index 7658ef159f..c687e4bea2 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 8949c3d5c2..4d65381c53 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 9f9a738871..ac0cad8193 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 6a8fc82f5f..98cd1a3c17 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index da921a999e..962603b0cb 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 7ce24d3768..7038bca253 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 6da9458911..9131a49407 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index e9722f5da6..98e1a96785 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index b8f699ec31..dd5ce1f499 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 55ee0bec86..99ce4dceae 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.11-SNAPSHOT + 13.11 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 039d121e70..1ed915de64 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.11-SNAPSHOT + 13.11 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 40ad8063ac..ff98b5e677 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.11-SNAPSHOT + 13.11 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index bd8cae47a7..09853fc2c5 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11-SNAPSHOT + 13.11 feign-vertx-parent From 9045ac8971e6034dfbdc5369c1eefe9d9af08106 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Wed, 18 Mar 2026 06:53:12 -0300 Subject: [PATCH 458/615] [ci skip] updating versions to next development iteration 13.12-SNAPSHOT --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index ae6d7ef143..c014de0401 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index f892884c22..aaeb1b7a04 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 0e02d062a5..9cf0959ced 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index eb576aae3f..fb9bf5129e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index cd8442b6ba..2113f27022 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 7185b9e5f2..c59139b5f7 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index ee22291b25..03acb10f8f 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 1d2ebc032a..e20290b054 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index db28da934b..1cca9e5925 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index e0e5cde036..c342fe4cb6 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 1a6a478e96..a50a0a0d84 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 051e6b0f7c..e00910eba2 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 61e63e66b1..0d827c9760 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index a552d0eae2..ee57d9cc82 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index 84478870ad..e7cb3e6948 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index 53453d8a95..b4199d3bd0 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index b41d6c3803..1f69a0ec59 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 6043c42555..3d385a8f99 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 130db39198..c277048cfa 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index b4dd8e1785..42e1c9f12a 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 67042ea4a8..7f1fdcdf0a 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index bfae09ce6f..af89b3a5da 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index cdb28a0338..9347a731bb 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 6b7c55d11d..db3a73ea23 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 6586905fa7..be5af86003 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 42c01e75c1..4a9d9d05b9 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 0a00fbf7b7..1dd83992b5 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 76d614db4b..bc8c15a215 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index dfb591442d..6d6fcff7b3 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 36356aae17..21cbcac6d0 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 3a3ce9dcdf..5b13d3e4e6 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index f0adaa79d0..42f7cbae50 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 03e8a9eb5d..a11e3d45db 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 5a705cd8f5..9ad1bc7233 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 40567fe5bf..58d5976a28 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 26e6cc0f82..698cff2151 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 425a5988a8..d80167cee5 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index bb9f57fe2e..7fa6c1b6d2 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index c687e4bea2..671eb12c9a 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 4d65381c53..a7eb57ff73 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index ac0cad8193..941bad579e 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 98cd1a3c17..327b9e490f 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 962603b0cb..497558323c 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 7038bca253..b8b8f14058 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 9131a49407..ecd6d1d682 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 98e1a96785..fe3ca30ce9 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index dd5ce1f499..173f05db3e 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 99ce4dceae..8508f3e62b 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.11 + 13.12-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 1ed915de64..047f51608c 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.11 + 13.12-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index ff98b5e677..dd3856c51d 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.11 + 13.12-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 09853fc2c5..f5ec1f1c55 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.11 + 13.12-SNAPSHOT feign-vertx-parent From 5cf77735f91b7ba2c478d1373bc0781f721f7b3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 05:25:07 +0000 Subject: [PATCH 459/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.33.0 to 6.34.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.33.0...v6.34.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.34.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 671eb12c9a..869b52a349 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 3.2.0 1.2.8 4.0.0 - 6.33.0 + 6.34.0 3.30.0 3.30.0 0.25.4 From 5c44b1d1bf67169938c643de2b5c8f44dae69029 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 05:26:01 +0000 Subject: [PATCH 460/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.30.0 to 3.30.1. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.30.0...v3.30.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.30.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 671eb12c9a..f9d5273da2 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 4.0.0 6.33.0 3.30.0 - 3.30.0 + 3.30.1 0.25.4 1.0 From b72a2f69a34d6bd6aaf0711d2c61a4808f603f93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 05:26:16 +0000 Subject: [PATCH 461/615] build(deps-dev): Bump jersey.version from 2.47 to 2.48 in /jaxrs2 Bumps `jersey.version` from 2.47 to 2.48. Updates `org.glassfish.jersey.core:jersey-client` from 2.47 to 2.48 Updates `org.glassfish.jersey.inject:jersey-hk2` from 2.47 to 2.48 --- updated-dependencies: - dependency-name: org.glassfish.jersey.core:jersey-client dependency-version: '2.48' dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: org.glassfish.jersey.inject:jersey-hk2 dependency-version: '2.48' dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- jaxrs2/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 21cbcac6d0..7e8983a0d1 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -31,7 +31,7 @@ true - 2.47 + 2.48 From 4346dc02eae293b34a691ddef62fdcee117ae47e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 05:23:57 +0000 Subject: [PATCH 462/615] build(deps): Bump springboot.version from 4.0.3 to 4.0.4 Bumps `springboot.version` from 4.0.3 to 4.0.4. Updates `org.springframework.boot:spring-boot-maven-plugin` from 4.0.3 to 4.0.4 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.3...v4.0.4) Updates `org.springframework.boot:spring-boot-starter-web` from 4.0.3 to 4.0.4 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.3...v4.0.4) Updates `org.springframework.boot:spring-boot-starter-test` from 4.0.3 to 4.0.4 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.3...v4.0.4) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-maven-plugin dependency-version: 4.0.4 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: org.springframework.boot:spring-boot-starter-web dependency-version: 4.0.4 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.springframework.boot:spring-boot-starter-test dependency-version: 4.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d717ee9494..beb662731b 100644 --- a/pom.xml +++ b/pom.xml @@ -167,7 +167,7 @@ 1.15.2 2.0.17 20251224 - 4.0.3 + 4.0.4 6.0.3 2.21.1 From a0eedd22e1e7ddc8981269a8dc8be4dcff8080e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 05:30:00 +0000 Subject: [PATCH 463/615] build(deps-dev): Bump io.undertow:undertow-core Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.23.Final to 2.3.24.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.23.Final...2.3.24.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-version: 2.3.24.Final dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index beb662731b..528f2926ef 100644 --- a/pom.xml +++ b/pom.xml @@ -245,7 +245,7 @@ 5.0.1 7.0.6 7.0.6 - 2.3.23.Final + 2.3.24.Final 1.18.0 From c6f169de93320f1c98f3cf82a44cf08181a27373 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 05:31:12 +0000 Subject: [PATCH 464/615] build(deps): Bump jackson.version from 2.21.1 to 2.21.2 Bumps `jackson.version` from 2.21.1 to 2.21.2. Updates `com.fasterxml.jackson:jackson-bom` from 2.21.1 to 2.21.2 - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.21.1...jackson-bom-2.21.2) Updates `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider` from 2.21.1 to 2.21.2 --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.21.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-version: 2.21.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index beb662731b..047b052140 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 4.0.4 6.0.3 - 2.21.1 + 2.21.2 3.1.0 3.27.7 5.23.0 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 8508f3e62b..832b396a32 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -31,7 +31,7 @@ 11 - 2.21.1 + 2.21.2 From 161c42455ba1c5a6e3da0370af569b77cfb43481 Mon Sep 17 00:00:00 2001 From: Yevhen Vasyliev Date: Mon, 23 Mar 2026 16:12:59 +0200 Subject: [PATCH 465/615] feat(form): enhance UrlencodedFormContentProcessor to support CollectionFormats in key-value pairs --- CHANGELOG.md | 5 + .../form/UrlencodedFormContentProcessor.java | 44 ++--- .../UrlencodedFormContentProcessorTest.java | 162 ++++++++++++++++++ 3 files changed, 184 insertions(+), 27 deletions(-) create mode 100644 form/src/test/java/feign/form/UrlencodedFormContentProcessorTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f3c52d2fe..42d4bb75fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### Version 13.12 + +* `UrlencodedFormContentProcessor` now honors `CollectionFormat` from `@RequestLine`/`RequestTemplate` for array and + collection values in `application/x-www-form-urlencoded` bodies. + ### Version 11.9 * `OkHttpClient` now implements `AsyncClient` diff --git a/form/src/main/java/feign/form/UrlencodedFormContentProcessor.java b/form/src/main/java/feign/form/UrlencodedFormContentProcessor.java index 1113c35821..14fb8166ec 100644 --- a/form/src/main/java/feign/form/UrlencodedFormContentProcessor.java +++ b/form/src/main/java/feign/form/UrlencodedFormContentProcessor.java @@ -17,14 +17,19 @@ import static feign.form.ContentType.URLENCODED; +import feign.CollectionFormat; import feign.RequestTemplate; import feign.codec.EncodeException; import java.net.URLEncoder; import java.nio.charset.Charset; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; import lombok.SneakyThrows; import lombok.val; @@ -55,7 +60,7 @@ public void process(RequestTemplate template, Charset charset, Map 0) { bodyData.append(QUERY_DELIMITER); } - bodyData.append(createKeyValuePair(entry, charset)); + bodyData.append(createKeyValuePair(template.collectionFormat(), entry, charset)); } val contentTypeValue = @@ -77,16 +82,19 @@ public ContentType getSupportedContentType() { return URLENCODED; } - private String createKeyValuePair(Entry entry, Charset charset) { + private CharSequence createKeyValuePair( + CollectionFormat collectionFormat, Entry entry, Charset charset) { String encodedKey = encode(entry.getKey(), charset); Object value = entry.getValue(); if (value == null) { return encodedKey; } else if (value.getClass().isArray()) { - return createKeyValuePairFromArray(encodedKey, value, charset); + return createKeyValuePair( + collectionFormat, encodedKey, Arrays.stream((Object[]) value), charset); } else if (value instanceof Collection) { - return createKeyValuePairFromCollection(encodedKey, value, charset); + return createKeyValuePair( + collectionFormat, encodedKey, ((Collection) value).stream(), charset); } return new StringBuilder() .append(encodedKey) @@ -95,28 +103,10 @@ private String createKeyValuePair(Entry entry, Charset charset) .toString(); } - private String createKeyValuePairFromCollection(String key, Object values, Charset charset) { - val collection = (Collection) values; - val array = collection.toArray(new Object[0]); - return createKeyValuePairFromArray(key, array, charset); - } - - private String createKeyValuePairFromArray(String key, Object values, Charset charset) { - val result = new StringBuilder(); - val array = (Object[]) values; - - for (int index = 0; index < array.length; index++) { - val value = array[index]; - if (value == null) { - continue; - } - - if (index > 0) { - result.append(QUERY_DELIMITER); - } - - result.append(key).append(EQUAL_SIGN).append(encode(value, charset)); - } - return result.toString(); + private CharSequence createKeyValuePair( + CollectionFormat collectionFormat, String key, Stream values, Charset charset) { + val stringValues = + values.filter(Objects::nonNull).map(Object::toString).collect(Collectors.toList()); + return collectionFormat.join(key, stringValues, charset); } } diff --git a/form/src/test/java/feign/form/UrlencodedFormContentProcessorTest.java b/form/src/test/java/feign/form/UrlencodedFormContentProcessorTest.java new file mode 100644 index 0000000000..17cf99ea68 --- /dev/null +++ b/form/src/test/java/feign/form/UrlencodedFormContentProcessorTest.java @@ -0,0 +1,162 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.form; + +import static org.assertj.core.api.Assertions.assertThat; + +import feign.CollectionFormat; +import feign.Feign; +import feign.Headers; +import feign.RequestLine; +import feign.form.utils.UndertowServer; +import feign.jackson.JacksonEncoder; +import io.undertow.server.HttpServerExchange; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.BiFunction; +import org.junit.jupiter.api.Test; + +class UrlencodedFormContentProcessorTest { + + @Test + void arrayValueUsesDefaultExplodedCollectionFormat() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=one&tags=two", + new String[] {"one", "two"}, Client::map); + } + + @Test + void collectionValueUsesDefaultExplodedCollectionFormat() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=one&tags=two", + Arrays.asList("one", "two"), Client::map); + } + + @Test + void arrayValueUsesCsvCollectionFormat() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=one%2Ctwo", + new String[] {"one", "two"}, Client::mapCsv); + } + + @Test + void collectionValueUsesCsvCollectionFormat() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=one%2Ctwo", + Arrays.asList("one", "two"), Client::mapCsv); + } + + @Test + void arrayValueUsesSsvCollectionFormat() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=one%20two", + new String[] {"one", "two"}, Client::mapSsv); + } + + @Test + void collectionValueUsesSsvCollectionFormat() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=one%20two", + Arrays.asList("one", "two"), Client::mapSsv); + } + + @Test + void arrayValueUsesTsvCollectionFormat() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=one%09two", + new String[] {"one", "two"}, Client::mapTsv); + } + + @Test + void collectionValueUsesTsvCollectionFormat() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=one%09two", + Arrays.asList("one", "two"), Client::mapTsv); + } + + @Test + void arrayValueUsesPipesCollectionFormat() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=one%7Ctwo", + new String[] {"one", "two"}, Client::mapPipes); + } + + @Test + void collectionValueUsesPipesCollectionFormat() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=one%7Ctwo", + Arrays.asList("one", "two"), Client::mapPipes); + } + + private void assertEncodedBody( + String expectedBody, + Object tags, + BiFunction, String> requestCall) { + try (var server = + UndertowServer.builder() + .callback((exchange, message) -> assertRequest(exchange, message, expectedBody)) + .start()) { + var client = + Feign.builder() + .encoder(new FormEncoder(new JacksonEncoder())) + .target(Client.class, server.getConnectUrl()); + + var data = createRequestData(tags); + assertThat(requestCall.apply(client, data)).isEqualTo("ok"); + } + } + + private Map createRequestData(Object tags) { + var data = new LinkedHashMap(); + data.put("from", "+987654321"); + data.put("to", "+123456789"); + data.put("tags", tags); + return data; + } + + private void assertRequest(HttpServerExchange exchange, byte[] message, String expectedBody) { + assertThat(exchange.getRequestHeaders().getFirst(io.undertow.util.Headers.CONTENT_TYPE)) + .isEqualTo("application/x-www-form-urlencoded; charset=UTF-8"); + assertThat(message).asString().isEqualTo(expectedBody); + + exchange.getResponseHeaders().put(io.undertow.util.Headers.CONTENT_TYPE, "text/plain"); + exchange.getResponseSender().send("ok"); + } + + interface Client { + + @RequestLine("POST") + @Headers("Content-Type: application/x-www-form-urlencoded; charset=utf-8") + String map(Map data); + + @RequestLine(value = "POST", collectionFormat = CollectionFormat.CSV) + @Headers("Content-Type: application/x-www-form-urlencoded; charset=utf-8") + String mapCsv(Map data); + + @RequestLine(value = "POST", collectionFormat = CollectionFormat.SSV) + @Headers("Content-Type: application/x-www-form-urlencoded; charset=utf-8") + String mapSsv(Map data); + + @RequestLine(value = "POST", collectionFormat = CollectionFormat.TSV) + @Headers("Content-Type: application/x-www-form-urlencoded; charset=utf-8") + String mapTsv(Map data); + + @RequestLine(value = "POST", collectionFormat = CollectionFormat.PIPES) + @Headers("Content-Type: application/x-www-form-urlencoded; charset=utf-8") + String mapPipes(Map data); + } +} From 5570496254066b0ad1b34637af1b498cad082e04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 05:17:53 +0000 Subject: [PATCH 466/615] build(deps-dev): Bump com.github.siom79.japicmp:japicmp-maven-plugin Bumps [com.github.siom79.japicmp:japicmp-maven-plugin](https://github.com/siom79/japicmp) from 0.25.4 to 0.25.6. - [Release notes](https://github.com/siom79/japicmp/releases) - [Changelog](https://github.com/siom79/japicmp/blob/master/release.py) - [Commits](https://github.com/siom79/japicmp/compare/japicmp-base-0.25.4...japicmp-base-0.25.6) --- updated-dependencies: - dependency-name: com.github.siom79.japicmp:japicmp-maven-plugin dependency-version: 0.25.6 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 522d8c8f79..009200c13d 100644 --- a/pom.xml +++ b/pom.xml @@ -204,7 +204,7 @@ 6.34.0 3.30.0 3.30.1 - 0.25.4 + 0.25.6 1.0 From 8199ae4ec8d177911983144a8edcff8088d3b3cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 05:29:43 +0000 Subject: [PATCH 467/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.30.1 to 3.32.1. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.30.1...v3.32.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.32.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 009200c13d..ebce66a37a 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 4.0.0 6.34.0 3.30.0 - 3.30.1 + 3.32.1 0.25.6 1.0 From 648329373c117f05e2f53260efa1bc03a429a54c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 05:41:51 +0000 Subject: [PATCH 468/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.30.0 to 3.34.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.30.0...v3.34.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.34.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ebce66a37a..7762a338a2 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 1.2.8 4.0.0 6.34.0 - 3.30.0 + 3.34.0 3.32.1 0.25.6 1.0 From 6e223322e840d8d9a71f9f1542ba4f00fa89148c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 05:53:40 +0000 Subject: [PATCH 469/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.34.0 to 6.36.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.34.0...v6.36.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.36.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7762a338a2..b580ebce8c 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 3.2.0 1.2.8 4.0.0 - 6.34.0 + 6.36.0 3.34.0 3.32.1 0.25.6 From 0a3f63796c2981f29282f28733342e6cd78fa98b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:38:59 +0000 Subject: [PATCH 470/615] build(deps): Bump com.google.guava:guava from 33.5.0-jre to 33.6.0-jre Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.5.0-jre to 33.6.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-version: 33.6.0-jre dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b580ebce8c..0d4ed22a6d 100644 --- a/pom.xml +++ b/pom.xml @@ -161,7 +161,7 @@ ${main.java.version} 5.3.2 - 33.5.0-jre + 33.6.0-jre 2.1.0 2.13.2 1.15.2 From f7ce997936759b3ff99b4c4d96744c4076b44124 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:40:19 +0000 Subject: [PATCH 471/615] build(deps): Bump tools.jackson:jackson-bom from 3.1.0 to 3.1.2 Bumps [tools.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 3.1.0 to 3.1.2. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-3.1.0...jackson-bom-3.1.2) --- updated-dependencies: - dependency-name: tools.jackson:jackson-bom dependency-version: 3.1.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b580ebce8c..9705cc8de2 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 6.0.3 2.21.2 - 3.1.0 + 3.1.2 3.27.7 5.23.0 2.0.61.android8 From 1e3c72bdc0a3f8ba82df8935fc423e9cc321981b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:40:20 +0000 Subject: [PATCH 472/615] build(deps-dev): Bump com.gradle:develocity-maven-extension Bumps com.gradle:develocity-maven-extension from 2.3.4 to 2.4.0. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: 2.4.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 7040f32333..a4c19ac4d5 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.3.4 + 2.4.0 com.gradle From 3f165702d15ac25692f100e977d5484290428065 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:40:20 +0000 Subject: [PATCH 473/615] build(deps): Bump reactor.version from 3.8.4 to 3.8.5 Bumps `reactor.version` from 3.8.4 to 3.8.5. Updates `io.projectreactor:reactor-core` from 3.8.4 to 3.8.5 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.4...v3.8.5) Updates `io.projectreactor:reactor-test` from 3.8.4 to 3.8.5 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.4...v3.8.5) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.8.5 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.8.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index a7eb57ff73..2f48e30472 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.8.4 + 3.8.5 1.0.4 2.2.21 From 1c23c600748897dbd3b55b60730b277f74d619aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:40:20 +0000 Subject: [PATCH 474/615] build(deps): Bump micrometer.version from 1.16.4 to 1.16.5 Bumps `micrometer.version` from 1.16.4 to 1.16.5. Updates `io.micrometer:micrometer-core` from 1.16.4 to 1.16.5 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.4...v1.16.5) Updates `io.micrometer:micrometer-test` from 1.16.4 to 1.16.5 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.4...v1.16.5) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.16.5 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.micrometer:micrometer-test dependency-version: 1.16.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 58d5976a28..d910aafbb7 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.16.4 + 1.16.5 From b27976f9fb90bee85f6375843be1822dc54b7f12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:40:20 +0000 Subject: [PATCH 475/615] build(deps-dev): Bump io.sundr:sundr-maven-plugin Bumps [io.sundr:sundr-maven-plugin](https://github.com/sundrio/sundrio) from 0.230.2 to 0.240.1. - [Commits](https://github.com/sundrio/sundrio/compare/0.230.2...0.240.1) --- updated-dependencies: - dependency-name: io.sundr:sundr-maven-plugin dependency-version: 0.240.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b580ebce8c..2e7295758f 100644 --- a/pom.xml +++ b/pom.xml @@ -189,7 +189,7 @@ 0.1.1 0.10.0 3.5.5 - 0.230.2 + 0.240.1 file://${project.basedir}/src/config/bom.xml 2.2.1 2.21.0 From 8b8048227d2cd72e15bbad08673f64fd739592fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:40:25 +0000 Subject: [PATCH 476/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx4-test Bumps `vertx.version` from 4.5.25 to 4.5.26. Updates `io.vertx:vertx-junit5` from 4.5.25 to 4.5.26 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.25...4.5.26) Updates `io.vertx:vertx-web-client` from 4.5.25 to 4.5.26 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.25...4.5.26) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 4.5.26 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 4.5.26 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx4-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 047f51608c..3be30a2265 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 4.x. - 4.5.25 + 4.5.26 From 2842f8e4f8aa5906f7af3c84ff3cf0f4713166d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:40:29 +0000 Subject: [PATCH 477/615] build(deps): Bump springboot.version from 4.0.4 to 4.0.5 Bumps `springboot.version` from 4.0.4 to 4.0.5. Updates `org.springframework.boot:spring-boot-maven-plugin` from 4.0.4 to 4.0.5 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.4...v4.0.5) Updates `org.springframework.boot:spring-boot-starter-web` from 4.0.4 to 4.0.5 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.4...v4.0.5) Updates `org.springframework.boot:spring-boot-starter-test` from 4.0.4 to 4.0.5 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.4...v4.0.5) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-maven-plugin dependency-version: 4.0.5 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: org.springframework.boot:spring-boot-starter-web dependency-version: 4.0.5 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.springframework.boot:spring-boot-starter-test dependency-version: 4.0.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b580ebce8c..c7d9a48286 100644 --- a/pom.xml +++ b/pom.xml @@ -167,7 +167,7 @@ 1.15.2 2.0.17 20251224 - 4.0.4 + 4.0.5 6.0.3 2.21.2 From 6647c50565a7ac6eae5b1cc718d4f525da847603 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:40:33 +0000 Subject: [PATCH 478/615] build(deps): Bump netty.version from 4.2.10.Final to 4.2.12.Final Bumps `netty.version` from 4.2.10.Final to 4.2.12.Final. Updates `io.netty:netty-bom` from 4.2.10.Final to 4.2.12.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.10.Final...netty-4.2.12.Final) Updates `io.netty:netty-handler` from 4.2.10.Final to 4.2.12.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.10.Final...netty-4.2.12.Final) Updates `io.netty:netty-codec-http` from 4.2.10.Final to 4.2.12.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.10.Final...netty-4.2.12.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.12.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.12.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.12.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 9cf0959ced..ec5002ee20 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.10.Final + 4.2.12.Final true From 7dbe55edadd2d99a9d6b3a401bb5b3a072def767 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:40:34 +0000 Subject: [PATCH 479/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx5-test Bumps `vertx.version` from 5.0.8 to 5.0.10. Updates `io.vertx:vertx-junit5` from 5.0.8 to 5.0.10 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/5.0.8...5.0.10) Updates `io.vertx:vertx-web-client` from 5.0.8 to 5.0.10 - [Commits](https://github.com/vert-x3/vertx-web/compare/5.0.8...5.0.10) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 5.0.10 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 5.0.10 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx5-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index dd3856c51d..078251417f 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.0.8 + 5.0.11 From ee8023bf39dd592ae962e60155bb561e2c945d8e Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 17 Apr 2026 13:57:32 -0300 Subject: [PATCH 480/615] feat(graphql-apt): honor @deprecated schema directive with class/method overrides Signed-off-by: Marvin Froeder --- .../graphql/apt/GraphqlSchemaProcessor.java | 11 + .../graphql/apt/TypeAnnotationConfig.java | 36 +-- .../java/feign/graphql/apt/TypeGenerator.java | 55 +++- .../apt/GraphqlSchemaProcessorTest.java | 252 ++++++++++++++++++ .../resources/deprecated-test-schema.graphql | 27 ++ .../main/java/feign/graphql/GraphqlQuery.java | 2 + .../java/feign/graphql/GraphqlSchema.java | 2 + 7 files changed, 344 insertions(+), 41 deletions(-) create mode 100644 graphql-apt/src/test/resources/deprecated-test-schema.graphql diff --git a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java index 575d89a001..2ea251ca80 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/GraphqlSchemaProcessor.java @@ -419,6 +419,7 @@ private TypeAnnotationConfig resolveClassConfig( rawAnnotations, annotation.useOptional(), annotation.useAliasForFieldNames(), + annotation.generateDeprecated(), classFieldAnnotations, nonNullFqns, nonNullRaw); @@ -436,6 +437,7 @@ private TypeAnnotationConfig resolveClassConfig( config.annotations(), config.useOptional(), config.useAliasForFieldNames(), + config.generateDeprecated(), config.fieldAnnotations(), config.nonNullAnnotations()); } @@ -455,6 +457,7 @@ private TypeAnnotationConfig resolveMethodConfig( var methodRaw = annotation.rawTypeAnnotations(); var methodOptionalToggle = annotation.useOptional(); var methodAliasToggle = annotation.useAliasForFieldNames(); + var methodDeprecatedToggle = annotation.generateDeprecated(); var useOptional = methodOptionalToggle == Toggle.INHERIT @@ -464,6 +467,10 @@ private TypeAnnotationConfig resolveMethodConfig( methodAliasToggle == Toggle.INHERIT ? classConfig.useAliasForFieldNames() : methodAliasToggle == Toggle.TRUE; + var generateDeprecated = + methodDeprecatedToggle == Toggle.INHERIT + ? classConfig.generateDeprecated() + : methodDeprecatedToggle == Toggle.TRUE; var methodFieldAnnotations = extractFieldAnnotations(method); var fieldAnnotations = @@ -479,6 +486,7 @@ private TypeAnnotationConfig resolveMethodConfig( if (!hasMethodAnnotations && !hasMethodNonNull) { if (useOptional == classConfig.useOptional() && useAliasForFieldNames == classConfig.useAliasForFieldNames() + && generateDeprecated == classConfig.generateDeprecated() && fieldAnnotations.equals(classConfig.fieldAnnotations())) { return classConfig; } @@ -491,6 +499,7 @@ private TypeAnnotationConfig resolveMethodConfig( classConfig.annotations(), useOptional, useAliasForFieldNames, + generateDeprecated, fieldAnnotations, classConfig.nonNullAnnotations()); } @@ -503,6 +512,7 @@ private TypeAnnotationConfig resolveMethodConfig( methodRaw, useOptional, useAliasForFieldNames, + generateDeprecated, fieldAnnotations, nonNullFqns, nonNullRaw); @@ -515,6 +525,7 @@ private TypeAnnotationConfig resolveMethodConfig( config.annotations(), useOptional, useAliasForFieldNames, + generateDeprecated, fieldAnnotations, resolvedNonNull); } diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java index 4cb94b7787..99b2f78f1a 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeAnnotationConfig.java @@ -28,48 +28,19 @@ record TypeAnnotationConfig( List annotations, boolean useOptional, boolean useAliasForFieldNames, + boolean generateDeprecated, Map fieldAnnotations, List nonNullAnnotations) { static final TypeAnnotationConfig EMPTY = - new TypeAnnotationConfig(Set.of(), List.of(), false, true, Map.of(), List.of()); - - static TypeAnnotationConfig resolve( - List typeAnnotationFqns, - String[] rawTypeAnnotations, - boolean useOptional, - boolean useAliasForFieldNames) { - return resolve( - typeAnnotationFqns, - rawTypeAnnotations, - useOptional, - useAliasForFieldNames, - Map.of(), - List.of(), - new String[0]); - } - - static TypeAnnotationConfig resolve( - List typeAnnotationFqns, - String[] rawTypeAnnotations, - boolean useOptional, - boolean useAliasForFieldNames, - Map fieldAnnotations) { - return resolve( - typeAnnotationFqns, - rawTypeAnnotations, - useOptional, - useAliasForFieldNames, - fieldAnnotations, - List.of(), - new String[0]); - } + new TypeAnnotationConfig(Set.of(), List.of(), false, true, true, Map.of(), List.of()); static TypeAnnotationConfig resolve( List typeAnnotationFqns, String[] rawTypeAnnotations, boolean useOptional, boolean useAliasForFieldNames, + boolean generateDeprecated, Map fieldAnnotations, List nonNullFqns, String[] nonNullRawAnnotations) { @@ -88,6 +59,7 @@ static TypeAnnotationConfig resolve( annotations, useOptional, useAliasForFieldNames, + generateDeprecated, fieldAnnotations, nonNullResolved); } diff --git a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java index 05e3064ada..dbce74a80b 100644 --- a/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java +++ b/graphql-apt/src/main/java/feign/graphql/apt/TypeGenerator.java @@ -20,6 +20,7 @@ import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; +import graphql.language.DirectivesContainer; import graphql.language.EnumTypeDefinition; import graphql.language.Field; import graphql.language.InputObjectTypeDefinition; @@ -144,6 +145,10 @@ private ResultTypeDefinition buildResultType( if (schemaDef == null) { continue; } + var deprecated = isDeprecated(schemaDef); + if (!annotationConfig.generateDeprecated() && deprecated) { + continue; + } var fieldName = responseKey(field); var fieldType = schemaDef.getType(); @@ -165,11 +170,11 @@ private ResultTypeDefinition buildResultType( var nestedType = wrapType(fieldType, ClassName.get("", nestedClassName), annotationConfig.useOptional()); var fieldNonNull = fieldType instanceof NonNullType; - fields.add(toRecordField(fieldName, nestedType, fieldNonNull)); + fields.add(toRecordField(fieldName, nestedType, fieldNonNull, deprecated)); } else { var javaType = typeMapper.map(fieldType, annotationConfig.useOptional()); var fieldNonNull = fieldType instanceof NonNullType; - fields.add(toRecordField(fieldName, javaType, fieldNonNull)); + fields.add(toRecordField(fieldName, javaType, fieldNonNull, deprecated)); enqueueIfNonScalar(rawTypeName); } } @@ -301,11 +306,15 @@ public void generateInputType(String className, String graphqlTypeName, Element var fields = new ArrayList(); for (var valueDef : inputDef.getInputValueDefinitions()) { + var deprecated = isDeprecated(valueDef); + if (!annotationConfig.generateDeprecated() && deprecated) { + continue; + } var fieldName = valueDef.getName(); var fieldType = valueDef.getType(); var javaType = typeMapper.map(fieldType, annotationConfig.useOptional()); var fieldNonNull = fieldType instanceof NonNullType; - fields.add(toRecordField(fieldName, javaType, fieldNonNull)); + fields.add(toRecordField(fieldName, javaType, fieldNonNull, deprecated)); var rawTypeName = GraphqlTypeMapper.unwrapTypeName(fieldType); enqueueIfNonScalar(rawTypeName); @@ -350,7 +359,17 @@ private void generateEnum(String className, EnumTypeDefinition enumDef, Element var enumBuilder = TypeSpec.enumBuilder(className).addModifiers(Modifier.PUBLIC); for (var value : enumDef.getEnumValueDefinitions()) { - enumBuilder.addEnumConstant(value.getName()); + var deprecated = isDeprecated(value); + if (!annotationConfig.generateDeprecated() && deprecated) { + continue; + } + if (deprecated) { + enumBuilder.addEnumConstant( + value.getName(), + TypeSpec.anonymousClassBuilder("").addAnnotation(Deprecated.class).build()); + } else { + enumBuilder.addEnumConstant(value.getName()); + } } writeType(enumBuilder.build(), element); @@ -366,11 +385,15 @@ private void generateFullObjectType( var fields = new ArrayList(); for (var fieldDef : objectDef.getFieldDefinitions()) { + var deprecated = isDeprecated(fieldDef); + if (!annotationConfig.generateDeprecated() && deprecated) { + continue; + } var fieldName = fieldDef.getName(); var fieldType = fieldDef.getType(); var javaType = typeMapper.map(fieldType, annotationConfig.useOptional()); var fieldNonNull = fieldType instanceof NonNullType; - fields.add(toRecordField(fieldName, javaType, fieldNonNull)); + fields.add(toRecordField(fieldName, javaType, fieldNonNull, deprecated)); var rawTypeName = GraphqlTypeMapper.unwrapTypeName(fieldDef.getType()); enqueueIfNonScalar(rawTypeName); @@ -386,6 +409,15 @@ private void enqueueIfNonScalar(String typeName) { } } + private static boolean isDeprecated(DirectivesContainer node) { + for (var directive : node.getDirectives()) { + if ("deprecated".equals(directive.getName())) { + return true; + } + } + return false; + } + private TypeName wrapType(Type schemaType, TypeName innerType, boolean useOptional) { boolean nullable = !(schemaType instanceof NonNullType); var wrapped = wrapTypeInner(schemaType, innerType); @@ -434,11 +466,14 @@ private String formatFieldParam(RecordField f, String pathPrefix) { var typeStr = fa != null && fa.typeOverride() != null ? fa.typeOverride() : f.typeString; - if (!hasNonNull && (fa == null || fa.annotations().isEmpty())) { + if (!hasNonNull && !f.deprecated && (fa == null || fa.annotations().isEmpty())) { return typeStr + " " + f.name; } var fieldAnns = new ArrayList(); + if (f.deprecated) { + fieldAnns.add("@Deprecated"); + } if (hasNonNull) { fieldAnns.addAll(annotationConfig.nonNullAnnotations()); } @@ -448,9 +483,10 @@ private String formatFieldParam(RecordField f, String pathPrefix) { return String.join(" ", fieldAnns) + " " + typeStr + " " + f.name; } - private RecordField toRecordField(String name, TypeName typeName, boolean nonNull) { + private RecordField toRecordField( + String name, TypeName typeName, boolean nonNull, boolean deprecated) { var typeString = typeNameToString(typeName); - return new RecordField(typeString, name, typeName, nonNull); + return new RecordField(typeString, name, typeName, nonNull, deprecated); } private String typeNameToString(TypeName typeName) { @@ -544,5 +580,6 @@ record ResultTypeDefinition( List fields, List innerTypes) {} - record RecordField(String typeString, String name, TypeName typeName, boolean nonNull) {} + record RecordField( + String typeString, String name, TypeName typeName, boolean nonNull, boolean deprecated) {} } diff --git a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java index f60c6e22b2..e4488eed11 100644 --- a/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java +++ b/graphql-apt/src/test/java/feign/graphql/apt/GraphqlSchemaProcessorTest.java @@ -1913,4 +1913,256 @@ interface AliasOverrideApi { plain.contains("Optional specs"); plain.contains("public record Specs("); } + + @Test + void deprecatedFieldsIncludedByDefault() { + var source = + JavaFileObjects.forSourceString( + "test.DefaultDeprecatedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("deprecated-test-schema.graphql") + interface DefaultDeprecatedApi { + @GraphqlQuery(\""" + { user(id: "1") { id name email emails status } } + \""") + UserResult getUser(); + + @GraphqlQuery(\""" + mutation createUser($input: CreateUserInput!) { + createUser(input: $input) { id name } + }\""") + CreateUserResult createUser(CreateUserInput input); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + var userResult = + assertThat(compilation).generatedSourceFile("test.UserResult").contentsAsUtf8String(); + userResult.contains("@Deprecated Optional email,"); + + var createInput = + assertThat(compilation).generatedSourceFile("test.CreateUserInput").contentsAsUtf8String(); + createInput.contains("@Deprecated Optional email"); + + var status = + assertThat(compilation).generatedSourceFile("test.UserStatus").contentsAsUtf8String(); + status.contains("@Deprecated\n BANNED"); + } + + @Test + void deprecatedFieldsSkippedWhenDisabledAtClassLevel() { + var source = + JavaFileObjects.forSourceString( + "test.ClassDisabledDeprecatedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "deprecated-test-schema.graphql", generateDeprecated = false) + interface ClassDisabledDeprecatedApi { + @GraphqlQuery(\""" + { user(id: "1") { id name email emails status } } + \""") + UserResult getUser(); + + @GraphqlQuery(\""" + mutation createUser($input: CreateUserInput!) { + createUser(input: $input) { id name } + }\""") + CreateUserResult createUser(CreateUserInput input); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation) + .generatedSourceFile("test.UserResult") + .contentsAsUtf8String() + .doesNotContain(" email,"); + assertThat(compilation) + .generatedSourceFile("test.CreateUserInput") + .contentsAsUtf8String() + .doesNotContain(" email,"); + assertThat(compilation) + .generatedSourceFile("test.UserStatus") + .contentsAsUtf8String() + .doesNotContain("BANNED"); + } + + @Test + void methodLevelToggleCanReEnableDeprecated() { + var source = + JavaFileObjects.forSourceString( + "test.MethodOverrideDeprecatedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.Toggle; + + @GraphqlSchema(value = "deprecated-test-schema.graphql", generateDeprecated = false) + interface MethodOverrideDeprecatedApi { + @GraphqlQuery(value = \""" + { user(id: "1") { id name email emails status } } + \""", generateDeprecated = Toggle.TRUE) + WithDeprecatedResult getUserWithDeprecated(); + + @GraphqlQuery(\""" + { user(id: "1") { id name email emails status } } + \""") + WithoutDeprecatedResult getUserFiltered(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation) + .generatedSourceFile("test.WithDeprecatedResult") + .contentsAsUtf8String() + .contains(" email,"); + assertThat(compilation) + .generatedSourceFile("test.WithoutDeprecatedResult") + .contentsAsUtf8String() + .doesNotContain(" email,"); + } + + @Test + void deprecatedEnumValuesSkippedWhenDisabled() { + var source = + JavaFileObjects.forSourceString( + "test.EnumDeprecatedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema(value = "deprecated-test-schema.graphql", generateDeprecated = false) + interface EnumDeprecatedApi { + @GraphqlQuery(\""" + { user(id: "1") { id status } } + \""") + UserResult getUser(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + var status = + assertThat(compilation).generatedSourceFile("test.UserStatus").contentsAsUtf8String(); + status.contains("ACTIVE"); + status.contains("INACTIVE"); + status.doesNotContain("BANNED"); + } + + @Test + void methodToggleReEnabledDeprecatedStillCarriesAnnotation() { + var source = + JavaFileObjects.forSourceString( + "test.ReEnabledDeprecatedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.Toggle; + + @GraphqlSchema(value = "deprecated-test-schema.graphql", generateDeprecated = false) + interface ReEnabledDeprecatedApi { + @GraphqlQuery(value = \""" + { user(id: "1") { id name email status } } + \""", generateDeprecated = Toggle.TRUE) + ReEnabledResult getUser(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation) + .generatedSourceFile("test.ReEnabledResult") + .contentsAsUtf8String() + .contains("@Deprecated Optional email,"); + assertThat(compilation) + .generatedSourceFile("test.UserStatus") + .contentsAsUtf8String() + .contains("@Deprecated\n BANNED"); + } + + @Test + void deprecatedEnumValuesKeptByDefault() { + var source = + JavaFileObjects.forSourceString( + "test.EnumDefaultApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + + @GraphqlSchema("deprecated-test-schema.graphql") + interface EnumDefaultApi { + @GraphqlQuery(\""" + { user(id: "1") { id status } } + \""") + UserResult getUser(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + var status = + assertThat(compilation).generatedSourceFile("test.UserStatus").contentsAsUtf8String(); + status.contains("ACTIVE"); + status.contains("INACTIVE"); + status.contains("BANNED"); + } + + @Test + void methodLevelToggleCanDisableDeprecated() { + var source = + JavaFileObjects.forSourceString( + "test.MethodDisableDeprecatedApi", + """ + package test; + + import feign.graphql.GraphqlSchema; + import feign.graphql.GraphqlQuery; + import feign.graphql.Toggle; + + @GraphqlSchema("deprecated-test-schema.graphql") + interface MethodDisableDeprecatedApi { + @GraphqlQuery(value = \""" + { user(id: "1") { id name email emails status } } + \""", generateDeprecated = Toggle.FALSE) + FilteredUserResult getUserFiltered(); + } + """); + + var compilation = javac().withProcessors(new GraphqlSchemaProcessor()).compile(source); + + assertThat(compilation).succeeded(); + assertThat(compilation) + .generatedSourceFile("test.FilteredUserResult") + .contentsAsUtf8String() + .doesNotContain(" email,"); + assertThat(compilation) + .generatedSourceFile("test.UserStatus") + .contentsAsUtf8String() + .doesNotContain("BANNED"); + } } diff --git a/graphql-apt/src/test/resources/deprecated-test-schema.graphql b/graphql-apt/src/test/resources/deprecated-test-schema.graphql new file mode 100644 index 0000000000..cdb4ae5170 --- /dev/null +++ b/graphql-apt/src/test/resources/deprecated-test-schema.graphql @@ -0,0 +1,27 @@ +type Query { + user(id: ID!): User +} + +type Mutation { + createUser(input: CreateUserInput!): User +} + +type User { + id: ID! + name: String! + email: String @deprecated(reason: "use emails instead") + emails: [String] + status: UserStatus +} + +input CreateUserInput { + name: String! + email: String @deprecated(reason: "use emails instead") + emails: [String] +} + +enum UserStatus { + ACTIVE + INACTIVE + BANNED @deprecated(reason: "no longer used") +} diff --git a/graphql/src/main/java/feign/graphql/GraphqlQuery.java b/graphql/src/main/java/feign/graphql/GraphqlQuery.java index 964c70ddd7..46d18e896f 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlQuery.java +++ b/graphql/src/main/java/feign/graphql/GraphqlQuery.java @@ -32,6 +32,8 @@ Toggle useAliasForFieldNames() default Toggle.INHERIT; + Toggle generateDeprecated() default Toggle.INHERIT; + Class[] typeAnnotations() default {}; String[] rawTypeAnnotations() default {}; diff --git a/graphql/src/main/java/feign/graphql/GraphqlSchema.java b/graphql/src/main/java/feign/graphql/GraphqlSchema.java index 4f5799b41e..5d8920bdcd 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlSchema.java +++ b/graphql/src/main/java/feign/graphql/GraphqlSchema.java @@ -34,6 +34,8 @@ boolean useAliasForFieldNames() default true; + boolean generateDeprecated() default true; + Class[] uses() default {}; Class[] typeAnnotations() default {}; From 091854787cd57244c0ba8d32deba811d217fc5f5 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 17 Apr 2026 14:09:28 -0300 Subject: [PATCH 481/615] prepare release 13.12 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index c014de0401..ba09214e38 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index aaeb1b7a04..c502ed15a8 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index ec5002ee20..264b57f6bd 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index fb9bf5129e..7567184837 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 2113f27022..95b9ff2d60 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index c59139b5f7..98cdd91735 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 03acb10f8f..e3f2dad637 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index e20290b054..8bf5099fa4 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 1cca9e5925..4d35664ec2 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index c342fe4cb6..3deb5bd781 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index a50a0a0d84..702d61429e 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index e00910eba2..d0cba151a8 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 0d827c9760..1d67551afd 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index ee57d9cc82..d9a09f7a44 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index e7cb3e6948..e3b13ca73a 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index b4199d3bd0..f5cfc49326 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index 1f69a0ec59..a783335a0a 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 3d385a8f99..558fe8df43 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index c277048cfa..4f5d475e10 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 42e1c9f12a..3d9644f269 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 7f1fdcdf0a..eeb2470041 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index af89b3a5da..c32db762e6 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 9347a731bb..0d385eb624 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index db3a73ea23..3a63fa5230 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index be5af86003..20cf1a610e 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 4a9d9d05b9..03bdde6fbd 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 1dd83992b5..1daf65a225 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index bc8c15a215..b07dbe690b 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 6d6fcff7b3..03049d2f33 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 7e8983a0d1..e33d5182f6 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 5b13d3e4e6..7fbfe39f30 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 42f7cbae50..013d4dd97d 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index a11e3d45db..872e7a22ef 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 9ad1bc7233..e157d941fe 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index d910aafbb7..ffde067aa9 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 698cff2151..96c470e401 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index d80167cee5..f3865359ae 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 7fa6c1b6d2..64ef259f1a 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-okhttp diff --git a/pom.xml b/pom.xml index 6a09d39bdf..90fe544fc4 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 2f48e30472..b62759c715 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 941bad579e..928f42e889 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 327b9e490f..6e7fc4feec 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 497558323c..825527d3d6 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index b8b8f14058..ffcbc2db12 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index ecd6d1d682..91e8344ad3 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index fe3ca30ce9..2b230c1958 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 173f05db3e..31734369b1 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 832b396a32..3f5e4bbf33 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.12-SNAPSHOT + 13.12 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 3be30a2265..9f2d0ff4b9 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.12-SNAPSHOT + 13.12 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 078251417f..7eaf7c8b19 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.12-SNAPSHOT + 13.12 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index f5ec1f1c55..f36e733b58 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12-SNAPSHOT + 13.12 feign-vertx-parent From 82d2e4397ff01c5e7c04cd9845c462c0cefab60c Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Fri, 17 Apr 2026 14:09:35 -0300 Subject: [PATCH 482/615] [ci skip] updating versions to next development iteration 13.13-SNAPSHOT --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index ba09214e38..25e1be69c0 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index c502ed15a8..c36dc2789b 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 264b57f6bd..1f73303357 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index 7567184837..58f79c5871 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index 95b9ff2d60..b1d584a4fc 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 98cdd91735..97ebea5884 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index e3f2dad637..671b20e06f 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 8bf5099fa4..2458198a11 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 4d35664ec2..6424011e8b 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 3deb5bd781..551c2969b6 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 702d61429e..7162b3f4a7 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-fastjson2 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index d0cba151a8..18a880fc1a 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 1d67551afd..1777951c51 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index d9a09f7a44..d89718f877 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index e3b13ca73a..b0a60a58b8 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index f5cfc49326..bd014420c1 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index a783335a0a..dce2da755f 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 558fe8df43..22ab8b2d9e 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-hc5 diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 4f5d475e10..b5ccf87a10 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index 3d9644f269..f3c0589009 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index eeb2470041..3e8dd5daef 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index c32db762e6..a1f5f2b3ad 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 0d385eb624..3bed5201dd 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 3a63fa5230..7a66128ed0 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 20cf1a610e..0d992c5158 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 03bdde6fbd..a2dcc3ade6 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 1daf65a225..9d9db921df 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index b07dbe690b..7d8949d48f 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 03049d2f33..3f35a80f53 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index e33d5182f6..a1e3c801c5 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 7fbfe39f30..b5dabe1d19 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 013d4dd97d..2b8f6defd1 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 872e7a22ef..2e8e847a2d 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index e157d941fe..8f01635301 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index ffde067aa9..6092d53273 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 96c470e401..97896b3c9b 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index f3865359ae..81fb5c5c45 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 64ef259f1a..30963523e1 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index 90fe544fc4..84dff0b85b 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index b62759c715..d06c79ff62 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index 928f42e889..a4723450dc 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 6e7fc4feec..071c4ace14 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 825527d3d6..54fb06d0a1 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index ffcbc2db12..99ba3ad6ad 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 91e8344ad3..382a46ea81 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 2b230c1958..541f3d15c8 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 31734369b1..c137a8ce87 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-spring4 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 3f5e4bbf33..8e3bfd3d46 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.12 + 13.13-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 9f2d0ff4b9..3c051200c4 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.12 + 13.13-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 7eaf7c8b19..daa9935202 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.12 + 13.13-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index f36e733b58..91cc96416e 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.12 + 13.13-SNAPSHOT feign-vertx-parent From 666bc859ca72038052f8b6fa1383fe0c477403bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 05:33:56 +0000 Subject: [PATCH 483/615] build(deps-dev): Bump org.springframework:spring-context Bumps [org.springframework:spring-context](https://github.com/spring-projects/spring-framework) from 7.0.6 to 7.0.7. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.6...v7.0.7) --- updated-dependencies: - dependency-name: org.springframework:spring-context dependency-version: 7.0.7 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 84dff0b85b..436227f479 100644 --- a/pom.xml +++ b/pom.xml @@ -243,7 +243,7 @@ 3.0.2 2025.1.1 5.0.1 - 7.0.6 + 7.0.7 7.0.6 2.3.24.Final 1.18.0 From 82b45b1fe5232d8ef07950b9f290075d460280b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 05:34:29 +0000 Subject: [PATCH 484/615] build(deps-dev): Bump io.sundr:sundr-maven-plugin Bumps [io.sundr:sundr-maven-plugin](https://github.com/sundrio/sundrio) from 0.240.1 to 0.300.0. - [Commits](https://github.com/sundrio/sundrio/compare/0.240.1...0.300.0) --- updated-dependencies: - dependency-name: io.sundr:sundr-maven-plugin dependency-version: 0.300.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 84dff0b85b..67b267df7c 100644 --- a/pom.xml +++ b/pom.xml @@ -189,7 +189,7 @@ 0.1.1 0.10.0 3.5.5 - 0.240.1 + 0.300.0 file://${project.basedir}/src/config/bom.xml 2.2.1 2.21.0 From 5de5d49f0c2243c098b4dde0616dbbd92962a813 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 05:34:52 +0000 Subject: [PATCH 485/615] build(deps): Bump org.apache.httpcomponents.client5:httpclient5 Bumps [org.apache.httpcomponents.client5:httpclient5](https://github.com/apache/httpcomponents-client) from 5.6 to 5.6.1. - [Changelog](https://github.com/apache/httpcomponents-client/blob/rel/v5.6.1/RELEASE_NOTES.txt) - [Commits](https://github.com/apache/httpcomponents-client/compare/rel/v5.6...rel/v5.6.1) --- updated-dependencies: - dependency-name: org.apache.httpcomponents.client5:httpclient5 dependency-version: 5.6.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 84dff0b85b..120e335f71 100644 --- a/pom.xml +++ b/pom.xml @@ -218,7 +218,7 @@ 25.0 4.5.0 4.5.14 - 5.6 + 5.6.1 1.13.0 1.5.18 3.1.0 From 9efef0666050f9040e6e09902138b08437d00266 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 05:45:13 +0000 Subject: [PATCH 486/615] build(deps): Bump org.springframework:spring-web from 7.0.6 to 7.0.7 Bumps [org.springframework:spring-web](https://github.com/spring-projects/spring-framework) from 7.0.6 to 7.0.7. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.6...v7.0.7) --- updated-dependencies: - dependency-name: org.springframework:spring-web dependency-version: 7.0.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- spring/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 792c5bdfb2..6aa33179e5 100644 --- a/pom.xml +++ b/pom.xml @@ -244,7 +244,7 @@ 2025.1.1 5.0.1 7.0.7 - 7.0.6 + 7.0.7 2.3.24.Final 1.18.0 diff --git a/spring/pom.xml b/spring/pom.xml index 541f3d15c8..540a72cfb2 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -31,7 +31,7 @@ 17 - 7.0.6 + 7.0.7 From ede083be52978354ae8653ee46b646477be0ebda Mon Sep 17 00:00:00 2001 From: cesar Date: Tue, 21 Apr 2026 18:06:13 -0300 Subject: [PATCH 487/615] Add custom tags support to Metrics5Capability Allows users to pass a Map of custom tags when building Metrics5Capability. Tags are applied to all metrics registered by Feign. Fixes #2306 --- .../java/feign/metrics5/FeignMetricName.java | 23 +++++++++++++--- .../feign/metrics5/MeteredAsyncClient.java | 10 +++++++ .../java/feign/metrics5/MeteredClient.java | 9 +++++++ .../java/feign/metrics5/MeteredDecoder.java | 12 +++++++++ .../java/feign/metrics5/MeteredEncoder.java | 12 +++++++++ .../MeteredInvocationHandleFactory.java | 11 ++++++++ .../feign/metrics5/Metrics5Capability.java | 23 ++++++++++++---- .../metrics5/Metrics5CapabilityTest.java | 27 +++++++++++++++++++ 8 files changed, 118 insertions(+), 9 deletions(-) diff --git a/dropwizard-metrics5/src/main/java/feign/metrics5/FeignMetricName.java b/dropwizard-metrics5/src/main/java/feign/metrics5/FeignMetricName.java index 416be48def..e9e8582fbd 100644 --- a/dropwizard-metrics5/src/main/java/feign/metrics5/FeignMetricName.java +++ b/dropwizard-metrics5/src/main/java/feign/metrics5/FeignMetricName.java @@ -22,13 +22,22 @@ import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; +import java.util.Collections; +import java.util.Map; final class FeignMetricName { private final Class meteredComponent; + private final Map customTags; public FeignMetricName(Class meteredComponent) { this.meteredComponent = meteredComponent; + this.customTags = Collections.emptyMap(); + } + + public FeignMetricName(Class meteredComponent, Map customTags) { + this.meteredComponent = meteredComponent; + this.customTags = customTags; } public MetricName metricName(MethodMetadata methodMetadata, Target target, String suffix) { @@ -40,10 +49,16 @@ public MetricName metricName(MethodMetadata methodMetadata, Target target) { } public MetricName metricName(Class targetType, Method method, String url) { - return MetricRegistry.name(meteredComponent) - .tagged("client", targetType.getName()) - .tagged("method", method.getName()) - .tagged("host", extractHost(url)); + MetricName name = + MetricRegistry.name(meteredComponent) + .tagged("client", targetType.getName()) + .tagged("method", method.getName()) + .tagged("host", extractHost(url)); + + for (Map.Entry entry : customTags.entrySet()) { + name = name.tagged(entry.getKey(), entry.getValue()); + } + return name; } private String extractHost(final String targetUrl) { diff --git a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredAsyncClient.java b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredAsyncClient.java index d996c6ff16..e40b09e879 100644 --- a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredAsyncClient.java +++ b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredAsyncClient.java @@ -23,6 +23,7 @@ import feign.Response; import io.dropwizard.metrics5.MetricRegistry; import io.dropwizard.metrics5.Timer; +import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -39,6 +40,15 @@ public MeteredAsyncClient( this.asyncClient = asyncClient; } + public MeteredAsyncClient( + AsyncClient asyncClient, + MetricRegistry metricRegistry, + MetricSuppliers metricSuppliers, + Map customTags) { + super(metricRegistry, new FeignMetricName(AsyncClient.class, customTags), metricSuppliers); + this.asyncClient = asyncClient; + } + @Override public CompletableFuture execute( Request request, Options options, Optional requestContext) { diff --git a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredClient.java b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredClient.java index 487947d8cb..1fd6575269 100644 --- a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredClient.java +++ b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredClient.java @@ -24,6 +24,7 @@ import io.dropwizard.metrics5.MetricRegistry; import io.dropwizard.metrics5.Timer; import java.io.IOException; +import java.util.Map; /** Warp feign {@link Client} with metrics. */ public class MeteredClient extends BaseMeteredClient implements Client { @@ -33,7 +34,15 @@ public class MeteredClient extends BaseMeteredClient implements Client { public MeteredClient( Client client, MetricRegistry metricRegistry, MetricSuppliers metricSuppliers) { super(metricRegistry, new FeignMetricName(Client.class), metricSuppliers); + this.client = client; + } + public MeteredClient( + Client client, + MetricRegistry metricRegistry, + MetricSuppliers metricSuppliers, + Map customTags) { + super(metricRegistry, new FeignMetricName(Client.class, customTags), metricSuppliers); this.client = client; } diff --git a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredDecoder.java b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredDecoder.java index a543c13169..653d29e62e 100644 --- a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredDecoder.java +++ b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredDecoder.java @@ -25,6 +25,7 @@ import io.dropwizard.metrics5.Timer.Context; import java.io.IOException; import java.lang.reflect.Type; +import java.util.Map; /** Warp feign {@link Decoder} with metrics. */ public class MeteredDecoder implements Decoder { @@ -42,6 +43,17 @@ public MeteredDecoder( this.metricName = new FeignMetricName(Decoder.class); } + public MeteredDecoder( + Decoder decoder, + MetricRegistry metricRegistry, + MetricSuppliers metricSuppliers, + Map customTags) { + this.decoder = decoder; + this.metricRegistry = metricRegistry; + this.metricSuppliers = metricSuppliers; + this.metricName = new FeignMetricName(Decoder.class, customTags); + } + @Override public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException { diff --git a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java index cd0ee72cf5..77cc7b78cb 100644 --- a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java +++ b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java @@ -21,6 +21,7 @@ import io.dropwizard.metrics5.MetricRegistry; import io.dropwizard.metrics5.Timer.Context; import java.lang.reflect.Type; +import java.util.Map; /** Warp feign {@link Encoder} with metrics. */ public class MeteredEncoder implements Encoder { @@ -38,6 +39,17 @@ public MeteredEncoder( this.metricName = new FeignMetricName(Encoder.class); } + public MeteredEncoder( + Encoder encoder, + MetricRegistry metricRegistry, + MetricSuppliers metricSuppliers, + Map customTags) { + this.encoder = encoder; + this.metricRegistry = metricRegistry; + this.metricSuppliers = metricSuppliers; + this.metricName = new FeignMetricName(Encoder.class, customTags); + } + @Override public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { diff --git a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredInvocationHandleFactory.java b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredInvocationHandleFactory.java index 15946eb76a..c8c2b59fc5 100644 --- a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredInvocationHandleFactory.java +++ b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredInvocationHandleFactory.java @@ -57,6 +57,17 @@ public MeteredInvocationHandleFactory( this.metricName = new FeignMetricName(Feign.class); } + public MeteredInvocationHandleFactory( + InvocationHandlerFactory invocationHandler, + MetricRegistry metricRegistry, + MetricSuppliers metricSuppliers, + Map customTags) { + this.invocationHandler = invocationHandler; + this.metricRegistry = metricRegistry; + this.metricSuppliers = metricSuppliers; + this.metricName = new FeignMetricName(Feign.class, customTags); + } + @Override public InvocationHandler create(Target target, Map dispatch) { final Class clientClass = target.type(); diff --git a/dropwizard-metrics5/src/main/java/feign/metrics5/Metrics5Capability.java b/dropwizard-metrics5/src/main/java/feign/metrics5/Metrics5Capability.java index 87a59d31b5..a6fbbc3782 100644 --- a/dropwizard-metrics5/src/main/java/feign/metrics5/Metrics5Capability.java +++ b/dropwizard-metrics5/src/main/java/feign/metrics5/Metrics5Capability.java @@ -23,11 +23,14 @@ import feign.codec.Encoder; import io.dropwizard.metrics5.MetricRegistry; import io.dropwizard.metrics5.SharedMetricRegistries; +import java.util.Collections; +import java.util.Map; public class Metrics5Capability implements Capability { private final MetricRegistry metricRegistry; private final MetricSuppliers metricSuppliers; + private final Map customTags; public Metrics5Capability() { this(SharedMetricRegistries.getOrCreate("feign"), new MetricSuppliers()); @@ -40,31 +43,41 @@ public Metrics5Capability(MetricRegistry metricRegistry) { public Metrics5Capability(MetricRegistry metricRegistry, MetricSuppliers metricSuppliers) { this.metricRegistry = metricRegistry; this.metricSuppliers = metricSuppliers; + this.customTags = Collections.emptyMap(); + } + + public Metrics5Capability( + MetricRegistry metricRegistry, + MetricSuppliers metricSuppliers, + Map customTags) { + this.metricRegistry = metricRegistry; + this.metricSuppliers = metricSuppliers; + this.customTags = customTags; } @Override public Client enrich(Client client) { - return new MeteredClient(client, metricRegistry, metricSuppliers); + return new MeteredClient(client, metricRegistry, metricSuppliers, customTags); } @Override public AsyncClient enrich(AsyncClient client) { - return new MeteredAsyncClient(client, metricRegistry, metricSuppliers); + return new MeteredAsyncClient(client, metricRegistry, metricSuppliers, customTags); } @Override public Encoder enrich(Encoder encoder) { - return new MeteredEncoder(encoder, metricRegistry, metricSuppliers); + return new MeteredEncoder(encoder, metricRegistry, metricSuppliers, customTags); } @Override public Decoder enrich(Decoder decoder) { - return new MeteredDecoder(decoder, metricRegistry, metricSuppliers); + return new MeteredDecoder(decoder, metricRegistry, metricSuppliers, customTags); } @Override public InvocationHandlerFactory enrich(InvocationHandlerFactory invocationHandlerFactory) { return new MeteredInvocationHandleFactory( - invocationHandlerFactory, metricRegistry, metricSuppliers); + invocationHandlerFactory, metricRegistry, metricSuppliers, customTags); } } diff --git a/dropwizard-metrics5/src/test/java/feign/metrics5/Metrics5CapabilityTest.java b/dropwizard-metrics5/src/test/java/feign/metrics5/Metrics5CapabilityTest.java index 240cb4e418..7ef0caa91a 100644 --- a/dropwizard-metrics5/src/test/java/feign/metrics5/Metrics5CapabilityTest.java +++ b/dropwizard-metrics5/src/test/java/feign/metrics5/Metrics5CapabilityTest.java @@ -15,9 +15,16 @@ */ package feign.metrics5; +import static org.junit.jupiter.api.Assertions.assertTrue; + import feign.Capability; +import feign.Feign; import feign.Util; import feign.micrometer.AbstractMetricsTestBase; +import feign.micrometer.AbstractMetricsTestBase.SimpleSource; +import feign.mock.HttpMethod; +import feign.mock.MockClient; +import feign.mock.MockTarget; import io.dropwizard.metrics5.Metered; import io.dropwizard.metrics5.Metric; import io.dropwizard.metrics5.MetricName; @@ -25,6 +32,7 @@ import java.util.Arrays; import java.util.Map; import java.util.Map.Entry; +import org.junit.jupiter.api.Test; public class Metrics5CapabilityTest extends AbstractMetricsTestBase { @@ -120,4 +128,23 @@ protected boolean doesMetricHasCounter(Metric metric) { protected long getMetricCounter(Metric metric) { return ((Metered) metric).getCount(); } + + @Test + void customTagsAreAppliedToMetrics() { + SimpleSource source = + Feign.builder() + .client(new MockClient().ok(HttpMethod.GET, "/get", "1234567890abcde")) + .addCapability( + new Metrics5Capability( + metricsRegistry, new MetricSuppliers(), Map.of("env", "prod"))) + .target(new MockTarget<>(SimpleSource.class)); + + source.get("0x3456789"); + + boolean hasCustomTag = + metricsRegistry.getMetrics().keySet().stream() + .anyMatch(name -> "prod".equals(name.getTags().get("env"))); + + assertTrue(hasCustomTag); + } } From 3ed1127feb006ce5506daf0b4388de419c6e3a2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 05:18:37 +0000 Subject: [PATCH 488/615] build(deps): Bump org.projectlombok:lombok from 1.18.44 to 1.18.46 Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.44 to 1.18.46. - [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/projectlombok/lombok/compare/v1.18.44...v1.18.46) --- updated-dependencies: - dependency-name: org.projectlombok:lombok dependency-version: 1.18.46 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6aa33179e5..45fb5115eb 100644 --- a/pom.xml +++ b/pom.xml @@ -233,7 +233,7 @@ 2.3.1 1.19.4 1.1.1 - 1.18.44 + 1.18.46 3.6.2 4.2.38 5.0.6 From 6e0d323a6e36e4629f1474795df2a17ec5b409d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 05:18:46 +0000 Subject: [PATCH 489/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.36.0 to 6.37.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.36.0...v6.37.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.37.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6aa33179e5..f38bc27d67 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 3.2.0 1.2.8 4.0.0 - 6.36.0 + 6.37.0 3.34.0 3.32.1 0.25.6 From 5c955aeb135d46a2a71f47deb9310994e1995700 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 05:19:45 +0000 Subject: [PATCH 490/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.32.1 to 3.33.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.32.1...v3.33.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.33.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6aa33179e5..1fd1016209 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 4.0.0 6.36.0 3.34.0 - 3.32.1 + 3.33.0 0.25.6 1.0 From f1822fb923700ceb47a418268ddd122c280ed88c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 05:30:40 +0000 Subject: [PATCH 491/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.34.0 to 3.35.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.34.0...v3.35.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.35.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 23d65db978..89536547c5 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 1.2.8 4.0.0 6.37.0 - 3.34.0 + 3.35.0 3.33.0 0.25.6 1.0 From d907cc4c62d71ea5bb5753ba30f81dfa7291b35e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 05:18:18 +0000 Subject: [PATCH 492/615] build(deps): Bump com.graphql-java:graphql-java from 25.0 to 26.0 Bumps [com.graphql-java:graphql-java](https://github.com/graphql-java/graphql-java) from 25.0 to 26.0. - [Release notes](https://github.com/graphql-java/graphql-java/releases) - [Commits](https://github.com/graphql-java/graphql-java/commits) --- updated-dependencies: - dependency-name: com.graphql-java:graphql-java dependency-version: '26.0' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 89536547c5..fa79b96703 100644 --- a/pom.xml +++ b/pom.xml @@ -215,7 +215,7 @@ 1.6.0 1.15.0 0.23.0 - 25.0 + 26.0 4.5.0 4.5.14 5.6.1 From 02cb182c6b71f8ffe95effb7d5ede3afceed1edd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 05:18:55 +0000 Subject: [PATCH 493/615] build(deps): Bump com.gradle:common-custom-user-data-maven-extension Bumps [com.gradle:common-custom-user-data-maven-extension](https://github.com/gradle/common-custom-user-data-maven-extension) from 2.1.0 to 2.2.0. - [Release notes](https://github.com/gradle/common-custom-user-data-maven-extension/releases) - [Commits](https://github.com/gradle/common-custom-user-data-maven-extension/compare/v2.1.0...v2.2.0) --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-maven-extension dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index a4c19ac4d5..470cc18a10 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -24,6 +24,6 @@ com.gradle common-custom-user-data-maven-extension - 2.1.0 + 2.2.0 From 4bcd927126b347d75ac9124c1dd39a55c3728f95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 05:19:19 +0000 Subject: [PATCH 494/615] build(deps): Bump springboot.version from 4.0.5 to 4.0.6 Bumps `springboot.version` from 4.0.5 to 4.0.6. Updates `org.springframework.boot:spring-boot-maven-plugin` from 4.0.5 to 4.0.6 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.5...v4.0.6) Updates `org.springframework.boot:spring-boot-starter-web` from 4.0.5 to 4.0.6 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.5...v4.0.6) Updates `org.springframework.boot:spring-boot-starter-test` from 4.0.5 to 4.0.6 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.5...v4.0.6) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-maven-plugin dependency-version: 4.0.6 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: org.springframework.boot:spring-boot-starter-web dependency-version: 4.0.6 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.springframework.boot:spring-boot-starter-test dependency-version: 4.0.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fa79b96703..4f85308cc0 100644 --- a/pom.xml +++ b/pom.xml @@ -167,7 +167,7 @@ 1.15.2 2.0.17 20251224 - 4.0.5 + 4.0.6 6.0.3 2.21.2 From 68156db2b0bba705cc9fbd8ba013acea662fd87a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 05:26:10 +0000 Subject: [PATCH 495/615] build(deps): Bump kotlin.version from 2.3.20 to 2.3.21 Bumps `kotlin.version` from 2.3.20 to 2.3.21. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.3.20 to 2.3.21 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.3.20...v2.3.21) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.3.20 to 2.3.21 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.3.20...v2.3.21) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.3.20 to 2.3.21 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-version: 2.3.21 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-version: 2.3.21 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-version: 2.3.21 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 8f01635301..6e41b75061 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.3.20 + 2.3.21 1.10.2 From 88929e77af0e5dfb508f19111f3843c04d0499fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 05:26:59 +0000 Subject: [PATCH 496/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.33.0 to 3.33.1. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.33.0...v3.33.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.33.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fa79b96703..3d357473be 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 4.0.0 6.37.0 3.35.0 - 3.33.0 + 3.33.1 0.25.6 1.0 From 8bd408090c616eba2f8651ae75261e487180127c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 05:27:07 +0000 Subject: [PATCH 497/615] build(deps): Bump com.google.code.gson:gson from 2.13.2 to 2.14.0 Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.13.2 to 2.14.0. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.13.2...gson-parent-2.14.0) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-version: 2.14.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fa79b96703..4ce2466e8f 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,7 @@ 5.3.2 33.6.0-jre 2.1.0 - 2.13.2 + 2.14.0 1.15.2 2.0.17 20251224 From 7306fcbf633096afb946a8c201b9628123256aff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 05:38:41 +0000 Subject: [PATCH 498/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.35.0 to 3.35.1. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.35.0...v3.35.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.35.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index debcf6e999..108bed4c2a 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 1.2.8 4.0.0 6.37.0 - 3.35.0 + 3.35.1 3.33.1 0.25.6 1.0 From db389e359bfb8624ccc3ad28f4f5d2471729c497 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 05:38:36 +0000 Subject: [PATCH 499/615] build(deps): Bump commons-codec:commons-codec from 1.21.0 to 1.22.0 Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.21.0 to 1.22.0. - [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.21.0...rel/commons-codec-1.22.0) --- updated-dependencies: - dependency-name: commons-codec:commons-codec dependency-version: 1.22.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 108bed4c2a..e3fe303286 100644 --- a/pom.xml +++ b/pom.xml @@ -210,7 +210,7 @@ 0.7.12 1.1.1 - 1.21.0 + 1.22.0 1.6.0 1.6.0 1.15.0 From e8901e42b46be493cc918a6bfc77ce13b3e77998 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 05:37:47 +0000 Subject: [PATCH 500/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.35.1 to 3.35.2. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.35.1...v3.35.2) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.35.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e3fe303286..db4c1dfe49 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ 1.2.8 4.0.0 6.37.0 - 3.35.1 + 3.35.2 3.33.1 0.25.6 1.0 From e3bd6712716347dfbc38ef96247f427a2a30db67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 05:49:10 +0000 Subject: [PATCH 501/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.37.0 to 6.38.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.37.0...v6.38.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.38.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index db4c1dfe49..8909f684b8 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 3.2.0 1.2.8 4.0.0 - 6.37.0 + 6.38.0 3.35.2 3.33.1 0.25.6 From 94eb8a461e5a785cac7f8103ae7a3c9c9768394a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 05:49:11 +0000 Subject: [PATCH 502/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.33.1 to 3.34.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.33.1...v3.34.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.34.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index db4c1dfe49..2aecb1d4e8 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 4.0.0 6.37.0 3.35.2 - 3.33.1 + 3.34.0 0.25.6 1.0 From 70b620a5f96930d22f6e78e0a46942e8f0da934b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 05:20:22 +0000 Subject: [PATCH 503/615] build(deps): Bump jackson.version from 2.21.2 to 2.21.3 Bumps `jackson.version` from 2.21.2 to 2.21.3. Updates `com.fasterxml.jackson:jackson-bom` from 2.21.2 to 2.21.3 - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.21.2...jackson-bom-2.21.3) Updates `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider` from 2.21.2 to 2.21.3 --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.21.3 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-version: 2.21.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b52e6c6bdb..d82ff20685 100644 --- a/pom.xml +++ b/pom.xml @@ -170,7 +170,7 @@ 4.0.6 6.0.3 - 2.21.2 + 2.21.3 3.1.2 3.27.7 5.23.0 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 8e3bfd3d46..718138ecdc 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -31,7 +31,7 @@ 11 - 2.21.2 + 2.21.3 From f4e8e35f00549b48053f7208de794863869863f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 05:45:33 +0000 Subject: [PATCH 504/615] build(deps): Bump tools.jackson:jackson-bom from 3.1.2 to 3.1.3 Bumps [tools.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 3.1.2 to 3.1.3. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-3.1.2...jackson-bom-3.1.3) --- updated-dependencies: - dependency-name: tools.jackson:jackson-bom dependency-version: 3.1.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d82ff20685..b576f3edd3 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 6.0.3 2.21.3 - 3.1.2 + 3.1.3 3.27.7 5.23.0 2.0.61.android8 From 6285fa91c0bbbc04f796daacb4a26285ae5cbace Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 05:54:22 +0000 Subject: [PATCH 505/615] build(deps): Bump netty.version from 4.2.12.Final to 4.2.13.Final Bumps `netty.version` from 4.2.12.Final to 4.2.13.Final. Updates `io.netty:netty-bom` from 4.2.12.Final to 4.2.13.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.12.Final...netty-4.2.13.Final) Updates `io.netty:netty-handler` from 4.2.12.Final to 4.2.13.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.12.Final...netty-4.2.13.Final) Updates `io.netty:netty-codec-http` from 4.2.12.Final to 4.2.13.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.12.Final...netty-4.2.13.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.13.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.13.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.13.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 1f73303357..c108c2098d 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.12.Final + 4.2.13.Final true From 6f77d8e3453874ac64bd2bf6e1a31396d59ebd2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 05:20:32 +0000 Subject: [PATCH 506/615] build(deps-dev): Bump io.undertow:undertow-core Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.3.24.Final to 2.4.0.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.3.24.Final...2.4.0.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-version: 2.4.0.Final dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b576f3edd3..0ea4ceb18f 100644 --- a/pom.xml +++ b/pom.xml @@ -245,7 +245,7 @@ 5.0.1 7.0.7 7.0.7 - 2.3.24.Final + 2.4.0.Final 1.18.0 From 6c25bd44eecf4aa839664b7d2ae32f259122c40d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 05:20:44 +0000 Subject: [PATCH 507/615] build(deps): Bump com.github.jknack:handlebars from 4.5.0 to 4.5.1 Bumps [com.github.jknack:handlebars](https://github.com/jknack/handlebars.java) from 4.5.0 to 4.5.1. - [Release notes](https://github.com/jknack/handlebars.java/releases) - [Commits](https://github.com/jknack/handlebars.java/compare/v4.5.0...v4.5.1) --- updated-dependencies: - dependency-name: com.github.jknack:handlebars dependency-version: 4.5.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b576f3edd3..7b234c9977 100644 --- a/pom.xml +++ b/pom.xml @@ -216,7 +216,7 @@ 1.15.0 0.23.0 26.0 - 4.5.0 + 4.5.1 4.5.14 5.6.1 1.13.0 From b4acfb4be1bdd4fcfb05ab50e418a1d72eb98bd3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 05:22:01 +0000 Subject: [PATCH 508/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx5-test Bumps `vertx.version` from 5.0.11 to 5.0.12. Updates `io.vertx:vertx-junit5` from 5.0.11 to 5.0.12 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/5.0.11...5.0.12) Updates `io.vertx:vertx-web-client` from 5.0.11 to 5.0.12 - [Commits](https://github.com/vert-x3/vertx-web/compare/5.0.11...5.0.12) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 5.0.12 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 5.0.12 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx5-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index daa9935202..dde012d55d 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.0.11 + 5.0.12 From e1b4a980cce6f333f1e3d45a3f1aad563889da01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 05:22:02 +0000 Subject: [PATCH 509/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx4-test Bumps `vertx.version` from 4.5.26 to 4.5.27. Updates `io.vertx:vertx-junit5` from 4.5.26 to 4.5.27 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.26...4.5.27) Updates `io.vertx:vertx-web-client` from 4.5.26 to 4.5.27 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.26...4.5.27) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 4.5.27 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 4.5.27 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx4-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 3c051200c4..c58aab329c 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 4.x. - 4.5.26 + 4.5.27 From e7bf8def66c672570a74da76c34a8a8beb2f2f88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 05:20:36 +0000 Subject: [PATCH 510/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.38.0 to 6.39.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.38.0...v6.39.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.39.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4a78deb974..ba0773f5da 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,7 @@ 3.2.0 1.2.8 4.0.0 - 6.38.0 + 6.39.0 3.35.2 3.34.0 0.25.6 From fa9848e4d14b82229cbb9753fb78f45750aab2d3 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Thu, 7 May 2026 09:55:27 -0300 Subject: [PATCH 511/615] Add MethodInterceptor extension point with feign-validation and feign-http-cache modules Signed-off-by: Marvin Froeder --- AGENTS.md | 2 + core/src/main/java/feign/AsyncFeign.java | 11 + .../java/feign/AsynchronousMethodHandler.java | 82 ++++++-- core/src/main/java/feign/BaseBuilder.java | 38 ++++ core/src/main/java/feign/Feign.java | 11 + core/src/main/java/feign/Invocation.java | 84 ++++++++ .../feign/MethodHandlerConfiguration.java | 32 +++ .../main/java/feign/MethodInterceptor.java | 90 +++++++++ .../main/java/feign/MethodInterceptors.java | 34 ++++ .../java/feign/SynchronousMethodHandler.java | 52 ++++- .../java/feign/MethodInterceptorTest.java | 191 ++++++++++++++++++ http-cache/README.md | 58 ++++++ http-cache/pom.xml | 57 ++++++ .../main/java/feign/cache/CachedEntry.java | 52 +++++ .../feign/cache/HttpCacheInterceptor.java | 141 +++++++++++++ .../main/java/feign/cache/HttpCacheStore.java | 29 +++ .../feign/cache/InMemoryHttpCacheStore.java | 49 +++++ .../feign/cache/HttpCacheInterceptorTest.java | 164 +++++++++++++++ pom.xml | 27 +++ validation-jakarta/README.md | 37 ++++ validation-jakarta/pom.xml | 82 ++++++++ .../BeanValidationMethodInterceptor.java | 96 +++++++++ .../BeanValidationMethodInterceptorTest.java | 126 ++++++++++++ validation/README.md | 46 +++++ validation/pom.xml | 76 +++++++ .../BeanValidationMethodInterceptor.java | 100 +++++++++ .../BeanValidationMethodInterceptorTest.java | 126 ++++++++++++ 27 files changed, 1875 insertions(+), 18 deletions(-) create mode 100644 core/src/main/java/feign/Invocation.java create mode 100644 core/src/main/java/feign/MethodInterceptor.java create mode 100644 core/src/main/java/feign/MethodInterceptors.java create mode 100644 core/src/test/java/feign/MethodInterceptorTest.java create mode 100644 http-cache/README.md create mode 100644 http-cache/pom.xml create mode 100644 http-cache/src/main/java/feign/cache/CachedEntry.java create mode 100644 http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java create mode 100644 http-cache/src/main/java/feign/cache/HttpCacheStore.java create mode 100644 http-cache/src/main/java/feign/cache/InMemoryHttpCacheStore.java create mode 100644 http-cache/src/test/java/feign/cache/HttpCacheInterceptorTest.java create mode 100644 validation-jakarta/README.md create mode 100644 validation-jakarta/pom.xml create mode 100644 validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java create mode 100644 validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java create mode 100644 validation/README.md create mode 100644 validation/pom.xml create mode 100644 validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java create mode 100644 validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java diff --git a/AGENTS.md b/AGENTS.md index 016f882190..929d41c041 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,6 +42,8 @@ Feign is a declarative HTTP client library with a modular design: - `spring/` - Spring MVC annotation support - `hystrix/` - Circuit breaker integration - `micrometer/`, `dropwizard-metrics4/5/` - Metrics integration +- `validation/`, `validation-jakarta/` - JSR-303 / Jakarta Bean Validation via the `MethodInterceptor` extension point +- `http-cache/` - Conditional revalidation (`ETag` / `Last-Modified` / `304 Not Modified`) via the `MethodInterceptor` extension point ### Key Design Patterns - **Builder Pattern**: `Feign.builder()` for configuring clients diff --git a/core/src/main/java/feign/AsyncFeign.java b/core/src/main/java/feign/AsyncFeign.java index 67948dd46e..42e835a0e3 100644 --- a/core/src/main/java/feign/AsyncFeign.java +++ b/core/src/main/java/feign/AsyncFeign.java @@ -187,6 +187,16 @@ public AsyncBuilder requestInterceptors(Iterable requestI return super.requestInterceptors(requestInterceptors); } + @Override + public AsyncBuilder methodInterceptor(MethodInterceptor methodInterceptor) { + return super.methodInterceptor(methodInterceptor); + } + + @Override + public AsyncBuilder methodInterceptors(Iterable methodInterceptors) { + return super.methodInterceptors(methodInterceptors); + } + @Override public AsyncBuilder invocationHandlerFactory( InvocationHandlerFactory invocationHandlerFactory) { @@ -215,6 +225,7 @@ public AsyncFeign internalBuild() { client, retryer, requestInterceptors, + methodInterceptors, responseHandler, logger, logLevel, diff --git a/core/src/main/java/feign/AsynchronousMethodHandler.java b/core/src/main/java/feign/AsynchronousMethodHandler.java index 4b9af33fa3..5ca29124ae 100644 --- a/core/src/main/java/feign/AsynchronousMethodHandler.java +++ b/core/src/main/java/feign/AsynchronousMethodHandler.java @@ -22,6 +22,7 @@ import feign.InvocationHandlerFactory.MethodHandler; import feign.Request.Options; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -56,23 +57,39 @@ private AsynchronousMethodHandler( public Object invoke(Object[] argv) throws Throwable { RequestTemplate template = methodHandlerConfiguration.getBuildTemplateFromArgs().create(argv); Options options = findOptions(argv); - Retryer retryer = this.methodHandlerConfiguration.getRetryer().clone(); - try { - if (methodInfo.isAsyncReturnType()) { - return executeAndDecode(template, options, retryer); - } else { - return executeAndDecode(template, options, retryer).join(); - } - } catch (CompletionException e) { - throw e.getCause(); + Invocation invocation = + new Invocation( + methodHandlerConfiguration.getTarget(), + methodHandlerConfiguration.getMetadata(), + template, + argv); + + MethodInterceptor.Chain endOfChain = + inv -> { + Retryer retryer = this.methodHandlerConfiguration.getRetryer().clone(); + try { + if (methodInfo.isAsyncReturnType()) { + return executeAndDecode(inv, options, retryer); + } else { + return executeAndDecode(inv, options, retryer).join(); + } + } catch (CompletionException e) { + throw e.getCause(); + } + }; + MethodInterceptor.Chain chain = endOfChain; + List methodInterceptors = methodHandlerConfiguration.getMethodInterceptors(); + for (int i = methodInterceptors.size() - 1; i >= 0; i--) { + chain = methodInterceptors.get(i).apply(chain); } + return chain.next(invocation); } private CompletableFuture executeAndDecode( - RequestTemplate template, Options options, Retryer retryer) { + Invocation invocation, Options options, Retryer retryer) { CancellableFuture resultFuture = new CancellableFuture<>(); - executeAndDecode(template, options) + executeAndDecode(invocation, options) .whenComplete( (response, throwable) -> { if (throwable != null) { @@ -85,7 +102,7 @@ private CompletableFuture executeAndDecode( methodHandlerConfiguration.getLogLevel()); } - resultFuture.setInner(executeAndDecode(template, options, retryer)); + resultFuture.setInner(executeAndDecode(invocation, options, retryer)); } } else { resultFuture.complete(response); @@ -154,7 +171,8 @@ private boolean shouldRetry( } } - private CompletableFuture executeAndDecode(RequestTemplate template, Options options) { + private CompletableFuture executeAndDecode(Invocation invocation, Options options) { + RequestTemplate template = invocation.requestTemplate(); Request request = targetRequest(template); if (methodHandlerConfiguration.getLogLevel() != Logger.Level.NONE) { @@ -170,9 +188,12 @@ private CompletableFuture executeAndDecode(RequestTemplate template, Opt return client .execute(request, options, Optional.ofNullable(requestContext)) .thenApply( - response -> - // TODO: remove in Feign 12 - ensureRequestIsSet(response, template, request)) + response -> { + // TODO: remove in Feign 12 + Response withRequest = ensureRequestIsSet(response, template, request); + invocation.response(withRequest); + return withRequest; + }) .exceptionally( throwable -> { CompletionException completionException = @@ -237,6 +258,7 @@ static class Factory implements MethodHandler.Factory { private final AsyncClient client; private final Retryer retryer; private final List requestInterceptors; + private final List methodInterceptors; private final AsyncResponseHandler responseHandler; private final Logger logger; private final Logger.Level logLevel; @@ -256,9 +278,36 @@ static class Factory implements MethodHandler.Factory { MethodInfoResolver methodInfoResolver, RequestTemplateFactoryResolver requestTemplateFactoryResolver, Options options) { + this( + client, + retryer, + requestInterceptors, + Collections.emptyList(), + responseHandler, + logger, + logLevel, + propagationPolicy, + methodInfoResolver, + requestTemplateFactoryResolver, + options); + } + + Factory( + AsyncClient client, + Retryer retryer, + List requestInterceptors, + List methodInterceptors, + AsyncResponseHandler responseHandler, + Logger logger, + Logger.Level logLevel, + ExceptionPropagationPolicy propagationPolicy, + MethodInfoResolver methodInfoResolver, + RequestTemplateFactoryResolver requestTemplateFactoryResolver, + Options options) { this.client = checkNotNull(client, "client"); this.retryer = checkNotNull(retryer, "retryer"); this.requestInterceptors = checkNotNull(requestInterceptors, "requestInterceptors"); + this.methodInterceptors = checkNotNull(methodInterceptors, "methodInterceptors"); this.responseHandler = responseHandler; this.logger = checkNotNull(logger, "logger"); this.logLevel = checkNotNull(logLevel, "logLevel"); @@ -280,6 +329,7 @@ public MethodHandler create(Target target, MethodMetadata metadata, C request target, retryer, requestInterceptors, + methodInterceptors, logger, logLevel, buildTemplateFromArgs, diff --git a/core/src/main/java/feign/BaseBuilder.java b/core/src/main/java/feign/BaseBuilder.java index 354f01fab7..09d24611cb 100644 --- a/core/src/main/java/feign/BaseBuilder.java +++ b/core/src/main/java/feign/BaseBuilder.java @@ -42,6 +42,7 @@ public abstract class BaseBuilder, T> implements Clo protected List requestInterceptors = new ArrayList<>(); protected List responseInterceptors = new ArrayList<>(); + protected List methodInterceptors = new ArrayList<>(); protected Logger.Level logLevel = Logger.Level.NONE; protected Contract contract = new DefaultContract(); protected Retryer retryer = new DefaultRetryer(); @@ -219,6 +220,27 @@ public B responseInterceptor(ResponseInterceptor responseInterceptor) { return thisB; } + /** + * Adds a single {@link MethodInterceptor} to the builder. Method interceptors run after contract + * resolution and wrap the entire HTTP exchange (request interceptors, HTTP execution, response + * interceptors, decoding). They have access to raw method arguments via {@link Invocation}. + */ + @Experimental + public B methodInterceptor(MethodInterceptor methodInterceptor) { + this.methodInterceptors.add(methodInterceptor); + return thisB; + } + + /** Sets the full set of method interceptors, overwriting any previously configured. */ + @Experimental + public B methodInterceptors(Iterable methodInterceptors) { + this.methodInterceptors.clear(); + for (MethodInterceptor methodInterceptor : methodInterceptors) { + this.methodInterceptors.add(methodInterceptor); + } + return thisB; + } + /** Allows you to override how reflective dispatch works inside of Feign. */ public B invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) { this.invocationHandlerFactory = invocationHandlerFactory; @@ -305,6 +327,21 @@ B enrich() { capabilities); clone.responseInterceptors = responseInterceptors.interceptors(); + // enrich each method interceptor, then enrich the list as a whole + MethodInterceptor[] methodArray = clone.methodInterceptors.toArray(new MethodInterceptor[0]); + for (int i = 0; i < methodArray.length; i++) { + methodArray[i] = + (MethodInterceptor) + Capability.enrich(methodArray[i], MethodInterceptor.class, capabilities); + } + MethodInterceptors methodInterceptors = + (MethodInterceptors) + Capability.enrich( + new MethodInterceptors(Arrays.asList(methodArray)), + MethodInterceptors.class, + capabilities); + clone.methodInterceptors = methodInterceptors.interceptors(); + return clone; } catch (CloneNotSupportedException e) { throw new AssertionError(e); @@ -322,6 +359,7 @@ List getFieldsToEnrich() { // interceptor lists are enriched per-element then as a whole via custom types .filter(field -> !Objects.equals(field.getName(), "requestInterceptors")) .filter(field -> !Objects.equals(field.getName(), "responseInterceptors")) + .filter(field -> !Objects.equals(field.getName(), "methodInterceptors")) // skip primitive types .filter(field -> !field.getType().isPrimitive()) // skip enumerations diff --git a/core/src/main/java/feign/Feign.java b/core/src/main/java/feign/Feign.java index c9095fb1d8..d7e466247d 100644 --- a/core/src/main/java/feign/Feign.java +++ b/core/src/main/java/feign/Feign.java @@ -169,6 +169,16 @@ public Builder requestInterceptors(Iterable requestIntercept return super.requestInterceptors(requestInterceptors); } + @Override + public Builder methodInterceptor(MethodInterceptor methodInterceptor) { + return super.methodInterceptor(methodInterceptor); + } + + @Override + public Builder methodInterceptors(Iterable methodInterceptors) { + return super.methodInterceptors(methodInterceptors); + } + @Override public Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) { return super.invocationHandlerFactory(invocationHandlerFactory); @@ -219,6 +229,7 @@ public Feign internalBuild() { client, retryer, requestInterceptors, + methodInterceptors, responseHandler, logger, logLevel, diff --git a/core/src/main/java/feign/Invocation.java b/core/src/main/java/feign/Invocation.java new file mode 100644 index 0000000000..e1a2c80a49 --- /dev/null +++ b/core/src/main/java/feign/Invocation.java @@ -0,0 +1,84 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import static feign.Util.checkNotNull; + +import java.lang.reflect.Method; + +/** + * Context for a single method invocation passed to {@link MethodInterceptor}s. Exposes the resolved + * {@link RequestTemplate} (mutable until the request is sent), the contract's {@link + * MethodMetadata}, the raw method arguments, and — after the chain has executed the HTTP call — the + * resulting {@link Response}. + */ +@Experimental +public final class Invocation { + + private final Target target; + private final MethodMetadata methodMetadata; + private final RequestTemplate requestTemplate; + private final Object[] arguments; + private volatile Response response; + + public Invocation( + Target target, + MethodMetadata methodMetadata, + RequestTemplate requestTemplate, + Object[] arguments) { + this.target = checkNotNull(target, "target"); + this.methodMetadata = checkNotNull(methodMetadata, "methodMetadata"); + this.requestTemplate = checkNotNull(requestTemplate, "requestTemplate"); + this.arguments = arguments; + } + + public Target target() { + return target; + } + + public MethodMetadata methodMetadata() { + return methodMetadata; + } + + /** Convenience accessor for the underlying reflective {@link Method}. */ + public Method method() { + return methodMetadata.method(); + } + + /** The mutable, contract-resolved request template. Mutations are visible downstream. */ + public RequestTemplate requestTemplate() { + return requestTemplate; + } + + /** Raw arguments passed to the proxied method. May be {@code null} for no-arg methods. */ + public Object[] arguments() { + return arguments; + } + + /** + * The HTTP {@link Response} captured after the framework's terminal chain step. Returns {@code + * null} when the chain has not yet executed the HTTP call, or when the call failed before a + * response was received. + */ + public Response response() { + return response; + } + + /** Package-private setter used by the framework's terminal chain step. */ + void response(Response response) { + this.response = response; + } +} diff --git a/core/src/main/java/feign/MethodHandlerConfiguration.java b/core/src/main/java/feign/MethodHandlerConfiguration.java index b928d24114..cef42d3be2 100644 --- a/core/src/main/java/feign/MethodHandlerConfiguration.java +++ b/core/src/main/java/feign/MethodHandlerConfiguration.java @@ -17,6 +17,7 @@ import static feign.Util.checkNotNull; +import java.util.Collections; import java.util.List; public class MethodHandlerConfiguration { @@ -29,6 +30,8 @@ public class MethodHandlerConfiguration { private final List requestInterceptors; + private final List methodInterceptors; + private final Logger logger; private final Logger.Level logLevel; @@ -55,6 +58,10 @@ public List getRequestInterceptors() { return requestInterceptors; } + public List getMethodInterceptors() { + return methodInterceptors; + } + public Logger getLogger() { return logger; } @@ -85,10 +92,35 @@ public MethodHandlerConfiguration( RequestTemplate.Factory buildTemplateFromArgs, Request.Options options, ExceptionPropagationPolicy propagationPolicy) { + this( + metadata, + target, + retryer, + requestInterceptors, + Collections.emptyList(), + logger, + logLevel, + buildTemplateFromArgs, + options, + propagationPolicy); + } + + public MethodHandlerConfiguration( + MethodMetadata metadata, + Target target, + Retryer retryer, + List requestInterceptors, + List methodInterceptors, + Logger logger, + Logger.Level logLevel, + RequestTemplate.Factory buildTemplateFromArgs, + Request.Options options, + ExceptionPropagationPolicy propagationPolicy) { this.target = checkNotNull(target, "target"); this.retryer = checkNotNull(retryer, "retryer for %s", target); this.requestInterceptors = checkNotNull(requestInterceptors, "requestInterceptors for %s", target); + this.methodInterceptors = checkNotNull(methodInterceptors, "methodInterceptors for %s", target); this.logger = checkNotNull(logger, "logger for %s", target); this.logLevel = checkNotNull(logLevel, "logLevel for %s", target); this.metadata = checkNotNull(metadata, "metadata for %s", target); diff --git a/core/src/main/java/feign/MethodInterceptor.java b/core/src/main/java/feign/MethodInterceptor.java new file mode 100644 index 0000000000..2a1e3ade25 --- /dev/null +++ b/core/src/main/java/feign/MethodInterceptor.java @@ -0,0 +1,90 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +/** + * An around-style interceptor invoked once per method call, after the {@link Contract} has resolved + * the {@link RequestTemplate} from method arguments and before {@link RequestInterceptor}s mutate + * it. Implementations have full access to the raw method arguments, the {@link MethodMetadata}, the + * resolved {@link RequestTemplate} (headers, query params, body bytes), and after {@link + * Chain#next(Invocation)} completes successfully, the {@link Response} via {@link + * Invocation#response()}. + * + *

Use this extension point when {@link RequestInterceptor} or {@link ResponseInterceptor} are + * not enough — typically when you need both the typed argument objects (e.g. for validation) and + * the resolved request, or when you need to short-circuit the entire HTTP exchange and return a + * value without sending a request. + * + *

Short-circuit: simply return a value without calling {@link Chain#next(Invocation)}. + * + *

Exception propagation: any {@link Throwable} thrown surfaces to the caller of the Feign + * interface method, after retry handling. + * + *

+ * public Object intercept(Invocation invocation, Chain chain) throws Throwable {
+ *   validate(invocation.arguments());
+ *   return chain.next(invocation);
+ * }
+ * 
+ */ +@Experimental +public interface MethodInterceptor { + + /** + * Called for every method invocation on a Feign-built proxy. + * + * @param invocation context for the current method call + * @param chain delegate to invoke the rest of the pipeline (request interceptors, HTTP, response + * interceptors, decoder) + * @return the value to return from the proxied method + */ + Object intercept(Invocation invocation, Chain chain) throws Throwable; + + /** + * Apply this interceptor to the given chain, producing a chain that runs this interceptor first. + */ + default Chain apply(Chain chain) { + return invocation -> intercept(invocation, chain); + } + + /** + * Returns a new {@link MethodInterceptor} that invokes the current interceptor first and then the + * one passed in. + */ + default MethodInterceptor andThen(MethodInterceptor next) { + return (invocation, chain) -> + intercept(invocation, nextInvocation -> next.intercept(nextInvocation, chain)); + } + + /** Contract for delegation to the rest of the chain. */ + interface Chain { + + /** Sentinel end-of-chain that throws if invoked; the framework provides a real terminal. */ + Chain DEFAULT = + invocation -> { + throw new UnsupportedOperationException("end of MethodInterceptor chain"); + }; + + /** + * Delegate to the rest of the chain. + * + * @param invocation invocation context (typically the same instance received by {@link + * #intercept(Invocation, Chain)}) + * @return value produced by the downstream chain + */ + Object next(Invocation invocation) throws Throwable; + } +} diff --git a/core/src/main/java/feign/MethodInterceptors.java b/core/src/main/java/feign/MethodInterceptors.java new file mode 100644 index 0000000000..43bf5f1216 --- /dev/null +++ b/core/src/main/java/feign/MethodInterceptors.java @@ -0,0 +1,34 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** Capability-friendly wrapper around the configured {@link MethodInterceptor}s. */ +public final class MethodInterceptors { + + private final List interceptors; + + public MethodInterceptors(List interceptors) { + this.interceptors = new ArrayList<>(interceptors); + } + + public List interceptors() { + return Collections.unmodifiableList(interceptors); + } +} diff --git a/core/src/main/java/feign/SynchronousMethodHandler.java b/core/src/main/java/feign/SynchronousMethodHandler.java index b7424a5a85..4576c4533b 100644 --- a/core/src/main/java/feign/SynchronousMethodHandler.java +++ b/core/src/main/java/feign/SynchronousMethodHandler.java @@ -22,6 +22,7 @@ import feign.InvocationHandlerFactory.MethodHandler; import feign.Request.Options; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @@ -47,10 +48,27 @@ private SynchronousMethodHandler( public Object invoke(Object[] argv) throws Throwable { RequestTemplate template = methodHandlerConfiguration.getBuildTemplateFromArgs().create(argv); Options options = findOptions(argv); + Invocation invocation = + new Invocation( + methodHandlerConfiguration.getTarget(), + methodHandlerConfiguration.getMetadata(), + template, + argv); + + MethodInterceptor.Chain endOfChain = inv -> runWithRetry(inv, options); + MethodInterceptor.Chain chain = endOfChain; + List methodInterceptors = methodHandlerConfiguration.getMethodInterceptors(); + for (int i = methodInterceptors.size() - 1; i >= 0; i--) { + chain = methodInterceptors.get(i).apply(chain); + } + return chain.next(invocation); + } + + private Object runWithRetry(Invocation invocation, Options options) throws Throwable { Retryer retryer = this.methodHandlerConfiguration.getRetryer().clone(); while (true) { try { - return executeAndDecode(template, options); + return executeAndDecode(invocation, options); } catch (RetryableException e) { try { retryer.continueOrPropagate(e); @@ -74,7 +92,8 @@ public Object invoke(Object[] argv) throws Throwable { } } - Object executeAndDecode(RequestTemplate template, Options options) throws Throwable { + Object executeAndDecode(Invocation invocation, Options options) throws Throwable { + RequestTemplate template = invocation.requestTemplate(); Request request = targetRequest(template); if (methodHandlerConfiguration.getLogLevel() != Logger.Level.NONE) { @@ -105,6 +124,8 @@ Object executeAndDecode(RequestTemplate template, Options options) throws Throwa throw errorExecuting(request, e); } + invocation.response(response); + long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); return responseHandler.handleResponse( methodHandlerConfiguration.getMetadata().configKey(), response, @@ -143,6 +164,7 @@ static class Factory implements MethodHandler.Factory { private final Client client; private final Retryer retryer; private final List requestInterceptors; + private final List methodInterceptors; private final ResponseHandler responseHandler; private final Logger logger; private final Logger.Level logLevel; @@ -160,9 +182,34 @@ static class Factory implements MethodHandler.Factory { ExceptionPropagationPolicy propagationPolicy, RequestTemplateFactoryResolver requestTemplateFactoryResolver, Options options) { + this( + client, + retryer, + requestInterceptors, + Collections.emptyList(), + responseHandler, + logger, + logLevel, + propagationPolicy, + requestTemplateFactoryResolver, + options); + } + + Factory( + Client client, + Retryer retryer, + List requestInterceptors, + List methodInterceptors, + ResponseHandler responseHandler, + Logger logger, + Logger.Level logLevel, + ExceptionPropagationPolicy propagationPolicy, + RequestTemplateFactoryResolver requestTemplateFactoryResolver, + Options options) { this.client = checkNotNull(client, "client"); this.retryer = checkNotNull(retryer, "retryer"); this.requestInterceptors = checkNotNull(requestInterceptors, "requestInterceptors"); + this.methodInterceptors = checkNotNull(methodInterceptors, "methodInterceptors"); this.responseHandler = checkNotNull(responseHandler, "responseHandler"); this.logger = checkNotNull(logger, "logger"); this.logLevel = checkNotNull(logLevel, "logLevel"); @@ -182,6 +229,7 @@ public MethodHandler create(Target target, MethodMetadata md, Object requestC target, retryer, requestInterceptors, + methodInterceptors, logger, logLevel, buildTemplateFromArgs, diff --git a/core/src/test/java/feign/MethodInterceptorTest.java b/core/src/test/java/feign/MethodInterceptorTest.java new file mode 100644 index 0000000000..9885c03841 --- /dev/null +++ b/core/src/test/java/feign/MethodInterceptorTest.java @@ -0,0 +1,191 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class MethodInterceptorTest { + + private final MockWebServer server = new MockWebServer(); + + @AfterEach + void tearDown() throws Exception { + server.shutdown(); + } + + interface Api { + @RequestLine("POST /things") + String send(String body); + + @RequestLine("GET /things/{id}") + String fetch(@Param("id") String id); + } + + @Test + void interceptorRunsAfterContractAndBeforeRequestInterceptor() throws Exception { + server.enqueue(new MockResponse().setBody("ok")); + + AtomicReference seenByMethodInterceptor = new AtomicReference<>(); + AtomicReference seenByRequestInterceptor = new AtomicReference<>(); + + MethodInterceptor methodInterceptor = + (invocation, chain) -> { + seenByMethodInterceptor.set(invocation.requestTemplate()); + // headers set here are visible to RequestInterceptors + invocation.requestTemplate().header("X-From-Method", "yes"); + return chain.next(invocation); + }; + RequestInterceptor requestInterceptor = + template -> { + seenByRequestInterceptor.set(template); + assertThat(template.headers().get("X-From-Method")).contains("yes"); + template.header("X-From-Request", "yes"); + }; + + Api api = + Feign.builder() + .methodInterceptor(methodInterceptor) + .requestInterceptor(requestInterceptor) + .target(Api.class, "http://localhost:" + server.getPort()); + + api.send("payload"); + + assertThat(seenByMethodInterceptor.get()).isNotNull(); + assertThat(seenByRequestInterceptor.get()).isNotNull(); + assertThat(server.takeRequest().getHeader("X-From-Method")).isEqualTo("yes"); + } + + @Test + void interceptorCanShortCircuit() throws Exception { + MethodInterceptor methodInterceptor = (invocation, chain) -> "short-circuited"; + + Api api = + Feign.builder() + .methodInterceptor(methodInterceptor) + .target(Api.class, "http://localhost:" + server.getPort()); + + String result = api.send("ignored"); + + assertThat(result).isEqualTo("short-circuited"); + assertThat(server.getRequestCount()).isZero(); + } + + @Test + void interceptorExceptionSurfacesToCaller() { + RuntimeException boom = new IllegalStateException("nope"); + MethodInterceptor methodInterceptor = + (invocation, chain) -> { + throw boom; + }; + + Api api = + Feign.builder() + .methodInterceptor(methodInterceptor) + .target(Api.class, "http://localhost:" + server.getPort()); + + assertThatThrownBy(() -> api.send("x")).isSameAs(boom); + assertThat(server.getRequestCount()).isZero(); + } + + @Test + void interceptorSeesResponseAfterChainCompletes() throws Exception { + server.enqueue(new MockResponse().setHeader("ETag", "v1").setBody("payload")); + + AtomicReference captured = new AtomicReference<>(); + MethodInterceptor methodInterceptor = + (invocation, chain) -> { + assertThat(invocation.response()).isNull(); + Object result = chain.next(invocation); + captured.set(invocation.response()); + return result; + }; + + Api api = + Feign.builder() + .methodInterceptor(methodInterceptor) + .target(Api.class, "http://localhost:" + server.getPort()); + + api.fetch("42"); + + Response response = captured.get(); + assertThat(response).isNotNull(); + assertThat(response.status()).isEqualTo(200); + assertThat(response.headers().get("etag")).contains("v1"); + } + + @Test + void chainOrderIsRegistrationOrder() throws Exception { + server.enqueue(new MockResponse().setBody("ok")); + + List visited = new ArrayList<>(); + MethodInterceptor first = + (invocation, chain) -> { + visited.add("first-pre"); + Object result = chain.next(invocation); + visited.add("first-post"); + return result; + }; + MethodInterceptor second = + (invocation, chain) -> { + visited.add("second-pre"); + Object result = chain.next(invocation); + visited.add("second-post"); + return result; + }; + + Api api = + Feign.builder() + .methodInterceptor(first) + .methodInterceptor(second) + .target(Api.class, "http://localhost:" + server.getPort()); + + api.fetch("1"); + + assertThat(visited).containsExactly("first-pre", "second-pre", "second-post", "first-post"); + } + + @Test + void invocationExposesArguments() throws Exception { + server.enqueue(new MockResponse().setBody("ok")); + + AtomicReference seenArgs = new AtomicReference<>(); + MethodInterceptor methodInterceptor = + (invocation, chain) -> { + seenArgs.set(invocation.arguments()); + assertThat(invocation.method().getName()).isEqualTo("send"); + assertThat(invocation.target().type()).isEqualTo(Api.class); + return chain.next(invocation); + }; + + Api api = + Feign.builder() + .methodInterceptor(methodInterceptor) + .target(Api.class, "http://localhost:" + server.getPort()); + + api.send("hello"); + + assertThat(seenArgs.get()).containsExactly("hello"); + } +} diff --git a/http-cache/README.md b/http-cache/README.md new file mode 100644 index 0000000000..1e10baab3c --- /dev/null +++ b/http-cache/README.md @@ -0,0 +1,58 @@ +Feign HTTP Cache +================ + +A `MethodInterceptor` that performs conditional HTTP revalidation using `ETag` and +`Last-Modified` headers. On the first call, the decoded response is stored alongside +its validators. Subsequent calls send `If-None-Match` / `If-Modified-Since` headers, +and a `304 Not Modified` response short-circuits to the cached value. + +Marked `@Experimental` while the underlying `feign.MethodInterceptor` API stabilises. + +```xml + + io.github.openfeign + feign-http-cache + ${feign.version} + +``` + +Usage +----- + +```java +HttpCacheStore store = new InMemoryHttpCacheStore(); + +Api api = Feign.builder() + .methodInterceptor(new HttpCacheInterceptor(store)) + .target(Api.class, "https://example.com"); +``` + +Plug in a different store (Caffeine, Redis, etc.) by implementing `HttpCacheStore`. + +Customising +----------- + +- `keyFn`: derive the cache key from an `Invocation` (e.g. include a tenant header). +- `cacheable`: decide which `RequestTemplate`s participate. The default is `GET` / + `HEAD` only. + +```java +HttpCacheInterceptor configured = new HttpCacheInterceptor(store) + .key(invocation -> invocation.methodMetadata().configKey() + + "|" + invocation.requestTemplate().url() + + "|" + invocation.requestTemplate().headers().get("X-Tenant")) + .cacheable(template -> "GET".equalsIgnoreCase(template.method())); +``` + +Caveats +------- + +- 304 detection relies on the configured `ErrorDecoder` raising a `FeignException` + for non-2xx responses (the default). A custom error decoder that swallows or + transforms 304 will break cache hits. +- The store retains the **decoded** response object. Decoding happens once, on the + first 200; on a 304 the cached object is returned as-is. Mutations on the returned + object propagate to subsequent callers — return immutable values from your decoder + if that matters. +- `Cache-Control` directives beyond `no-store` are not interpreted; freshness windows + (`max-age`, etc.) are not enforced. Every cached entry triggers revalidation. diff --git a/http-cache/pom.xml b/http-cache/pom.xml new file mode 100644 index 0000000000..9d471c7379 --- /dev/null +++ b/http-cache/pom.xml @@ -0,0 +1,57 @@ + + + + 4.0.0 + + + io.github.openfeign + feign-parent + 13.13-SNAPSHOT + + + feign-http-cache + Feign HTTP Cache + Feign HTTP Cache (ETag / Last-Modified) + + + + ${project.groupId} + feign-core + + + + ${project.groupId} + feign-core + test-jar + test + + + + com.squareup.okhttp3 + mockwebserver + test + + + org.junit.jupiter + junit-jupiter + test + + + + diff --git a/http-cache/src/main/java/feign/cache/CachedEntry.java b/http-cache/src/main/java/feign/cache/CachedEntry.java new file mode 100644 index 0000000000..708d2c43ff --- /dev/null +++ b/http-cache/src/main/java/feign/cache/CachedEntry.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.cache; + +import feign.Experimental; +import java.time.Instant; + +/** Immutable cache record produced from a successful response with revalidation headers. */ +@Experimental +public final class CachedEntry { + + private final Object value; + private final String etag; + private final String lastModified; + private final Instant storedAt; + + public CachedEntry(Object value, String etag, String lastModified, Instant storedAt) { + this.value = value; + this.etag = etag; + this.lastModified = lastModified; + this.storedAt = storedAt; + } + + public Object value() { + return value; + } + + public String etag() { + return etag; + } + + public String lastModified() { + return lastModified; + } + + public Instant storedAt() { + return storedAt; + } +} diff --git a/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java b/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java new file mode 100644 index 0000000000..a762da072c --- /dev/null +++ b/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java @@ -0,0 +1,141 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.cache; + +import feign.Experimental; +import feign.FeignException; +import feign.Invocation; +import feign.MethodInterceptor; +import feign.RequestTemplate; +import feign.Response; +import java.time.Instant; +import java.util.Collection; +import java.util.Map; +import java.util.function.Function; + +/** + * A {@link MethodInterceptor} that adds conditional revalidation headers ({@code If-None-Match} / + * {@code If-Modified-Since}) to outgoing requests and, on a {@code 304 Not Modified} response, + * returns the previously decoded value from {@link HttpCacheStore} without re-decoding. + * + *

Successful responses (2xx) carrying an {@code ETag} or {@code Last-Modified} header are + * stored. Responses with {@code Cache-Control: no-store} are skipped. + * + *

Default scope is HTTP {@code GET} and {@code HEAD}; override via {@link #cacheable(Function)}. + * + *

Important: 304 detection relies on the configured {@link feign.codec.ErrorDecoder} + * raising a {@link FeignException} for non-2xx responses (the default behaviour). If a custom error + * decoder swallows or transforms 304 responses, the cache hit path will not fire. + */ +@Experimental +public final class HttpCacheInterceptor implements MethodInterceptor { + + private final HttpCacheStore store; + private final Function keyFn; + private final Function cacheable; + + public HttpCacheInterceptor(HttpCacheStore store) { + this(store, HttpCacheInterceptor::defaultKey, HttpCacheInterceptor::defaultCacheable); + } + + private HttpCacheInterceptor( + HttpCacheStore store, + Function keyFn, + Function cacheable) { + this.store = store; + this.keyFn = keyFn; + this.cacheable = cacheable; + } + + /** Override how cache keys are derived from an invocation. */ + public HttpCacheInterceptor key(Function keyFn) { + return new HttpCacheInterceptor(store, keyFn, cacheable); + } + + /** Override which requests participate in the cache. */ + public HttpCacheInterceptor cacheable(Function cacheable) { + return new HttpCacheInterceptor(store, keyFn, cacheable); + } + + @Override + public Object intercept(Invocation invocation, Chain chain) throws Throwable { + RequestTemplate template = invocation.requestTemplate(); + if (!Boolean.TRUE.equals(cacheable.apply(template))) { + return chain.next(invocation); + } + String key = keyFn.apply(invocation); + CachedEntry hit = store.get(key); + if (hit != null) { + if (hit.etag() != null) { + template.header("If-None-Match", hit.etag()); + } + if (hit.lastModified() != null) { + template.header("If-Modified-Since", hit.lastModified()); + } + } + try { + Object result = chain.next(invocation); + Response response = invocation.response(); + if (response != null + && response.status() >= 200 + && response.status() < 300 + && !hasNoStore(response)) { + String etag = firstHeader(response.headers(), "ETag"); + String lastMod = firstHeader(response.headers(), "Last-Modified"); + if (etag != null || lastMod != null) { + store.put(key, new CachedEntry(result, etag, lastMod, Instant.now())); + } + } + return result; + } catch (FeignException e) { + if (e.status() == 304 && hit != null) { + return hit.value(); + } + throw e; + } + } + + private static String defaultKey(Invocation invocation) { + RequestTemplate template = invocation.requestTemplate(); + return invocation.methodMetadata().configKey() + "|" + template.method() + " " + template.url(); + } + + private static Boolean defaultCacheable(RequestTemplate template) { + String method = template.method(); + return "GET".equalsIgnoreCase(method) || "HEAD".equalsIgnoreCase(method); + } + + private static boolean hasNoStore(Response response) { + Collection values = response.headers().get("Cache-Control"); + if (values == null) { + return false; + } + for (String value : values) { + if (value != null && value.toLowerCase().contains("no-store")) { + return true; + } + } + return false; + } + + private static String firstHeader(Map> headers, String name) { + Collection values = headers.get(name); + if (values == null || values.isEmpty()) { + return null; + } + return values.iterator().next(); + } +} diff --git a/http-cache/src/main/java/feign/cache/HttpCacheStore.java b/http-cache/src/main/java/feign/cache/HttpCacheStore.java new file mode 100644 index 0000000000..42f39a2f07 --- /dev/null +++ b/http-cache/src/main/java/feign/cache/HttpCacheStore.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.cache; + +import feign.Experimental; + +/** Backing store for {@link HttpCacheInterceptor}. Implementations must be thread-safe. */ +@Experimental +public interface HttpCacheStore { + + CachedEntry get(String key); + + void put(String key, CachedEntry entry); + + void invalidate(String key); +} diff --git a/http-cache/src/main/java/feign/cache/InMemoryHttpCacheStore.java b/http-cache/src/main/java/feign/cache/InMemoryHttpCacheStore.java new file mode 100644 index 0000000000..14fc715383 --- /dev/null +++ b/http-cache/src/main/java/feign/cache/InMemoryHttpCacheStore.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.cache; + +import feign.Experimental; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * Unbounded {@link HttpCacheStore} backed by a {@link ConcurrentHashMap}. Suitable for tests and + * small deployments. Plug in a custom store backed by Caffeine, Redis, etc. for production. + */ +@Experimental +public final class InMemoryHttpCacheStore implements HttpCacheStore { + + private final ConcurrentMap entries = new ConcurrentHashMap<>(); + + @Override + public CachedEntry get(String key) { + return entries.get(key); + } + + @Override + public void put(String key, CachedEntry entry) { + entries.put(key, entry); + } + + @Override + public void invalidate(String key) { + entries.remove(key); + } + + public int size() { + return entries.size(); + } +} diff --git a/http-cache/src/test/java/feign/cache/HttpCacheInterceptorTest.java b/http-cache/src/test/java/feign/cache/HttpCacheInterceptorTest.java new file mode 100644 index 0000000000..677505bfcd --- /dev/null +++ b/http-cache/src/test/java/feign/cache/HttpCacheInterceptorTest.java @@ -0,0 +1,164 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.cache; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import feign.Feign; +import feign.FeignException; +import feign.Param; +import feign.RequestLine; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class HttpCacheInterceptorTest { + + private final MockWebServer server = new MockWebServer(); + private final InMemoryHttpCacheStore store = new InMemoryHttpCacheStore(); + + @AfterEach + void tearDown() throws Exception { + server.shutdown(); + } + + interface Api { + @RequestLine("GET /things/{id}") + String fetch(@Param("id") String id); + + @RequestLine("POST /things") + String create(String body); + } + + private Api api() { + return Feign.builder() + .methodInterceptor(new HttpCacheInterceptor(store)) + .target(Api.class, "http://localhost:" + server.getPort()); + } + + @Test + void firstCallStoresEntryWhenETagPresent() throws Exception { + server.enqueue(new MockResponse().setHeader("ETag", "\"v1\"").setBody("payload-1")); + + String result = api().fetch("42"); + + assertThat(result).isEqualTo("payload-1"); + assertThat(store.size()).isEqualTo(1); + RecordedRequest first = server.takeRequest(); + assertThat(first.getHeader("If-None-Match")).isNull(); + } + + @Test + void notModifiedReturnsCachedValueAndSendsConditionalHeader() throws Exception { + server.enqueue(new MockResponse().setHeader("ETag", "\"v1\"").setBody("payload-1")); + server.enqueue(new MockResponse().setResponseCode(304)); + + Api api = api(); + String first = api.fetch("42"); + String second = api.fetch("42"); + + assertThat(first).isEqualTo("payload-1"); + assertThat(second).isEqualTo("payload-1"); + server.takeRequest(); // first + RecordedRequest revalidation = server.takeRequest(); + assertThat(revalidation.getHeader("If-None-Match")).isEqualTo("\"v1\""); + } + + @Test + void freshTwoHundredReplacesCachedEntry() throws Exception { + server.enqueue(new MockResponse().setHeader("ETag", "\"v1\"").setBody("payload-1")); + server.enqueue(new MockResponse().setHeader("ETag", "\"v2\"").setBody("payload-2")); + server.enqueue(new MockResponse().setResponseCode(304)); + + Api api = api(); + String first = api.fetch("42"); + String second = api.fetch("42"); + String third = api.fetch("42"); + + assertThat(first).isEqualTo("payload-1"); + assertThat(second).isEqualTo("payload-2"); + assertThat(third).isEqualTo("payload-2"); + server.takeRequest(); + server.takeRequest(); + RecordedRequest third304 = server.takeRequest(); + assertThat(third304.getHeader("If-None-Match")).isEqualTo("\"v2\""); + } + + @Test + void responseWithoutValidatorsIsNotStored() throws Exception { + server.enqueue(new MockResponse().setBody("payload")); + + api().fetch("42"); + + assertThat(store.size()).isZero(); + } + + @Test + void postRequestsBypassCache() throws Exception { + server.enqueue(new MockResponse().setHeader("ETag", "\"v1\"").setBody("payload")); + + api().create("body"); + + assertThat(store.size()).isZero(); + RecordedRequest recorded = server.takeRequest(); + assertThat(recorded.getHeader("If-None-Match")).isNull(); + } + + @Test + void noStoreCacheControlPreventsStorage() throws Exception { + server.enqueue( + new MockResponse() + .setHeader("ETag", "\"v1\"") + .setHeader("Cache-Control", "no-store") + .setBody("payload")); + + api().fetch("42"); + + assertThat(store.size()).isZero(); + } + + @Test + void serverErrorPropagatesAndDoesNotEvictExistingEntry() throws Exception { + server.enqueue(new MockResponse().setHeader("ETag", "\"v1\"").setBody("payload-1")); + server.enqueue(new MockResponse().setResponseCode(500).setBody("nope")); + + Api api = api(); + String first = api.fetch("42"); + assertThatThrownBy(() -> api.fetch("42")).isInstanceOf(FeignException.class); + + assertThat(first).isEqualTo("payload-1"); + assertThat(store.size()).isEqualTo(1); + } + + @Test + void lastModifiedRevalidationSendsIfModifiedSince() throws Exception { + String lastModified = "Wed, 21 Oct 2020 07:28:00 GMT"; + server.enqueue(new MockResponse().setHeader("Last-Modified", lastModified).setBody("payload")); + server.enqueue(new MockResponse().setResponseCode(304)); + + Api api = api(); + api.fetch("42"); + String second = api.fetch("42"); + + assertThat(second).isEqualTo("payload"); + server.takeRequest(); + RecordedRequest revalidation = server.takeRequest(); + assertThat(revalidation.getHeader("If-Modified-Since")).isEqualTo(lastModified); + } +} diff --git a/pom.xml b/pom.xml index ba0773f5da..fc2a6a0768 100644 --- a/pom.xml +++ b/pom.xml @@ -85,6 +85,7 @@ core gson + http-cache httpclient hc5 hystrix @@ -129,6 +130,8 @@ fastjson2 form form-spring + validation + validation-jakarta vertx @@ -231,6 +234,12 @@ 2.3.9 4.0.3 2.3.1 + 2.0.1.Final + 3.0.2 + 6.2.5.Final + 8.0.1.Final + 3.0.4 + 5.0.0 1.19.4 1.1.1 1.18.46 @@ -271,6 +280,12 @@ ${project.version} + + ${project.groupId} + feign-http-cache + ${project.version} + + ${project.groupId} feign-httpclient @@ -402,6 +417,18 @@ ${project.version} + + ${project.groupId} + feign-validation + ${project.version} + + + + ${project.groupId} + feign-validation-jakarta + ${project.version} + + ${project.groupId} feign-vertx diff --git a/validation-jakarta/README.md b/validation-jakarta/README.md new file mode 100644 index 0000000000..a6fb92f201 --- /dev/null +++ b/validation-jakarta/README.md @@ -0,0 +1,37 @@ +Feign Validation (Jakarta) +========================== + +Validates the body argument and any `@Valid`-annotated parameters of a Feign-built +interface using Jakarta Bean Validation (`jakarta.validation`) **before** the HTTP +request is dispatched. Constraint violations surface as +`jakarta.validation.ConstraintViolationException`. + +Marked `@Experimental` while the underlying `feign.MethodInterceptor` API stabilises. + +For the legacy `javax.validation` namespace, use the sibling `feign-validation` module. + +```xml + + io.github.openfeign + feign-validation-jakarta + ${feign.version} + +``` + +Usage +----- + +```java +Api api = Feign.builder() + .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory()) + .target(Api.class, "https://example.com"); +``` + +You can pass an explicit `Validator` and validation groups: + +```java +Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); +Feign.builder() + .methodInterceptor(new BeanValidationMethodInterceptor(validator, Create.class)) + .target(Api.class, "https://example.com"); +``` diff --git a/validation-jakarta/pom.xml b/validation-jakarta/pom.xml new file mode 100644 index 0000000000..ee695e787f --- /dev/null +++ b/validation-jakarta/pom.xml @@ -0,0 +1,82 @@ + + + + 4.0.0 + + + io.github.openfeign + feign-parent + 13.13-SNAPSHOT + + + feign-validation-jakarta + Feign Validation Jakarta + Feign Bean Validation (jakarta.validation) + + + 17 + 17 + 17 + + + + + ${project.groupId} + feign-core + + + + ${project.groupId} + feign-core + test-jar + test + + + + jakarta.validation + jakarta.validation-api + ${jakarta.validation-api.version} + + + + + org.hibernate.validator + hibernate-validator + ${hibernate-validator-8.version} + test + + + org.glassfish.expressly + expressly + ${expressly.version} + test + + + com.squareup.okhttp3 + mockwebserver + test + + + org.junit.jupiter + junit-jupiter + test + + + + diff --git a/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java b/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java new file mode 100644 index 0000000000..cea8b11320 --- /dev/null +++ b/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java @@ -0,0 +1,96 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.validation; + +import feign.Experimental; +import feign.Invocation; +import feign.MethodInterceptor; +import feign.MethodMetadata; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Valid; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import java.lang.annotation.Annotation; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * A {@link MethodInterceptor} that validates the method's body argument and any {@link Valid} + * -annotated parameters using a {@link Validator} before the HTTP request is sent. + * + *

If any constraint violations are found a {@link ConstraintViolationException} is thrown and + * the request is never dispatched. + * + *

+ * Feign.builder()
+ *   .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory())
+ *   .target(...);
+ * 
+ */ +@Experimental +public final class BeanValidationMethodInterceptor implements MethodInterceptor { + + private final Validator validator; + private final Class[] groups; + + public BeanValidationMethodInterceptor(Validator validator, Class... groups) { + this.validator = validator; + this.groups = groups == null ? new Class[0] : groups; + } + + /** + * Builds an interceptor backed by the default {@link Validation#buildDefaultValidatorFactory}. + */ + public static BeanValidationMethodInterceptor usingDefaultFactory() { + return new BeanValidationMethodInterceptor( + Validation.buildDefaultValidatorFactory().getValidator()); + } + + @Override + public Object intercept(Invocation invocation, Chain chain) throws Throwable { + Object[] arguments = invocation.arguments(); + if (arguments != null && arguments.length > 0) { + Set> violations = new LinkedHashSet<>(); + MethodMetadata metadata = invocation.methodMetadata(); + Annotation[][] parameterAnnotations = invocation.method().getParameterAnnotations(); + Integer bodyIndex = metadata.bodyIndex(); + for (int i = 0; i < arguments.length; i++) { + Object argument = arguments[i]; + if (argument == null) { + continue; + } + boolean isBody = bodyIndex != null && bodyIndex == i; + if (isBody || hasValidAnnotation(parameterAnnotations[i])) { + violations.addAll(validator.validate(argument, groups)); + } + } + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } + } + return chain.next(invocation); + } + + private static boolean hasValidAnnotation(Annotation[] annotations) { + for (Annotation annotation : annotations) { + if (annotation.annotationType() == Valid.class) { + return true; + } + } + return false; + } +} diff --git a/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java b/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java new file mode 100644 index 0000000000..b2c977a242 --- /dev/null +++ b/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java @@ -0,0 +1,126 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.validation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import feign.Feign; +import feign.Param; +import feign.RequestLine; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class BeanValidationMethodInterceptorTest { + + private final MockWebServer server = new MockWebServer(); + + @AfterEach + void tearDown() throws Exception { + server.shutdown(); + } + + static class Payload { + @NotNull public String name; + + @NotBlank public String description; + + Payload(String name, String description) { + this.name = name; + this.description = description; + } + + @Override + public String toString() { + return "{\"name\":\"" + name + "\",\"description\":\"" + description + "\"}"; + } + } + + static class HeaderInfo { + @NotBlank public String tenant; + + HeaderInfo(String tenant) { + this.tenant = tenant; + } + } + + interface Api { + @RequestLine("POST /things") + String create(Payload body); + + @RequestLine("GET /things/{id}") + String fetch(@Param("id") String id, @Valid HeaderInfo info); + + @RequestLine("GET /things") + String list(); + } + + private Api api() { + return Feign.builder() + .encoder((object, bodyType, template) -> template.body(String.valueOf(object))) + .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory()) + .target(Api.class, "http://localhost:" + server.getPort()); + } + + @Test + void validBodyReachesServer() throws Exception { + server.enqueue(new MockResponse().setBody("ok")); + + String result = api().create(new Payload("a", "b")); + + assertThat(result).isEqualTo("ok"); + assertThat(server.getRequestCount()).isEqualTo(1); + } + + @Test + void invalidBodyThrowsBeforeRequest() { + Payload bad = new Payload(null, ""); + + assertThatThrownBy(() -> api().create(bad)) + .isInstanceOf(ConstraintViolationException.class) + .satisfies( + ex -> { + ConstraintViolationException cve = (ConstraintViolationException) ex; + assertThat(cve.getConstraintViolations()).hasSize(2); + }); + assertThat(server.getRequestCount()).isZero(); + } + + @Test + void invalidNonBodyValidParameterThrowsBeforeRequest() { + HeaderInfo bad = new HeaderInfo(""); + + assertThatThrownBy(() -> api().fetch("42", bad)) + .isInstanceOf(ConstraintViolationException.class); + assertThat(server.getRequestCount()).isZero(); + } + + @Test + void noArgsMethodPassesThrough() throws Exception { + server.enqueue(new MockResponse().setBody("ok")); + + String result = api().list(); + + assertThat(result).isEqualTo("ok"); + assertThat(server.getRequestCount()).isEqualTo(1); + } +} diff --git a/validation/README.md b/validation/README.md new file mode 100644 index 0000000000..820050e743 --- /dev/null +++ b/validation/README.md @@ -0,0 +1,46 @@ +Feign Validation +================ + +Validates the body argument and any `@Valid`-annotated parameters of a Feign-built +interface using JSR-303 / Bean Validation 2.0 (`javax.validation`) **before** the HTTP +request is dispatched. Constraint violations surface as +`javax.validation.ConstraintViolationException`. + +Marked `@Experimental` while the underlying `feign.MethodInterceptor` API stabilises. + +For the Jakarta namespace, see the sibling module `feign-validation-jakarta`. + +```xml + + io.github.openfeign + feign-validation + ${feign.version} + +``` + +Usage +----- + +```java +Api api = Feign.builder() + .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory()) + .target(Api.class, "https://example.com"); +``` + +You can pass an explicit `Validator` and validation groups: + +```java +Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); +Feign.builder() + .methodInterceptor(new BeanValidationMethodInterceptor(validator, Create.class)) + .target(Api.class, "https://example.com"); +``` + +What gets validated +------------------- + +- The method's body argument (the parameter Feign treats as `bodyIndex`) — always. +- Any other parameter annotated with `@Valid` — useful for headers, query parameters + carrying complex objects, etc. + +Null arguments are skipped. Methods with no parameters pass through. diff --git a/validation/pom.xml b/validation/pom.xml new file mode 100644 index 0000000000..adc5841f93 --- /dev/null +++ b/validation/pom.xml @@ -0,0 +1,76 @@ + + + + 4.0.0 + + + io.github.openfeign + feign-parent + 13.13-SNAPSHOT + + + feign-validation + Feign Validation + Feign Bean Validation (javax.validation) + + + + ${project.groupId} + feign-core + + + + ${project.groupId} + feign-core + test-jar + test + + + + javax.validation + validation-api + ${javax.validation-api.version} + + + + + org.hibernate.validator + hibernate-validator + ${hibernate-validator-6.version} + test + + + org.glassfish + jakarta.el + ${jakarta.el-3.version} + test + + + com.squareup.okhttp3 + mockwebserver + test + + + org.junit.jupiter + junit-jupiter + test + + + + diff --git a/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java b/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java new file mode 100644 index 0000000000..7352471135 --- /dev/null +++ b/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java @@ -0,0 +1,100 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.validation; + +import feign.Experimental; +import feign.Invocation; +import feign.MethodInterceptor; +import feign.MethodMetadata; +import java.lang.annotation.Annotation; +import java.util.LinkedHashSet; +import java.util.Set; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Valid; +import javax.validation.Validation; +import javax.validation.Validator; + +/** + * A {@link MethodInterceptor} that validates the method's body argument and any {@link Valid} + * -annotated parameters using a {@link Validator} before the HTTP request is sent. + * + *

If any constraint violations are found a {@link ConstraintViolationException} is thrown and + * the request is never dispatched. + * + *

Validation runs on the typed argument objects, before encoding. This is the right layer for + * JSR-303 / Bean Validation 2.0 because the encoder may turn the body into bytes that the validator + * cannot inspect. + * + *

+ * Feign.builder()
+ *   .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory())
+ *   .target(...);
+ * 
+ */ +@Experimental +public final class BeanValidationMethodInterceptor implements MethodInterceptor { + + private final Validator validator; + private final Class[] groups; + + public BeanValidationMethodInterceptor(Validator validator, Class... groups) { + this.validator = validator; + this.groups = groups == null ? new Class[0] : groups; + } + + /** + * Builds an interceptor backed by the default {@link Validation#buildDefaultValidatorFactory}. + */ + public static BeanValidationMethodInterceptor usingDefaultFactory() { + return new BeanValidationMethodInterceptor( + Validation.buildDefaultValidatorFactory().getValidator()); + } + + @Override + public Object intercept(Invocation invocation, Chain chain) throws Throwable { + Object[] arguments = invocation.arguments(); + if (arguments != null && arguments.length > 0) { + Set> violations = new LinkedHashSet<>(); + MethodMetadata metadata = invocation.methodMetadata(); + Annotation[][] parameterAnnotations = invocation.method().getParameterAnnotations(); + Integer bodyIndex = metadata.bodyIndex(); + for (int i = 0; i < arguments.length; i++) { + Object argument = arguments[i]; + if (argument == null) { + continue; + } + boolean isBody = bodyIndex != null && bodyIndex == i; + if (isBody || hasValidAnnotation(parameterAnnotations[i])) { + violations.addAll(validator.validate(argument, groups)); + } + } + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } + } + return chain.next(invocation); + } + + private static boolean hasValidAnnotation(Annotation[] annotations) { + for (Annotation annotation : annotations) { + if (annotation.annotationType() == Valid.class) { + return true; + } + } + return false; + } +} diff --git a/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java b/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java new file mode 100644 index 0000000000..11c19dd111 --- /dev/null +++ b/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java @@ -0,0 +1,126 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.validation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import feign.Feign; +import feign.Param; +import feign.RequestLine; +import javax.validation.ConstraintViolationException; +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class BeanValidationMethodInterceptorTest { + + private final MockWebServer server = new MockWebServer(); + + @AfterEach + void tearDown() throws Exception { + server.shutdown(); + } + + static class Payload { + @NotNull public String name; + + @NotBlank public String description; + + Payload(String name, String description) { + this.name = name; + this.description = description; + } + + @Override + public String toString() { + return "{\"name\":\"" + name + "\",\"description\":\"" + description + "\"}"; + } + } + + static class HeaderInfo { + @NotBlank public String tenant; + + HeaderInfo(String tenant) { + this.tenant = tenant; + } + } + + interface Api { + @RequestLine("POST /things") + String create(Payload body); + + @RequestLine("GET /things/{id}") + String fetch(@Param("id") String id, @Valid HeaderInfo info); + + @RequestLine("GET /things") + String list(); + } + + private Api api() { + return Feign.builder() + .encoder((object, bodyType, template) -> template.body(String.valueOf(object))) + .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory()) + .target(Api.class, "http://localhost:" + server.getPort()); + } + + @Test + void validBodyReachesServer() throws Exception { + server.enqueue(new MockResponse().setBody("ok")); + + String result = api().create(new Payload("a", "b")); + + assertThat(result).isEqualTo("ok"); + assertThat(server.getRequestCount()).isEqualTo(1); + } + + @Test + void invalidBodyThrowsBeforeRequest() { + Payload bad = new Payload(null, ""); + + assertThatThrownBy(() -> api().create(bad)) + .isInstanceOf(ConstraintViolationException.class) + .satisfies( + ex -> { + ConstraintViolationException cve = (ConstraintViolationException) ex; + assertThat(cve.getConstraintViolations()).hasSize(2); + }); + assertThat(server.getRequestCount()).isZero(); + } + + @Test + void invalidNonBodyValidParameterThrowsBeforeRequest() { + HeaderInfo bad = new HeaderInfo(""); + + assertThatThrownBy(() -> api().fetch("42", bad)) + .isInstanceOf(ConstraintViolationException.class); + assertThat(server.getRequestCount()).isZero(); + } + + @Test + void noArgsMethodPassesThrough() throws Exception { + server.enqueue(new MockResponse().setBody("ok")); + + String result = api().list(); + + assertThat(result).isEqualTo("ok"); + assertThat(server.getRequestCount()).isEqualTo(1); + } +} From 57687b076beb1c6583f6731682d8628eeeb0400b Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Thu, 7 May 2026 11:35:36 -0300 Subject: [PATCH 512/615] Move MethodInterceptor classes into feign.interceptor package Signed-off-by: Marvin Froeder --- core/src/main/java/feign/AsyncFeign.java | 1 + .../java/feign/AsynchronousMethodHandler.java | 2 ++ core/src/main/java/feign/BaseBuilder.java | 2 ++ core/src/main/java/feign/Feign.java | 1 + .../java/feign/MethodHandlerConfiguration.java | 1 + .../main/java/feign/SynchronousMethodHandler.java | 2 ++ .../java/feign/{ => interceptor}/Invocation.java | 15 ++++++++++++--- .../{ => interceptor}/MethodInterceptor.java | 10 +++++++++- .../{ => interceptor}/MethodInterceptors.java | 2 +- .../{ => interceptor}/MethodInterceptorTest.java | 8 +++++++- http-cache/README.md | 2 +- .../java/feign/cache/HttpCacheInterceptor.java | 4 ++-- validation-jakarta/README.md | 2 +- .../BeanValidationMethodInterceptor.java | 4 ++-- validation/README.md | 2 +- .../BeanValidationMethodInterceptor.java | 4 ++-- 16 files changed, 47 insertions(+), 15 deletions(-) rename core/src/main/java/feign/{ => interceptor}/Invocation.java (86%) rename core/src/main/java/feign/{ => interceptor}/MethodInterceptor.java (93%) rename core/src/main/java/feign/{ => interceptor}/MethodInterceptors.java (97%) rename core/src/test/java/feign/{ => interceptor}/MethodInterceptorTest.java (97%) diff --git a/core/src/main/java/feign/AsyncFeign.java b/core/src/main/java/feign/AsyncFeign.java index 42e835a0e3..08cfcc96c6 100644 --- a/core/src/main/java/feign/AsyncFeign.java +++ b/core/src/main/java/feign/AsyncFeign.java @@ -22,6 +22,7 @@ import feign.codec.Decoder; import feign.codec.Encoder; import feign.codec.ErrorDecoder; +import feign.interceptor.MethodInterceptor; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; diff --git a/core/src/main/java/feign/AsynchronousMethodHandler.java b/core/src/main/java/feign/AsynchronousMethodHandler.java index 5ca29124ae..ce1da9f180 100644 --- a/core/src/main/java/feign/AsynchronousMethodHandler.java +++ b/core/src/main/java/feign/AsynchronousMethodHandler.java @@ -21,6 +21,8 @@ import feign.InvocationHandlerFactory.MethodHandler; import feign.Request.Options; +import feign.interceptor.Invocation; +import feign.interceptor.MethodInterceptor; import java.io.IOException; import java.util.Collections; import java.util.List; diff --git a/core/src/main/java/feign/BaseBuilder.java b/core/src/main/java/feign/BaseBuilder.java index 09d24611cb..05608dc2ed 100644 --- a/core/src/main/java/feign/BaseBuilder.java +++ b/core/src/main/java/feign/BaseBuilder.java @@ -27,6 +27,8 @@ import feign.codec.DefaultErrorDecoder; import feign.codec.Encoder; import feign.codec.ErrorDecoder; +import feign.interceptor.MethodInterceptor; +import feign.interceptor.MethodInterceptors; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; diff --git a/core/src/main/java/feign/Feign.java b/core/src/main/java/feign/Feign.java index d7e466247d..0f00726a5d 100644 --- a/core/src/main/java/feign/Feign.java +++ b/core/src/main/java/feign/Feign.java @@ -21,6 +21,7 @@ import feign.codec.Decoder; import feign.codec.Encoder; import feign.codec.ErrorDecoder; +import feign.interceptor.MethodInterceptor; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Type; diff --git a/core/src/main/java/feign/MethodHandlerConfiguration.java b/core/src/main/java/feign/MethodHandlerConfiguration.java index cef42d3be2..6ee6ca0217 100644 --- a/core/src/main/java/feign/MethodHandlerConfiguration.java +++ b/core/src/main/java/feign/MethodHandlerConfiguration.java @@ -17,6 +17,7 @@ import static feign.Util.checkNotNull; +import feign.interceptor.MethodInterceptor; import java.util.Collections; import java.util.List; diff --git a/core/src/main/java/feign/SynchronousMethodHandler.java b/core/src/main/java/feign/SynchronousMethodHandler.java index 4576c4533b..5c5853b21f 100644 --- a/core/src/main/java/feign/SynchronousMethodHandler.java +++ b/core/src/main/java/feign/SynchronousMethodHandler.java @@ -21,6 +21,8 @@ import feign.InvocationHandlerFactory.MethodHandler; import feign.Request.Options; +import feign.interceptor.Invocation; +import feign.interceptor.MethodInterceptor; import java.io.IOException; import java.util.Collections; import java.util.List; diff --git a/core/src/main/java/feign/Invocation.java b/core/src/main/java/feign/interceptor/Invocation.java similarity index 86% rename from core/src/main/java/feign/Invocation.java rename to core/src/main/java/feign/interceptor/Invocation.java index e1a2c80a49..d9900521a4 100644 --- a/core/src/main/java/feign/Invocation.java +++ b/core/src/main/java/feign/interceptor/Invocation.java @@ -13,10 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package feign; +package feign.interceptor; import static feign.Util.checkNotNull; +import feign.Experimental; +import feign.MethodMetadata; +import feign.RequestTemplate; +import feign.Response; +import feign.Target; import java.lang.reflect.Method; /** @@ -77,8 +82,12 @@ public Response response() { return response; } - /** Package-private setter used by the framework's terminal chain step. */ - void response(Response response) { + /** + * Framework-internal setter populated by the terminal chain step after the HTTP client returns. + * Calling this from interceptor code is unsupported and may break in future versions. + */ + @Experimental + public void response(Response response) { this.response = response; } } diff --git a/core/src/main/java/feign/MethodInterceptor.java b/core/src/main/java/feign/interceptor/MethodInterceptor.java similarity index 93% rename from core/src/main/java/feign/MethodInterceptor.java rename to core/src/main/java/feign/interceptor/MethodInterceptor.java index 2a1e3ade25..5c343ad968 100644 --- a/core/src/main/java/feign/MethodInterceptor.java +++ b/core/src/main/java/feign/interceptor/MethodInterceptor.java @@ -13,7 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package feign; +package feign.interceptor; + +import feign.Contract; +import feign.Experimental; +import feign.MethodMetadata; +import feign.RequestInterceptor; +import feign.RequestTemplate; +import feign.Response; +import feign.ResponseInterceptor; /** * An around-style interceptor invoked once per method call, after the {@link Contract} has resolved diff --git a/core/src/main/java/feign/MethodInterceptors.java b/core/src/main/java/feign/interceptor/MethodInterceptors.java similarity index 97% rename from core/src/main/java/feign/MethodInterceptors.java rename to core/src/main/java/feign/interceptor/MethodInterceptors.java index 43bf5f1216..e408683163 100644 --- a/core/src/main/java/feign/MethodInterceptors.java +++ b/core/src/main/java/feign/interceptor/MethodInterceptors.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package feign; +package feign.interceptor; import java.util.ArrayList; import java.util.Collections; diff --git a/core/src/test/java/feign/MethodInterceptorTest.java b/core/src/test/java/feign/interceptor/MethodInterceptorTest.java similarity index 97% rename from core/src/test/java/feign/MethodInterceptorTest.java rename to core/src/test/java/feign/interceptor/MethodInterceptorTest.java index 9885c03841..87d47a5311 100644 --- a/core/src/test/java/feign/MethodInterceptorTest.java +++ b/core/src/test/java/feign/interceptor/MethodInterceptorTest.java @@ -13,11 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package feign; +package feign.interceptor; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import feign.Feign; +import feign.Param; +import feign.RequestInterceptor; +import feign.RequestLine; +import feign.RequestTemplate; +import feign.Response; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicReference; diff --git a/http-cache/README.md b/http-cache/README.md index 1e10baab3c..c8670f5336 100644 --- a/http-cache/README.md +++ b/http-cache/README.md @@ -6,7 +6,7 @@ A `MethodInterceptor` that performs conditional HTTP revalidation using `ETag` a its validators. Subsequent calls send `If-None-Match` / `If-Modified-Since` headers, and a `304 Not Modified` response short-circuits to the cached value. -Marked `@Experimental` while the underlying `feign.MethodInterceptor` API stabilises. +Marked `@Experimental` while the underlying `feign.interceptor.MethodInterceptor` API stabilises. ```xml diff --git a/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java b/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java index a762da072c..851b599c06 100644 --- a/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java +++ b/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java @@ -17,10 +17,10 @@ import feign.Experimental; import feign.FeignException; -import feign.Invocation; -import feign.MethodInterceptor; import feign.RequestTemplate; import feign.Response; +import feign.interceptor.Invocation; +import feign.interceptor.MethodInterceptor; import java.time.Instant; import java.util.Collection; import java.util.Map; diff --git a/validation-jakarta/README.md b/validation-jakarta/README.md index a6fb92f201..6d5c082840 100644 --- a/validation-jakarta/README.md +++ b/validation-jakarta/README.md @@ -6,7 +6,7 @@ interface using Jakarta Bean Validation (`jakarta.validation`) **before** the HT request is dispatched. Constraint violations surface as `jakarta.validation.ConstraintViolationException`. -Marked `@Experimental` while the underlying `feign.MethodInterceptor` API stabilises. +Marked `@Experimental` while the underlying `feign.interceptor.MethodInterceptor` API stabilises. For the legacy `javax.validation` namespace, use the sibling `feign-validation` module. diff --git a/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java b/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java index cea8b11320..04a1c5f9c9 100644 --- a/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java +++ b/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java @@ -16,9 +16,9 @@ package feign.validation; import feign.Experimental; -import feign.Invocation; -import feign.MethodInterceptor; import feign.MethodMetadata; +import feign.interceptor.Invocation; +import feign.interceptor.MethodInterceptor; import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; import jakarta.validation.Valid; diff --git a/validation/README.md b/validation/README.md index 820050e743..10336b204c 100644 --- a/validation/README.md +++ b/validation/README.md @@ -6,7 +6,7 @@ interface using JSR-303 / Bean Validation 2.0 (`javax.validation`) **before** th request is dispatched. Constraint violations surface as `javax.validation.ConstraintViolationException`. -Marked `@Experimental` while the underlying `feign.MethodInterceptor` API stabilises. +Marked `@Experimental` while the underlying `feign.interceptor.MethodInterceptor` API stabilises. For the Jakarta namespace, see the sibling module `feign-validation-jakarta`. diff --git a/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java b/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java index 7352471135..6b6e1fb50b 100644 --- a/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java +++ b/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java @@ -16,9 +16,9 @@ package feign.validation; import feign.Experimental; -import feign.Invocation; -import feign.MethodInterceptor; import feign.MethodMetadata; +import feign.interceptor.Invocation; +import feign.interceptor.MethodInterceptor; import java.lang.annotation.Annotation; import java.util.LinkedHashSet; import java.util.Set; From 0bad174a3f4837328304e3f7253141d0a387c956 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Thu, 7 May 2026 14:21:24 -0300 Subject: [PATCH 513/615] Convert CachedEntry to a Java record Signed-off-by: Marvin Froeder --- http-cache/pom.xml | 6 ++++ .../main/java/feign/cache/CachedEntry.java | 31 +------------------ 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/http-cache/pom.xml b/http-cache/pom.xml index 9d471c7379..0722503a98 100644 --- a/http-cache/pom.xml +++ b/http-cache/pom.xml @@ -29,6 +29,12 @@ Feign HTTP Cache Feign HTTP Cache (ETag / Last-Modified) + + 17 + 17 + 17 + + ${project.groupId} diff --git a/http-cache/src/main/java/feign/cache/CachedEntry.java b/http-cache/src/main/java/feign/cache/CachedEntry.java index 708d2c43ff..3aef66c3d4 100644 --- a/http-cache/src/main/java/feign/cache/CachedEntry.java +++ b/http-cache/src/main/java/feign/cache/CachedEntry.java @@ -20,33 +20,4 @@ /** Immutable cache record produced from a successful response with revalidation headers. */ @Experimental -public final class CachedEntry { - - private final Object value; - private final String etag; - private final String lastModified; - private final Instant storedAt; - - public CachedEntry(Object value, String etag, String lastModified, Instant storedAt) { - this.value = value; - this.etag = etag; - this.lastModified = lastModified; - this.storedAt = storedAt; - } - - public Object value() { - return value; - } - - public String etag() { - return etag; - } - - public String lastModified() { - return lastModified; - } - - public Instant storedAt() { - return storedAt; - } -} +public record CachedEntry(Object value, String etag, String lastModified, Instant storedAt) {} From 2c6c0d4805854665ce8e36914aa28d58a166018a Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Thu, 7 May 2026 14:24:43 -0300 Subject: [PATCH 514/615] Add MethodInterceptor branch to README feature overview mindmap Signed-off-by: Marvin Froeder --- src/docs/overview-mindmap.iuml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/docs/overview-mindmap.iuml b/src/docs/overview-mindmap.iuml index bd84375752..afd6aefbf3 100644 --- a/src/docs/overview-mindmap.iuml +++ b/src/docs/overview-mindmap.iuml @@ -48,6 +48,13 @@ left side *** Dropwizard Metrics 4 *** Dropwizard Metrics 5 *** Micrometer +** interceptors +*** RequestInterceptor +*** ResponseInterceptor +*** MethodInterceptor +**** Bean Validation (JSR-303) +**** Bean Validation (Jakarta) +**** HTTP Cache (ETag / Last-Modified) ** extras *** Hystrix *** SLF4J From eb0daad839a2e7df993f694c674207bd363554d8 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Thu, 7 May 2026 14:42:14 -0300 Subject: [PATCH 515/615] Add Invocation.body() and apply review cleanups (chain reduce, no-store regex, annotation cache) Signed-off-by: Marvin Froeder --- .../java/feign/AsynchronousMethodHandler.java | 36 ++-------- .../java/feign/SynchronousMethodHandler.java | 34 ++-------- .../java/feign/interceptor/Invocation.java | 12 ++++ .../feign/cache/HttpCacheInterceptor.java | 67 ++++++++++++------- .../BeanValidationMethodInterceptor.java | 53 ++++++++++----- .../BeanValidationMethodInterceptor.java | 53 ++++++++++----- 6 files changed, 133 insertions(+), 122 deletions(-) diff --git a/core/src/main/java/feign/AsynchronousMethodHandler.java b/core/src/main/java/feign/AsynchronousMethodHandler.java index ce1da9f180..4ffc663c6b 100644 --- a/core/src/main/java/feign/AsynchronousMethodHandler.java +++ b/core/src/main/java/feign/AsynchronousMethodHandler.java @@ -24,7 +24,6 @@ import feign.interceptor.Invocation; import feign.interceptor.MethodInterceptor; import java.io.IOException; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -79,11 +78,11 @@ public Object invoke(Object[] argv) throws Throwable { throw e.getCause(); } }; - MethodInterceptor.Chain chain = endOfChain; - List methodInterceptors = methodHandlerConfiguration.getMethodInterceptors(); - for (int i = methodInterceptors.size() - 1; i >= 0; i--) { - chain = methodInterceptors.get(i).apply(chain); - } + MethodInterceptor.Chain chain = + methodHandlerConfiguration.getMethodInterceptors().stream() + .reduce(MethodInterceptor::andThen) + .map(interceptor -> interceptor.apply(endOfChain)) + .orElse(endOfChain); return chain.next(invocation); } @@ -269,31 +268,6 @@ static class Factory implements MethodHandler.Factory { private final RequestTemplateFactoryResolver requestTemplateFactoryResolver; private final Options options; - Factory( - AsyncClient client, - Retryer retryer, - List requestInterceptors, - AsyncResponseHandler responseHandler, - Logger logger, - Logger.Level logLevel, - ExceptionPropagationPolicy propagationPolicy, - MethodInfoResolver methodInfoResolver, - RequestTemplateFactoryResolver requestTemplateFactoryResolver, - Options options) { - this( - client, - retryer, - requestInterceptors, - Collections.emptyList(), - responseHandler, - logger, - logLevel, - propagationPolicy, - methodInfoResolver, - requestTemplateFactoryResolver, - options); - } - Factory( AsyncClient client, Retryer retryer, diff --git a/core/src/main/java/feign/SynchronousMethodHandler.java b/core/src/main/java/feign/SynchronousMethodHandler.java index 5c5853b21f..244fe90f5d 100644 --- a/core/src/main/java/feign/SynchronousMethodHandler.java +++ b/core/src/main/java/feign/SynchronousMethodHandler.java @@ -24,7 +24,6 @@ import feign.interceptor.Invocation; import feign.interceptor.MethodInterceptor; import java.io.IOException; -import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @@ -58,11 +57,11 @@ public Object invoke(Object[] argv) throws Throwable { argv); MethodInterceptor.Chain endOfChain = inv -> runWithRetry(inv, options); - MethodInterceptor.Chain chain = endOfChain; - List methodInterceptors = methodHandlerConfiguration.getMethodInterceptors(); - for (int i = methodInterceptors.size() - 1; i >= 0; i--) { - chain = methodInterceptors.get(i).apply(chain); - } + MethodInterceptor.Chain chain = + methodHandlerConfiguration.getMethodInterceptors().stream() + .reduce(MethodInterceptor::andThen) + .map(interceptor -> interceptor.apply(endOfChain)) + .orElse(endOfChain); return chain.next(invocation); } @@ -174,29 +173,6 @@ static class Factory implements MethodHandler.Factory { private final RequestTemplateFactoryResolver requestTemplateFactoryResolver; private final Options options; - Factory( - Client client, - Retryer retryer, - List requestInterceptors, - ResponseHandler responseHandler, - Logger logger, - Logger.Level logLevel, - ExceptionPropagationPolicy propagationPolicy, - RequestTemplateFactoryResolver requestTemplateFactoryResolver, - Options options) { - this( - client, - retryer, - requestInterceptors, - Collections.emptyList(), - responseHandler, - logger, - logLevel, - propagationPolicy, - requestTemplateFactoryResolver, - options); - } - Factory( Client client, Retryer retryer, diff --git a/core/src/main/java/feign/interceptor/Invocation.java b/core/src/main/java/feign/interceptor/Invocation.java index d9900521a4..52e6e7c404 100644 --- a/core/src/main/java/feign/interceptor/Invocation.java +++ b/core/src/main/java/feign/interceptor/Invocation.java @@ -73,6 +73,18 @@ public Object[] arguments() { return arguments; } + /** + * Returns the typed argument that will be serialized as the request body, or {@code null} if the + * method has no body parameter or it was passed as {@code null}. + */ + public Object body() { + Integer bodyIndex = methodMetadata.bodyIndex(); + if (bodyIndex == null || arguments == null || bodyIndex >= arguments.length) { + return null; + } + return arguments[bodyIndex]; + } + /** * The HTTP {@link Response} captured after the framework's terminal chain step. Returns {@code * null} when the chain has not yet executed the HTTP call, or when the call failed before a diff --git a/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java b/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java index 851b599c06..f95d66d95b 100644 --- a/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java +++ b/http-cache/src/main/java/feign/cache/HttpCacheInterceptor.java @@ -19,12 +19,14 @@ import feign.FeignException; import feign.RequestTemplate; import feign.Response; +import feign.Util; import feign.interceptor.Invocation; import feign.interceptor.MethodInterceptor; import java.time.Instant; import java.util.Collection; import java.util.Map; import java.util.function.Function; +import java.util.regex.Pattern; /** * A {@link MethodInterceptor} that adds conditional revalidation headers ({@code If-None-Match} / @@ -43,6 +45,8 @@ @Experimental public final class HttpCacheInterceptor implements MethodInterceptor { + private static final Pattern NO_STORE = Pattern.compile("(?i)\\bno-store\\b"); + private final HttpCacheStore store; private final Function keyFn; private final Function cacheable; @@ -78,27 +82,10 @@ public Object intercept(Invocation invocation, Chain chain) throws Throwable { } String key = keyFn.apply(invocation); CachedEntry hit = store.get(key); - if (hit != null) { - if (hit.etag() != null) { - template.header("If-None-Match", hit.etag()); - } - if (hit.lastModified() != null) { - template.header("If-Modified-Since", hit.lastModified()); - } - } + addConditionalHeaders(template, hit); try { Object result = chain.next(invocation); - Response response = invocation.response(); - if (response != null - && response.status() >= 200 - && response.status() < 300 - && !hasNoStore(response)) { - String etag = firstHeader(response.headers(), "ETag"); - String lastMod = firstHeader(response.headers(), "Last-Modified"); - if (etag != null || lastMod != null) { - store.put(key, new CachedEntry(result, etag, lastMod, Instant.now())); - } - } + maybeStore(key, result, invocation.response()); return result; } catch (FeignException e) { if (e.status() == 304 && hit != null) { @@ -108,6 +95,38 @@ public Object intercept(Invocation invocation, Chain chain) throws Throwable { } } + private static void addConditionalHeaders(RequestTemplate template, CachedEntry hit) { + if (hit == null) { + return; + } + if (hit.etag() != null) { + template.header("If-None-Match", hit.etag()); + } + if (hit.lastModified() != null) { + template.header("If-Modified-Since", hit.lastModified()); + } + } + + private void maybeStore(String key, Object result, Response response) { + if (response == null) { + return; + } + int status = response.status(); + if (status < 200 || status >= 300) { + return; + } + Map> headers = response.headers(); + if (containsNoStore(headers)) { + return; + } + String etag = firstHeader(headers, "ETag"); + String lastMod = firstHeader(headers, "Last-Modified"); + if (etag == null && lastMod == null) { + return; + } + store.put(key, new CachedEntry(result, etag, lastMod, Instant.now())); + } + private static String defaultKey(Invocation invocation) { RequestTemplate template = invocation.requestTemplate(); return invocation.methodMetadata().configKey() + "|" + template.method() + " " + template.url(); @@ -118,13 +137,9 @@ private static Boolean defaultCacheable(RequestTemplate template) { return "GET".equalsIgnoreCase(method) || "HEAD".equalsIgnoreCase(method); } - private static boolean hasNoStore(Response response) { - Collection values = response.headers().get("Cache-Control"); - if (values == null) { - return false; - } - for (String value : values) { - if (value != null && value.toLowerCase().contains("no-store")) { + private static boolean containsNoStore(Map> headers) { + for (String value : Util.valuesOrEmpty(headers, "Cache-Control")) { + if (value != null && NO_STORE.matcher(value).find()) { return true; } } diff --git a/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java b/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java index 04a1c5f9c9..f8396dc39b 100644 --- a/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java +++ b/validation-jakarta/src/main/java/feign/validation/BeanValidationMethodInterceptor.java @@ -16,7 +16,6 @@ package feign.validation; import feign.Experimental; -import feign.MethodMetadata; import feign.interceptor.Invocation; import feign.interceptor.MethodInterceptor; import jakarta.validation.ConstraintViolation; @@ -25,8 +24,12 @@ import jakarta.validation.Validation; import jakarta.validation.Validator; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** * A {@link MethodInterceptor} that validates the method's body argument and any {@link Valid} @@ -46,6 +49,8 @@ public final class BeanValidationMethodInterceptor implements MethodInterceptor private final Validator validator; private final Class[] groups; + private final ConcurrentMap parameterAnnotationsCache = + new ConcurrentHashMap<>(); public BeanValidationMethodInterceptor(Validator validator, Class... groups) { this.validator = validator; @@ -62,27 +67,39 @@ public static BeanValidationMethodInterceptor usingDefaultFactory() { @Override public Object intercept(Invocation invocation, Chain chain) throws Throwable { + Set> violations = collectViolations(invocation); + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } + return chain.next(invocation); + } + + private Set> collectViolations(Invocation invocation) { Object[] arguments = invocation.arguments(); - if (arguments != null && arguments.length > 0) { - Set> violations = new LinkedHashSet<>(); - MethodMetadata metadata = invocation.methodMetadata(); - Annotation[][] parameterAnnotations = invocation.method().getParameterAnnotations(); - Integer bodyIndex = metadata.bodyIndex(); - for (int i = 0; i < arguments.length; i++) { - Object argument = arguments[i]; - if (argument == null) { - continue; - } - boolean isBody = bodyIndex != null && bodyIndex == i; - if (isBody || hasValidAnnotation(parameterAnnotations[i])) { - violations.addAll(validator.validate(argument, groups)); - } + if (arguments == null || arguments.length == 0) { + return Collections.emptySet(); + } + Set> violations = new LinkedHashSet<>(); + Object body = invocation.body(); + if (body != null) { + violations.addAll(validator.validate(body, groups)); + } + Integer bodyIndex = invocation.methodMetadata().bodyIndex(); + Annotation[][] parameterAnnotations = + parameterAnnotationsCache.computeIfAbsent( + invocation.method(), Method::getParameterAnnotations); + for (int i = 0; i < arguments.length; i++) { + if (arguments[i] == null) { + continue; } - if (!violations.isEmpty()) { - throw new ConstraintViolationException(violations); + if (bodyIndex != null && bodyIndex == i) { + continue; + } + if (hasValidAnnotation(parameterAnnotations[i])) { + violations.addAll(validator.validate(arguments[i], groups)); } } - return chain.next(invocation); + return violations; } private static boolean hasValidAnnotation(Annotation[] annotations) { diff --git a/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java b/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java index 6b6e1fb50b..fcb83693a1 100644 --- a/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java +++ b/validation/src/main/java/feign/validation/BeanValidationMethodInterceptor.java @@ -16,12 +16,15 @@ package feign.validation; import feign.Experimental; -import feign.MethodMetadata; import feign.interceptor.Invocation; import feign.interceptor.MethodInterceptor; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.validation.Valid; @@ -50,6 +53,8 @@ public final class BeanValidationMethodInterceptor implements MethodInterceptor private final Validator validator; private final Class[] groups; + private final ConcurrentMap parameterAnnotationsCache = + new ConcurrentHashMap<>(); public BeanValidationMethodInterceptor(Validator validator, Class... groups) { this.validator = validator; @@ -66,27 +71,39 @@ public static BeanValidationMethodInterceptor usingDefaultFactory() { @Override public Object intercept(Invocation invocation, Chain chain) throws Throwable { + Set> violations = collectViolations(invocation); + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } + return chain.next(invocation); + } + + private Set> collectViolations(Invocation invocation) { Object[] arguments = invocation.arguments(); - if (arguments != null && arguments.length > 0) { - Set> violations = new LinkedHashSet<>(); - MethodMetadata metadata = invocation.methodMetadata(); - Annotation[][] parameterAnnotations = invocation.method().getParameterAnnotations(); - Integer bodyIndex = metadata.bodyIndex(); - for (int i = 0; i < arguments.length; i++) { - Object argument = arguments[i]; - if (argument == null) { - continue; - } - boolean isBody = bodyIndex != null && bodyIndex == i; - if (isBody || hasValidAnnotation(parameterAnnotations[i])) { - violations.addAll(validator.validate(argument, groups)); - } + if (arguments == null || arguments.length == 0) { + return Collections.emptySet(); + } + Set> violations = new LinkedHashSet<>(); + Object body = invocation.body(); + if (body != null) { + violations.addAll(validator.validate(body, groups)); + } + Integer bodyIndex = invocation.methodMetadata().bodyIndex(); + Annotation[][] parameterAnnotations = + parameterAnnotationsCache.computeIfAbsent( + invocation.method(), Method::getParameterAnnotations); + for (int i = 0; i < arguments.length; i++) { + if (arguments[i] == null) { + continue; } - if (!violations.isEmpty()) { - throw new ConstraintViolationException(violations); + if (bodyIndex != null && bodyIndex == i) { + continue; + } + if (hasValidAnnotation(parameterAnnotations[i])) { + violations.addAll(validator.validate(arguments[i], groups)); } } - return chain.next(invocation); + return violations; } private static boolean hasValidAnnotation(Annotation[] annotations) { From 21237c59e7a8765a7c8752bba78858b8a1c27301 Mon Sep 17 00:00:00 2001 From: CharmingKyu <45731301+loadkrnis@users.noreply.github.com> Date: Fri, 8 May 2026 03:04:01 +0900 Subject: [PATCH 516/615] Fix Slf4jLogger and JavaLogger returning unbuffered response when logging disabled (#3172) When SLF4J/java.util.logging level is above DEBUG/FINE, logAndRebufferResponse() was returning the original response without rebuffering. This caused: 1. ErrorDecoder failing to read response body from error responses 2. Inconsistent behavior where response.body() returns different types (byte[] vs InputStream) based solely on logging configuration Now always delegates to super.logAndRebufferResponse() to ensure consistent rebuffering based on Feign's Logger.Level, while logging output is still controlled by the underlying logger's level check in log() method. - Remove conditional in Slf4jLogger.logAndRebufferResponse() - Remove conditional in JavaLogger.logAndRebufferResponse() - Add unit tests for rebuffering at various logging levels Fixes #1336 --- core/src/main/java/feign/Logger.java | 5 +- core/src/test/java/feign/JavaLoggerTest.java | 117 ++++++++++ .../test/java/feign/LoggerRebufferTest.java | 207 ++++++++++++++++++ .../main/java/feign/slf4j/Slf4jLogger.java | 5 +- .../java/feign/slf4j/Slf4jLoggerTest.java | 82 +++++++ 5 files changed, 408 insertions(+), 8 deletions(-) create mode 100644 core/src/test/java/feign/JavaLoggerTest.java create mode 100644 core/src/test/java/feign/LoggerRebufferTest.java diff --git a/core/src/main/java/feign/Logger.java b/core/src/main/java/feign/Logger.java index 4dcb5f0d48..a460251a6a 100644 --- a/core/src/main/java/feign/Logger.java +++ b/core/src/main/java/feign/Logger.java @@ -230,10 +230,7 @@ protected void logRequest(String configKey, Level logLevel, Request request) { @Override protected Response logAndRebufferResponse( String configKey, Level logLevel, Response response, long elapsedTime) throws IOException { - if (logger.isLoggable(java.util.logging.Level.FINE)) { - return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime); - } - return response; + return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime); } @Override diff --git a/core/src/test/java/feign/JavaLoggerTest.java b/core/src/test/java/feign/JavaLoggerTest.java new file mode 100644 index 0000000000..f05d839e15 --- /dev/null +++ b/core/src/test/java/feign/JavaLoggerTest.java @@ -0,0 +1,117 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import feign.Logger.JavaLogger; +import feign.Request.HttpMethod; +import java.util.Collection; +import java.util.Collections; +import java.util.logging.Level; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class JavaLoggerTest { + + private static final String CONFIG_KEY = "TestApi#testMethod()"; + private java.util.logging.Logger julLogger; + private JavaLogger logger; + + @BeforeEach + void setUp() { + julLogger = java.util.logging.Logger.getLogger(JavaLoggerTest.class.getName()); + logger = new JavaLogger(JavaLoggerTest.class); + } + + @Test + void rebuffersResponseBodyWhenJulLevelIsInfo() throws Exception { + // given + julLogger.setLevel(Level.INFO); + Response responseWithBody = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body("{\"error\":\"test\"}", Util.UTF_8) + .build(); + + // when + Response result = + logger.logAndRebufferResponse( + CONFIG_KEY, feign.Logger.Level.HEADERS, responseWithBody, 273); + + // then + String body1 = Util.toString(result.body().asReader(Util.UTF_8)); + String body2 = Util.toString(result.body().asReader(Util.UTF_8)); + assert body1.equals("{\"error\":\"test\"}") : "First read should return body content"; + assert body2.equals("{\"error\":\"test\"}") : "Second read should return same body content"; + } + + @Test + void rebuffersResponseBodyWhenJulLevelIsWarning() throws Exception { + // given + julLogger.setLevel(Level.WARNING); + Response responseWithBody = + Response.builder() + .status(500) + .reason("Internal Server Error") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body("{\"message\":\"error details\"}", Util.UTF_8) + .build(); + + // when + Response result = + logger.logAndRebufferResponse(CONFIG_KEY, feign.Logger.Level.FULL, responseWithBody, 100); + + // then + byte[] bodyBytes = Util.toByteArray(result.body().asInputStream()); + assert new String(bodyBytes, Util.UTF_8).equals("{\"message\":\"error details\"}") + : "Body should be readable after rebuffering"; + } + + @Test + void responseBodyReadableMultipleTimesForErrorDecoder() throws Exception { + // given + julLogger.setLevel(Level.SEVERE); + String originalBody = "{\"errorCode\":\"E001\",\"message\":\"Validation failed\"}"; + Response responseWithBody = + Response.builder() + .status(400) + .reason("Bad Request") + .request( + Request.create( + HttpMethod.POST, "/api/submit", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body(originalBody, Util.UTF_8) + .build(); + + // when + Response result = + logger.logAndRebufferResponse( + CONFIG_KEY, feign.Logger.Level.HEADERS, responseWithBody, 150); + + // then + String read1 = Util.toString(result.body().asReader(Util.UTF_8)); + String read2 = Util.toString(result.body().asReader(Util.UTF_8)); + String read3 = Util.toString(result.body().asReader(Util.UTF_8)); + assert read1.equals(originalBody) : "First read should match original body"; + assert read2.equals(originalBody) : "Second read should match original body"; + assert read3.equals(originalBody) : "Third read should match original body"; + } +} diff --git a/core/src/test/java/feign/LoggerRebufferTest.java b/core/src/test/java/feign/LoggerRebufferTest.java new file mode 100644 index 0000000000..5928a8f255 --- /dev/null +++ b/core/src/test/java/feign/LoggerRebufferTest.java @@ -0,0 +1,207 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import feign.Request.HttpMethod; +import java.util.Collection; +import java.util.Collections; +import org.junit.jupiter.api.Test; + +public class LoggerRebufferTest { + + private static final String CONFIG_KEY = "TestApi#testMethod()"; + + private static class TestLogger extends Logger { + @Override + protected void log(String configKey, String format, Object... args) {} + } + + @Test + void headersLevelRebuffersResponseBody() throws Exception { + // given + TestLogger logger = new TestLogger(); + String originalBody = "{\"status\":\"error\",\"message\":\"Not found\"}"; + Response response = + Response.builder() + .status(404) + .reason("Not Found") + .request( + Request.create( + HttpMethod.GET, "/api/resource", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body(originalBody, Util.UTF_8) + .build(); + + // when + Response result = + logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.HEADERS, response, 100); + + // then + String read1 = Util.toString(result.body().asReader(Util.UTF_8)); + String read2 = Util.toString(result.body().asReader(Util.UTF_8)); + assertEquals(originalBody, read1, "First read should return original body"); + assertEquals(originalBody, read2, "Second read should return same body (rebuffered)"); + } + + @Test + void basicLevelDoesNotRebufferResponseBody() throws Exception { + // given + TestLogger logger = new TestLogger(); + String originalBody = "{\"status\":\"ok\"}"; + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create( + HttpMethod.GET, "/api/resource", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body(originalBody, Util.UTF_8) + .build(); + + // when + Response result = logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.BASIC, response, 100); + + // then + String read1 = Util.toString(result.body().asReader(Util.UTF_8)); + assertEquals(originalBody, read1, "First read should return original body"); + } + + @Test + void fullLevelRebuffersResponseBody() throws Exception { + // given + TestLogger logger = new TestLogger(); + String originalBody = "{\"data\":{\"id\":123,\"name\":\"test\"}}"; + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create( + HttpMethod.POST, "/api/create", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body(originalBody, Util.UTF_8) + .build(); + + // when + Response result = logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.FULL, response, 50); + + // then + String read1 = Util.toString(result.body().asReader(Util.UTF_8)); + String read2 = Util.toString(result.body().asReader(Util.UTF_8)); + String read3 = Util.toString(result.body().asReader(Util.UTF_8)); + assertEquals(originalBody, read1, "First read should return original body"); + assertEquals(originalBody, read2, "Second read should return same body"); + assertEquals(originalBody, read3, "Third read should return same body"); + } + + @Test + void noneLevelDoesNotRebufferResponseBody() throws Exception { + // given + TestLogger logger = new TestLogger(); + String originalBody = "{\"result\":\"success\"}"; + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create( + HttpMethod.GET, "/api/status", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body(originalBody, Util.UTF_8) + .build(); + + // When + Response result = logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.NONE, response, 100); + + // then + String read1 = Util.toString(result.body().asReader(Util.UTF_8)); + assertEquals(originalBody, read1, "Body should be readable"); + } + + @Test + void http204DoesNotRebufferEvenAtHeadersLevel() throws Exception { + // given + TestLogger logger = new TestLogger(); + Response response = + Response.builder() + .status(204) + .reason("No Content") + .request( + Request.create( + HttpMethod.DELETE, "/api/resource/1", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body("should be ignored", Util.UTF_8) + .build(); + + // when + Response result = + logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.HEADERS, response, 100); + + // then + assertNotNull(result.body(), "Response body object should exist"); + } + + @Test + void http205DoesNotRebufferEvenAtHeadersLevel() throws Exception { + // given + TestLogger logger = new TestLogger(); + Response response = + Response.builder() + .status(205) + .reason("Reset Content") + .request( + Request.create( + HttpMethod.POST, "/api/form", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body("should be ignored", Util.UTF_8) + .build(); + + // when + Response result = + logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.HEADERS, response, 100); + + // then + assertNotNull(result.body(), "Response body object should exist"); + } + + @Test + void nullBodyHandledCorrectlyAtHeadersLevel() throws Exception { + // given + TestLogger logger = new TestLogger(); + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create( + HttpMethod.HEAD, "/api/resource", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body((byte[]) null) + .build(); + + // when + Response result = + logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.HEADERS, response, 100); + + // then + assertNull(result.body(), "Body should remain null"); + } +} diff --git a/slf4j/src/main/java/feign/slf4j/Slf4jLogger.java b/slf4j/src/main/java/feign/slf4j/Slf4jLogger.java index c90c551283..fb14971e96 100644 --- a/slf4j/src/main/java/feign/slf4j/Slf4jLogger.java +++ b/slf4j/src/main/java/feign/slf4j/Slf4jLogger.java @@ -56,10 +56,7 @@ protected void logRequest(String configKey, Level logLevel, Request request) { @Override protected Response logAndRebufferResponse( String configKey, Level logLevel, Response response, long elapsedTime) throws IOException { - if (logger.isDebugEnabled()) { - return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime); - } - return response; + return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime); } @Override diff --git a/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java b/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java index 0a1f235ef9..c4eaf5bfd5 100644 --- a/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java +++ b/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java @@ -115,4 +115,86 @@ void logRequestsAndResponses() throws Exception { logger.logRequest(CONFIG_KEY, Logger.Level.BASIC, REQUEST); logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.BASIC, RESPONSE, 273); } + + @Test + void rebuffersResponseBodyWhenLogLevelIsInfo() throws Exception { + // given + slf4j.logLevel("info"); + + Response responseWithBody = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body("{\"error\":\"test\"}", Util.UTF_8) + .build(); + logger = new Slf4jLogger(); + + // when + Response result = + logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.HEADERS, responseWithBody, 273); + + // then + String body1 = Util.toString(result.body().asReader(Util.UTF_8)); + String body2 = Util.toString(result.body().asReader(Util.UTF_8)); + assert body1.equals("{\"error\":\"test\"}") : "First read should return body content"; + assert body2.equals("{\"error\":\"test\"}") : "Second read should return same body content"; + } + + @Test + void rebuffersResponseBodyWhenLogLevelIsFull() throws Exception { + // given + slf4j.logLevel("info"); + Response responseWithBody = + Response.builder() + .status(500) + .reason("Internal Server Error") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body("{\"message\":\"error details\"}", Util.UTF_8) + .build(); + logger = new Slf4jLogger(); + + // when + Response result = + logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.FULL, responseWithBody, 100); + + // then + byte[] bodyBytes = Util.toByteArray(result.body().asInputStream()); + assert new String(bodyBytes, Util.UTF_8).equals("{\"message\":\"error details\"}") + : "Body should be readable after rebuffering"; + } + + @Test + void responseBodyReadableMultipleTimes() throws Exception { + // given + slf4j.logLevel("info"); + String originalBody = "{\"data\":\"important information\",\"count\":42}"; + Response responseWithBody = + Response.builder() + .status(400) + .reason("Bad Request") + .request( + Request.create( + HttpMethod.POST, "/api/submit", Collections.emptyMap(), null, Util.UTF_8)) + .headers(Collections.>emptyMap()) + .body(originalBody, Util.UTF_8) + .build(); + logger = new Slf4jLogger(); + + // when + Response result = + logger.logAndRebufferResponse(CONFIG_KEY, Logger.Level.HEADERS, responseWithBody, 150); + + // then + String read1 = Util.toString(result.body().asReader(Util.UTF_8)); + String read2 = Util.toString(result.body().asReader(Util.UTF_8)); + String read3 = Util.toString(result.body().asReader(Util.UTF_8)); + assert read1.equals(originalBody) : "First read should match original body"; + assert read2.equals(originalBody) : "Second read should match original body"; + assert read3.equals(originalBody) : "Third read should match original body"; + } } From 16a49d136c4231c8e92f7222b277b665372fe270 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 05:22:59 +0000 Subject: [PATCH 517/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.34.0 to 3.34.1. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.34.0...v3.34.1) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.34.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fc2a6a0768..06a827351a 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ 4.0.0 6.39.0 3.35.2 - 3.34.0 + 3.34.1 0.25.6 1.0 From 65046511347349126a0390cc823e4d529496921c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 05:23:40 +0000 Subject: [PATCH 518/615] build(deps-dev): Bump org.glassfish.expressly:expressly Bumps [org.glassfish.expressly:expressly](https://github.com/eclipse-ee4j/expressly) from 5.0.0 to 6.0.0. - [Release notes](https://github.com/eclipse-ee4j/expressly/releases) - [Commits](https://github.com/eclipse-ee4j/expressly/compare/5.0.0-RELEASE...6.0.0-RELEASE) --- updated-dependencies: - dependency-name: org.glassfish.expressly:expressly dependency-version: 6.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fc2a6a0768..68dd296073 100644 --- a/pom.xml +++ b/pom.xml @@ -239,7 +239,7 @@ 6.2.5.Final 8.0.1.Final 3.0.4 - 5.0.0 + 6.0.0 1.19.4 1.1.1 1.18.46 From 9e4d8d308a61e45ef4e3264b0ffbc868d3bf5dc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 05:24:25 +0000 Subject: [PATCH 519/615] build(deps): Bump jakarta.validation:jakarta.validation-api Bumps [jakarta.validation:jakarta.validation-api](https://github.com/jakartaee/validation) from 3.0.2 to 3.1.1. - [Release notes](https://github.com/jakartaee/validation/releases) - [Commits](https://github.com/jakartaee/validation/compare/3.0.2...3.1.1) --- updated-dependencies: - dependency-name: jakarta.validation:jakarta.validation-api dependency-version: 3.1.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fc2a6a0768..4de9e0b80b 100644 --- a/pom.xml +++ b/pom.xml @@ -235,7 +235,7 @@ 4.0.3 2.3.1 2.0.1.Final - 3.0.2 + 3.1.1 6.2.5.Final 8.0.1.Final 3.0.4 From 88af974eece6a83a9b6f8c8d5412239c2373d075 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 05:35:00 +0000 Subject: [PATCH 520/615] build(deps-dev): Bump com.github.siom79.japicmp:japicmp-maven-plugin Bumps [com.github.siom79.japicmp:japicmp-maven-plugin](https://github.com/siom79/japicmp) from 0.25.6 to 0.25.7. - [Release notes](https://github.com/siom79/japicmp/releases) - [Changelog](https://github.com/siom79/japicmp/blob/master/release.py) - [Commits](https://github.com/siom79/japicmp/compare/japicmp-base-0.25.6...japicmp-base-0.25.7) --- updated-dependencies: - dependency-name: com.github.siom79.japicmp:japicmp-maven-plugin dependency-version: 0.25.7 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 564df435d9..c6dd719a1a 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ 6.39.0 3.35.2 3.34.1 - 0.25.6 + 0.25.7 1.0 From 961273407733542774e7a6a569ec2836415c4cc2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 05:35:18 +0000 Subject: [PATCH 521/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.35.2 to 3.35.3. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.35.2...v3.35.3) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.35.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 564df435d9..872297b6c2 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,7 @@ 1.2.8 4.0.0 6.39.0 - 3.35.2 + 3.35.3 3.34.1 0.25.6 1.0 From 987e3e0c7e2d686a3e87ff5807c97a78a0cbf75d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 06:00:10 +0000 Subject: [PATCH 522/615] build(deps): Bump kotlinx.coroutines.version from 1.10.2 to 1.11.0 Bumps `kotlinx.coroutines.version` from 1.10.2 to 1.11.0. Updates `org.jetbrains.kotlinx:kotlinx-coroutines-jdk8` from 1.10.2 to 1.11.0 - [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases) - [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md) - [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.10.2...1.11.0) Updates `org.jetbrains.kotlinx:kotlinx-coroutines-reactor` from 1.10.2 to 1.11.0 - [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases) - [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md) - [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.10.2...1.11.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-jdk8 dependency-version: 1.11.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-reactor dependency-version: 1.11.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 6e41b75061..34a6e57d7b 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -31,7 +31,7 @@ 2.3.21 - 1.10.2 + 1.11.0 From 1133afd7f3634c850123a11b594f96e4f3a095b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 06:01:17 +0000 Subject: [PATCH 523/615] build(deps): Bump org.slf4j:slf4j-log4j12 from 2.0.16 to 2.0.17 Bumps org.slf4j:slf4j-log4j12 from 2.0.16 to 2.0.17. --- updated-dependencies: - dependency-name: org.slf4j:slf4j-log4j12 dependency-version: 2.0.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/pom.xml b/vertx/pom.xml index 91cc96416e..34c0ad2636 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -36,7 +36,7 @@ 5.0.4 - 2.0.16 + 2.0.17 3.0.1 From 3361d983b4f14b86698b46bfed6836e86433d635 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 05:22:13 +0000 Subject: [PATCH 524/615] build(deps): Bump slf4j.version from 2.0.17 to 2.0.18 Bumps `slf4j.version` from 2.0.17 to 2.0.18. Updates `org.slf4j:slf4j-simple` from 2.0.17 to 2.0.18 Updates `org.slf4j:slf4j-nop` from 2.0.17 to 2.0.18 Updates `org.slf4j:slf4j-api` from 2.0.17 to 2.0.18 Updates `org.slf4j:slf4j-jdk14` from 2.0.17 to 2.0.18 --- updated-dependencies: - dependency-name: org.slf4j:slf4j-simple dependency-version: 2.0.18 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: org.slf4j:slf4j-nop dependency-version: 2.0.18 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.slf4j:slf4j-api dependency-version: 2.0.18 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: org.slf4j:slf4j-jdk14 dependency-version: 2.0.18 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 85bc1b7244..8c1dd9b27f 100644 --- a/pom.xml +++ b/pom.xml @@ -168,7 +168,7 @@ 2.1.0 2.14.0 1.15.2 - 2.0.17 + 2.0.18 20251224 4.0.6 From 12177c10af3e9dcf761b7c6161372b096b232c7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 05:23:12 +0000 Subject: [PATCH 525/615] build(deps): Bump org.slf4j:slf4j-log4j12 from 2.0.17 to 2.0.18 Bumps org.slf4j:slf4j-log4j12 from 2.0.17 to 2.0.18. --- updated-dependencies: - dependency-name: org.slf4j:slf4j-log4j12 dependency-version: 2.0.18 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/pom.xml b/vertx/pom.xml index 34c0ad2636..185047b3f1 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -36,7 +36,7 @@ 5.0.4 - 2.0.17 + 2.0.18 3.0.1 From cef5e55b6256f7d07336d74b65ff3753650ed544 Mon Sep 17 00:00:00 2001 From: Rishabh Srivastava Date: Wed, 13 May 2026 15:38:56 +0000 Subject: [PATCH 526/615] do not unwrap checked and undeclared exceptions --- .../java/feign/SynchronousMethodHandler.java | 18 ++++++++- core/src/test/java/feign/FeignTest.java | 37 +++++++++++++++++++ .../feign/httpclient/ApacheHttpClient.java | 8 +++- .../httpclient/ApacheHttpClientTest.java | 17 +++++++++ 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/feign/SynchronousMethodHandler.java b/core/src/main/java/feign/SynchronousMethodHandler.java index 244fe90f5d..6680fc5aa3 100644 --- a/core/src/main/java/feign/SynchronousMethodHandler.java +++ b/core/src/main/java/feign/SynchronousMethodHandler.java @@ -24,6 +24,7 @@ import feign.interceptor.Invocation; import feign.interceptor.MethodInterceptor; import java.io.IOException; +import java.lang.reflect.Method; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @@ -75,7 +76,12 @@ private Object runWithRetry(Invocation invocation, Options options) throws Throw retryer.continueOrPropagate(e); } catch (RetryableException th) { Throwable cause = th.getCause(); - if (methodHandlerConfiguration.getPropagationPolicy() == UNWRAP && cause != null) { + if (methodHandlerConfiguration.getPropagationPolicy() == UNWRAP + && cause != null + && (cause instanceof RuntimeException + || cause instanceof Error + || isDeclaredCheckedException( + cause, methodHandlerConfiguration.getMetadata().method()))) { throw cause; } else { throw th; @@ -160,6 +166,16 @@ Options findOptions(Object[] argv) { .getMethodOptions(methodHandlerConfiguration.getMetadata().method().getName())); } + private static boolean isDeclaredCheckedException(Throwable cause, Method method) { + Class[] exceptionTypes = method.getExceptionTypes(); + for (Class exType : exceptionTypes) { + if (exType.isAssignableFrom(cause.getClass())) { + return true; + } + } + return false; + } + static class Factory implements MethodHandler.Factory { private final Client client; diff --git a/core/src/test/java/feign/FeignTest.java b/core/src/test/java/feign/FeignTest.java index 748bfe1ad5..f30c069f50 100755 --- a/core/src/test/java/feign/FeignTest.java +++ b/core/src/test/java/feign/FeignTest.java @@ -50,6 +50,7 @@ import feign.querymap.FieldQueryMapEncoder; import java.io.IOException; import java.lang.reflect.Type; +import java.net.ProtocolException; import java.net.URI; import java.time.Clock; import java.time.Instant; @@ -708,6 +709,39 @@ void throwsRetryableExceptionIfNoUnderlyingCause() throws Exception { assertThat(exception.getMessage()).contains(message); } + @Test + void doesNotUnwrapUndeclaredCheckedCauseWhenPropagationPolicyIsUnwrap() { + TestInterface api = + Feign.builder() + .exceptionPropagationPolicy(UNWRAP) + .retryer(new DefaultRetryer(1, 1, 1)) + .client( + (_, _) -> { + throw new ProtocolException("missing Location header for redirect"); + }) + .target(TestInterface.class, "http://localhost:" + server.getPort()); + + RetryableException exception = assertThrows(RetryableException.class, () -> api.post()); + assertThat(exception.getMessage()).contains("missing Location header for redirect"); + } + + @Test + void unwrapDeclaredCheckedCauseWhenPropagationPolicyIsUnwrap() { + TestInterface api = + Feign.builder() + .exceptionPropagationPolicy(UNWRAP) + .retryer(new DefaultRetryer(1, 1, 1)) + .client( + (_, _) -> { + throw new ProtocolException("missing Location header for redirect"); + }) + .target(TestInterface.class, "http://localhost:" + server.getPort()); + + ProtocolException exception = + assertThrows(ProtocolException.class, () -> api.postThrowsProtocolException()); + assertThat(exception.getMessage()).contains("missing Location header for redirect"); + } + @Test void whenReturnTypeIsResponseNoErrorHandling() { Map> headers = new LinkedHashMap<>(); @@ -1234,6 +1268,9 @@ interface TestInterface { @RequestLine("POST /") String post() throws TestInterfaceException; + @RequestLine("POST /") + String postThrowsProtocolException() throws ProtocolException; + @RequestLine("POST /") @Body( "%7B\"customer_name\": \"{customer_name}\", \"user_name\": \"{user_name}\", \"password\":" diff --git a/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java b/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java index 010c229cb7..5ab2ba459e 100644 --- a/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java +++ b/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java @@ -81,8 +81,12 @@ public Response execute(Request request, Request.Options options) throws IOExcep } catch (URISyntaxException e) { throw new IOException("URL '" + request.url() + "' couldn't be parsed into a URI", e); } - HttpResponse httpResponse = client.execute(httpUriRequest); - return toFeignResponse(httpResponse, request); + try { + HttpResponse httpResponse = client.execute(httpUriRequest); + return toFeignResponse(httpResponse, request); + } catch (Exception e) { + throw new IOException(e); + } } HttpUriRequest toHttpUriRequest(Request request, Request.Options options) diff --git a/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java b/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java index 3506aae5be..9ad3406f74 100644 --- a/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java +++ b/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java @@ -23,6 +23,8 @@ import feign.Feign.Builder; import feign.FeignException; import feign.Request.Options; +import feign.RetryableException; +import feign.Retryer; import feign.client.AbstractClientTest; import feign.jaxrs.JAXRSContract; import java.nio.charset.StandardCharsets; @@ -89,6 +91,21 @@ void notFollowRedirectIsRespected() throws InterruptedException { assertThat(server.takeRequest().getPath()).isEqualTo("/withOptions"); } + @Test + void redirectWithoutLocationHeader() { + JaxRsTestInterface api = + Feign.builder() + .contract(new JAXRSContract()) + .retryer(Retryer.NEVER_RETRY) + .client(new ApacheHttpClient(HttpClientBuilder.create().build())) + .target(JaxRsTestInterface.class, "http://localhost:" + server.getPort()); + + server.enqueue(new MockResponse().setResponseCode(303)); + RetryableException exception = + assertThrows(RetryableException.class, () -> api.withoutBody("foo")); + assertThat(exception.getMessage()).contains("org.apache.http.client.ClientProtocolException"); + } + private JaxRsTestInterface buildTestInterface() { return Feign.builder() .contract(new JAXRSContract()) From 7f6e105fa70ece1724a400e2c760b06acd845edd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 17:54:13 +0000 Subject: [PATCH 527/615] build(deps): Bump org.apache.maven.plugins:maven-enforcer-plugin Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.6.2 to 3.6.3. - [Release notes](https://github.com/apache/maven-enforcer/releases) - [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.6.2...enforcer-3.6.3) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-enforcer-plugin dependency-version: 3.6.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8c1dd9b27f..ecb5894b73 100644 --- a/pom.xml +++ b/pom.xml @@ -200,7 +200,7 @@ 3.1.4 1.2.2 1.3.0.Final - 3.6.2 + 3.6.3 3.2.0 1.2.8 4.0.0 From 6bbb5b518347d5d8c2c0e451357da477ef3cf71c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 17:54:35 +0000 Subject: [PATCH 528/615] build(deps-dev): Bump io.undertow:undertow-core Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.4.0.Final to 2.4.1.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.4.0.Final...2.4.1.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-version: 2.4.1.Final dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8c1dd9b27f..1f91f70cdb 100644 --- a/pom.xml +++ b/pom.xml @@ -254,7 +254,7 @@ 5.0.1 7.0.7 7.0.7 - 2.4.0.Final + 2.4.1.Final 1.18.0 From 2085f384aa929c8fe8b61bf9afd7ae4ed1423b07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 May 2026 10:03:29 +0000 Subject: [PATCH 529/615] build(deps): Bump org.junit:junit-bom from 6.0.3 to 6.1.0 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 6.0.3 to 6.1.0. - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r6.0.3...r6.1.0) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3194946589..c48b625dfc 100644 --- a/pom.xml +++ b/pom.xml @@ -172,7 +172,7 @@ 20251224 4.0.6 - 6.0.3 + 6.1.0 2.21.3 3.1.3 3.27.7 From d3bcf6114218cde46828a92b4486b9ba2e210e2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 05:24:54 +0000 Subject: [PATCH 530/615] build(deps): Bump netty.version from 4.2.13.Final to 4.2.14.Final Bumps `netty.version` from 4.2.13.Final to 4.2.14.Final. Updates `io.netty:netty-bom` from 4.2.13.Final to 4.2.14.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.13.Final...netty-4.2.14.Final) Updates `io.netty:netty-handler` from 4.2.13.Final to 4.2.14.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.13.Final...netty-4.2.14.Final) Updates `io.netty:netty-codec-http` from 4.2.13.Final to 4.2.14.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.13.Final...netty-4.2.14.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.14.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.14.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.14.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index c108c2098d..235e578c3f 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.13.Final + 4.2.14.Final true From 8400ee162da9eb743c4d9d2d3a7ade9ed67a9ab9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 05:25:45 +0000 Subject: [PATCH 531/615] build(deps-dev): Bump com.gradle:develocity-maven-extension Bumps com.gradle:develocity-maven-extension from 2.4.0 to 2.4.1. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: 2.4.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 470cc18a10..1c05e35670 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.4.0 + 2.4.1 com.gradle From c11ab30e0466fdedb469a0a73ffa1599e8547174 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 05:24:38 +0000 Subject: [PATCH 532/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.39.0 to 6.40.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.39.0...v6.40.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.40.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c48b625dfc..c2679a2b63 100644 --- a/pom.xml +++ b/pom.xml @@ -204,7 +204,7 @@ 3.2.0 1.2.8 4.0.0 - 6.39.0 + 6.40.0 3.35.3 3.34.1 0.25.7 From ac34622011a1cf63f489a670423a7dbc55fef569 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 05:25:19 +0000 Subject: [PATCH 533/615] build(deps-dev): Bump com.github.siom79.japicmp:japicmp-maven-plugin Bumps [com.github.siom79.japicmp:japicmp-maven-plugin](https://github.com/siom79/japicmp) from 0.25.7 to 0.26.0. - [Release notes](https://github.com/siom79/japicmp/releases) - [Changelog](https://github.com/siom79/japicmp/blob/master/release.py) - [Commits](https://github.com/siom79/japicmp/compare/japicmp-base-0.25.7...japicmp-base-0.26.0) --- updated-dependencies: - dependency-name: com.github.siom79.japicmp:japicmp-maven-plugin dependency-version: 0.26.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c48b625dfc..42002a2a26 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ 6.39.0 3.35.3 3.34.1 - 0.25.7 + 0.26.0 1.0 From 0c0a07f557a4409a1e5b9883dedacbd36d22c4c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 05:37:52 +0000 Subject: [PATCH 534/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.35.3 to 3.36.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.35.3...v3.36.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.36.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6f2b8b3086..aa74432083 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,7 @@ 1.2.8 4.0.0 6.40.0 - 3.35.3 + 3.36.0 3.34.1 0.26.0 1.0 From d82719b83d3e85daac5d08669c6819a843cdaeae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 05:52:18 +0000 Subject: [PATCH 535/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.34.1 to 3.35.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.34.1...v3.35.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.35.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aa74432083..081a060112 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ 4.0.0 6.40.0 3.36.0 - 3.34.1 + 3.35.0 0.26.0 1.0 From 5e02c73815c87ecf8ca59d966a40d1c8ef2aaee5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 May 2026 06:53:19 +0000 Subject: [PATCH 536/615] build(deps): Bump org.json:json from 20251224 to 20260522 Bumps [org.json:json](https://github.com/douglascrockford/JSON-java) from 20251224 to 20260522. - [Release notes](https://github.com/douglascrockford/JSON-java/releases) - [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md) - [Commits](https://github.com/douglascrockford/JSON-java/compare/20251224...20260522) --- updated-dependencies: - dependency-name: org.json:json dependency-version: '20260522' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 081a060112..bdeedb4885 100644 --- a/pom.xml +++ b/pom.xml @@ -169,7 +169,7 @@ 2.14.0 1.15.2 2.0.18 - 20251224 + 20260522 4.0.6 6.1.0 From de63c816fed2a8991947a37da336734d2a622711 Mon Sep 17 00:00:00 2001 From: seonwoojung <79202163+seonwoo-jung@users.noreply.github.com> Date: Mon, 25 May 2026 23:30:40 +0900 Subject: [PATCH 537/615] Document metrics published by the micrometer module (#3370) Adds a module-level README under micrometer/ that lists every metric emitted by MicrometerCapability (timers, counters, distribution summaries), its tags, and the observation emitted by MicrometerObservationCapability together with the keys carried by the default convention. The main README's Micrometer section now links to this reference. Fixes #2248 Co-authored-by: seonwoo_jung --- README.md | 3 + micrometer/README.md | 127 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 micrometer/README.md diff --git a/README.md b/README.md index 6e31ab89f0..cbaae10766 100644 --- a/README.md +++ b/README.md @@ -1190,6 +1190,9 @@ public class MyApp { } ``` +See the [micrometer module README](./micrometer/README.md) for the full list of +metrics that are published, their tags and how to use `MicrometerObservationCapability`. + #### Static and Default Methods Interfaces targeted by Feign may have static or default methods (if using Java 8+). These allows Feign clients to contain logic that is not expressly defined by the underlying API. diff --git a/micrometer/README.md b/micrometer/README.md new file mode 100644 index 0000000000..d060cefbe1 --- /dev/null +++ b/micrometer/README.md @@ -0,0 +1,127 @@ +Micrometer +=================== + +This module integrates Feign with [Micrometer](https://micrometer.io/) so that +HTTP calls made through Feign clients are observable through any Micrometer-supported +monitoring system (Prometheus, Datadog, CloudWatch, etc.). + +Two capabilities are provided: + +* `MicrometerCapability` — publishes timers, counters and distribution summaries + to a `MeterRegistry`. +* `MicrometerObservationCapability` — publishes Micrometer `Observation`s to an + `ObservationRegistry` (which can in turn produce metrics and tracing spans). + +Pick one — both record the same underlying call, so registering both would +double-count. + +## Usage + +### `MicrometerCapability` + +```java +GitHub github = Feign.builder() + .addCapability(new MicrometerCapability()) + .target(GitHub.class, "https://api.github.com"); +``` + +By default, metrics are registered with `io.micrometer.core.instrument.Metrics.globalRegistry`. +Pass your own registry and/or common tags if you want explicit control: + +```java +MeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT); + +GitHub github = Feign.builder() + .addCapability(new MicrometerCapability(registry, Tags.of("application", "my-app"))) + .target(GitHub.class, "https://api.github.com"); +``` + +### `MicrometerObservationCapability` + +```java +ObservationRegistry observationRegistry = ObservationRegistry.create(); + +GitHub github = Feign.builder() + .addCapability(new MicrometerObservationCapability(observationRegistry)) + .target(GitHub.class, "https://api.github.com"); +``` + +To customize the tags or name of the observation, implement +`FeignObservationConvention` (or extend `DefaultFeignObservationConvention`) and +pass it to the constructor: + +```java +new MicrometerObservationCapability(observationRegistry, new MyFeignObservationConvention()); +``` + +## Metrics published by `MicrometerCapability` + +The capability instruments five stages of a Feign call. Each stage emits a +timer; counters and distribution summaries are emitted where noted. + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `feign.Feign` | Timer | Total time spent in the Feign method invocation, including encoding, the HTTP call and decoding. Recorded by `MeteredInvocationHandleFactory`. | +| `feign.Feign.exception` | Timer | Same as above, recorded when the invocation throws (any `Throwable`). | +| `feign.Feign.http_error` | Counter | Incremented once per `FeignException` thrown by an invocation. Adds `http_status` and `error_group` tags. | +| `feign.Client` | Timer | Time spent in the underlying HTTP client for a single request. Recorded by `MeteredClient`. | +| `feign.Client.exception` | Timer | Same as above, recorded when the HTTP call throws. | +| `feign.Client.http_response_code` | Counter | Incremented once per HTTP response (including error responses). Adds `http_status`, `status_group`, `http_method` and `uri` tags. | +| `feign.AsyncClient` | Timer | Async-equivalent of `feign.Client`. Recorded by `MeteredAsyncClient`. | +| `feign.AsyncClient.exception` | Timer | Async-equivalent of `feign.Client.exception`. | +| `feign.AsyncClient.http_response_code` | Counter | Async-equivalent of `feign.Client.http_response_code`. | +| `feign.codec.Encoder` | Timer | Time spent encoding the request body. Recorded by `MeteredEncoder`. | +| `feign.codec.Encoder.response_size` | DistributionSummary | Size, in bytes, of the encoded **request** body. The metric name predates the current behavior. | +| `feign.codec.Decoder` | Timer | Time spent decoding the response body. Recorded by `MeteredDecoder`. | +| `feign.codec.Decoder.exception` | Timer | Same as above, recorded when decoding throws. | +| `feign.codec.Decoder.response_size` | DistributionSummary | Size, in bytes, of the response body read by the decoder. | + +### Tags + +Every metric carries the following tags, populated by `FeignMetricTagResolver`: + +| Tag | Source | Example | +| --- | ------ | ------- | +| `client` | Target interface FQN | `com.example.GitHub` | +| `method` | Java method name | `contributors` | +| `host` | Host extracted from the target URL | `api.github.com` | +| `exception_name` | Exception simple name (only present on error) | `FeignException` | +| `root_cause_name` | Root cause exception simple name (only present on error) | `SocketTimeoutException` | + +Additional tags are added by specific metrics: + +* `feign.Client.http_response_code` / `feign.AsyncClient.http_response_code` — + adds `http_status` (e.g. `404`), `status_group` (e.g. `4xx`), `http_method` + (e.g. `GET`) and `uri` (the templated path, e.g. `/repos/{owner}/{repo}/contributors`). +* `feign.Feign.http_error` — adds `http_status` and `error_group` (e.g. `5xx`). +* `feign.codec.Decoder.*` — adds `uri`. + +You can attach extra common tags either through `MeterRegistry.config().commonTags(...)` +or via the `MicrometerCapability(MeterRegistry, List)` / +`MicrometerCapability(MeterRegistry, Map)` constructors. + +## Observation published by `MicrometerObservationCapability` + +A single observation is produced per HTTP call: + +| Name | Contextual name | Description | +| ---- | --------------- | ----------- | +| `http.client.requests` | `HTTP {method}` (e.g. `HTTP GET`) | One observation per HTTP request issued by the Feign client. The observation is stopped after the response is received or an exception is signalled. | + +The default convention (`DefaultFeignObservationConvention`) attaches the +following low-cardinality key values: + +| Key | Value | +| --- | ----- | +| `http.method` | The HTTP method (`GET`, `POST`, ...). `UNKNOWN` if the request is null. | +| `http.url` | The templated URL of the method. | +| `http.status_code` | The response status code, or `CLIENT_ERROR` if no response was received. | +| `clientName` | The target interface FQN. | + +The following key names are also declared on `FeignObservationDocumentation` and +are available for custom conventions to populate: `http.scheme`, `net.peer.host`, +`net.peer.port`. + +Whatever observation handlers are registered on the `ObservationRegistry` +(for example `DefaultMeterObservationHandler` for metrics, a tracing handler +for spans) decide what is ultimately emitted. From f4d78edd46b714c6fc2f8072356c061363e1da1c Mon Sep 17 00:00:00 2001 From: seonwoojung <79202163+seonwoo-jung@users.noreply.github.com> Date: Mon, 25 May 2026 23:31:30 +0900 Subject: [PATCH 538/615] Forward dismiss404 from CoroutineFeign builder to AsyncFeign (#3371) CoroutineFeign.CoroutineBuilder inherits the dismiss404 setter from BaseBuilder, but internalBuild() created a fresh AsyncFeign.builder() chain that never forwarded the flag, so dismiss404() configured on a CoroutineBuilder had no effect at runtime: a 404 response still produced a FeignException instead of being passed to the decoder. Split the chain so the configured dismiss404 value is applied to the underlying AsyncBuilder before build(). Adds a unit test that verifies the decoder is invoked for a 404 response when dismiss404 is set on the CoroutineBuilder. Fixes #2026 Co-authored-by: seonwoo_jung --- .../java/feign/kotlin/CoroutineFeign.java | 40 ++++++++++--------- .../kotlin/feign/kotlin/CoroutineFeignTest.kt | 26 ++++++++++++ 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java b/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java index 4027e1d149..a4cd53b5af 100644 --- a/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java +++ b/kotlin/src/main/java/feign/kotlin/CoroutineFeign.java @@ -163,25 +163,27 @@ public T target(Target target, C context) { @Override @SuppressWarnings("unchecked") public CoroutineFeign internalBuild() { - AsyncFeign asyncFeign = - (AsyncFeign) - AsyncFeign.builder() - .logLevel(logLevel) - .client((AsyncClient) client) - .decoder(decoder) - .errorDecoder(errorDecoder) - .contract(contract) - .retryer(retryer) - .logger(logger) - .encoder(encoder) - .queryMapEncoder(queryMapEncoder) - .options(options) - .requestInterceptors(requestInterceptors) - .responseInterceptors(responseInterceptors) - .invocationHandlerFactory(invocationHandlerFactory) - .defaultContextSupplier((AsyncContextSupplier) defaultContextSupplier) - .methodInfoResolver(methodInfoResolver) - .build(); + AsyncFeign.AsyncBuilder asyncBuilder = + AsyncFeign.builder() + .logLevel(logLevel) + .client((AsyncClient) client) + .decoder(decoder) + .errorDecoder(errorDecoder) + .contract(contract) + .retryer(retryer) + .logger(logger) + .encoder(encoder) + .queryMapEncoder(queryMapEncoder) + .options(options) + .requestInterceptors(requestInterceptors) + .responseInterceptors(responseInterceptors) + .invocationHandlerFactory(invocationHandlerFactory) + .defaultContextSupplier((AsyncContextSupplier) defaultContextSupplier) + .methodInfoResolver(methodInfoResolver); + if (dismiss404) { + asyncBuilder.dismiss404(); + } + AsyncFeign asyncFeign = (AsyncFeign) asyncBuilder.build(); return new CoroutineFeign<>(asyncFeign); } } diff --git a/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt b/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt index 011ee32ac2..aa1d25266b 100644 --- a/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt +++ b/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt @@ -34,6 +34,7 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.Test import java.io.IOException import java.lang.reflect.Type +import java.util.concurrent.atomic.AtomicBoolean class CoroutineFeignTest { @Test @@ -105,6 +106,31 @@ class CoroutineFeignTest { assertThat(firstOrder).isEqualTo(Unit) } + @Test + fun `sut should dismiss 404 responses when dismiss404 is configured on CoroutineBuilder`(): Unit = runBlocking { + // Arrange: server returns 404; a custom decoder records whether it was invoked + val server = MockWebServer() + server.enqueue(MockResponse().setResponseCode(404)) + + val decoderInvokedFor404 = AtomicBoolean(false) + val recordingDecoder = Decoder { response, _ -> + decoderInvokedFor404.set(response.status() == 404) + "" + } + + val client = TestInterfaceAsyncBuilder() + .dismiss404() + .decoder(recordingDecoder) + .target("http://localhost:" + server.port) + + // Act: must not throw FeignException; the decoder must be invoked for the 404 + val result: String = client.findOrderThatReturningBasicType(orderId = 1) + + // Assert + assertThat(decoderInvokedFor404.get()).isTrue() + assertThat(result).isEqualTo("") + } + @Test fun `sut should run correctly when using http body`(): Unit = runBlocking { // Arrange From 9e439190213420bdd99c60a43bd403859fba8c59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 07:01:33 +0000 Subject: [PATCH 539/615] build(deps): Bump io.dropwizard.metrics:metrics-core Bumps [io.dropwizard.metrics:metrics-core](https://github.com/dropwizard/metrics) from 4.2.38 to 4.2.39. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v4.2.38...v4.2.39) --- updated-dependencies: - dependency-name: io.dropwizard.metrics:metrics-core dependency-version: 4.2.39 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bdeedb4885..e7c4feb5b6 100644 --- a/pom.xml +++ b/pom.xml @@ -244,7 +244,7 @@ 1.1.1 1.18.46 3.6.2 - 4.2.38 + 4.2.39 5.0.6 0.2.0 2.1.1 From 2496e033b4c6a5a8735654c3ded40847abf30a99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 07:04:21 +0000 Subject: [PATCH 540/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx5-test Bumps `vertx.version` from 5.0.12 to 5.1.0. Updates `io.vertx:vertx-junit5` from 5.0.12 to 5.1.0 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/5.0.12...5.1.0) Updates `io.vertx:vertx-web-client` from 5.0.12 to 5.1.0 - [Commits](https://github.com/vert-x3/vertx-web/compare/5.0.12...5.1.0) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 5.1.0 dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: io.vertx:vertx-web-client dependency-version: 5.1.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx5-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index dde012d55d..4ebdd7ef5a 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.0.12 + 5.1.0 From 1cba9718e1127399fb35612b9174395d95a4e8e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 07:14:28 +0000 Subject: [PATCH 541/615] build(deps): Bump io.dropwizard.metrics5:metrics-core Bumps [io.dropwizard.metrics5:metrics-core](https://github.com/dropwizard/metrics) from 5.0.6 to 5.0.7. - [Release notes](https://github.com/dropwizard/metrics/releases) - [Commits](https://github.com/dropwizard/metrics/compare/v5.0.6...v5.0.7) --- updated-dependencies: - dependency-name: io.dropwizard.metrics5:metrics-core dependency-version: 5.0.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e7c4feb5b6..5f78eedb78 100644 --- a/pom.xml +++ b/pom.xml @@ -245,7 +245,7 @@ 1.18.46 3.6.2 4.2.39 - 5.0.6 + 5.0.7 0.2.0 2.1.1 1.5.3 From f03867f4d75639dba2c6297dcbe4212b49717c58 Mon Sep 17 00:00:00 2001 From: Kevin <96028167+young0264@users.noreply.github.com> Date: Thu, 28 May 2026 04:46:47 +0900 Subject: [PATCH 542/615] Only unwrap declared checked causes with UNWRAP (#3359) --- .../java/feign/SynchronousMethodHandler.java | 13 +++- core/src/test/java/feign/FeignTest.java | 61 +++++++++++++++++++ .../httpclient/ApacheHttpClientTest.java | 23 +++++++ 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/feign/SynchronousMethodHandler.java b/core/src/main/java/feign/SynchronousMethodHandler.java index 244fe90f5d..64b81d43b4 100644 --- a/core/src/main/java/feign/SynchronousMethodHandler.java +++ b/core/src/main/java/feign/SynchronousMethodHandler.java @@ -76,10 +76,17 @@ private Object runWithRetry(Invocation invocation, Options options) throws Throw } catch (RetryableException th) { Throwable cause = th.getCause(); if (methodHandlerConfiguration.getPropagationPolicy() == UNWRAP && cause != null) { - throw cause; - } else { - throw th; + if (cause instanceof RuntimeException || cause instanceof Error) { + throw cause; + } + for (Class exceptionType : + methodHandlerConfiguration.getMetadata().method().getExceptionTypes()) { + if (exceptionType.isAssignableFrom(cause.getClass())) { + throw cause; + } + } } + throw th; } if (methodHandlerConfiguration.getLogLevel() != Logger.Level.NONE) { methodHandlerConfiguration diff --git a/core/src/test/java/feign/FeignTest.java b/core/src/test/java/feign/FeignTest.java index 748bfe1ad5..47a348bfaf 100755 --- a/core/src/test/java/feign/FeignTest.java +++ b/core/src/test/java/feign/FeignTest.java @@ -50,6 +50,7 @@ import feign.querymap.FieldQueryMapEncoder; import java.io.IOException; import java.lang.reflect.Type; +import java.net.ProtocolException; import java.net.URI; import java.time.Clock; import java.time.Instant; @@ -631,6 +632,60 @@ void throwsFeignExceptionWithoutBody() { } } + @Test + void doesNotUnwrapUndeclaredCheckedCauseWhenPropagationPolicyIsUnwrap() { + TestInterface api = + Feign.builder() + .exceptionPropagationPolicy(UNWRAP) + .retryer(new DefaultRetryer(1, 1, 1)) + .client( + (_, _) -> { + throw new ProtocolException("missing Location header for redirect"); + }) + .target(TestInterface.class, "http://localhost:" + server.getPort()); + + RetryableException exception = assertThrows(RetryableException.class, () -> api.post()); + + assertThat(exception.getMessage()).contains("missing Location header for redirect"); + assertThat(exception.getCause()).isInstanceOf(ProtocolException.class); + } + + @Test + void unwrapDeclaredCheckedCauseWhenPropagationPolicyIsUnwrap() { + TestInterface api = + Feign.builder() + .exceptionPropagationPolicy(UNWRAP) + .retryer(new DefaultRetryer(1, 1, 1)) + .client( + (_, _) -> { + throw new ProtocolException("missing Location header for redirect"); + }) + .target(TestInterface.class, "http://localhost:" + server.getPort()); + + ProtocolException exception = + assertThrows(ProtocolException.class, () -> api.postThrowsProtocolException()); + + assertThat(exception.getMessage()).contains("missing Location header for redirect"); + } + + @Test + void unwrapCheckedCauseAssignableToDeclaredTypeWhenPropagationPolicyIsUnwrap() { + TestInterface api = + Feign.builder() + .exceptionPropagationPolicy(UNWRAP) + .retryer(new DefaultRetryer(1, 1, 1)) + .client( + (_, _) -> { + throw new ProtocolException("missing Location header for redirect"); + }) + .target(TestInterface.class, "http://localhost:" + server.getPort()); + + IOException exception = assertThrows(IOException.class, () -> api.postThrowsIOException()); + + assertThat(exception).isInstanceOf(ProtocolException.class); + assertThat(exception.getMessage()).contains("missing Location header for redirect"); + } + @Test void ensureRetryerClonesItself() throws Exception { server.enqueue(new MockResponse().setResponseCode(503).setBody("foo 1")); @@ -1234,6 +1289,12 @@ interface TestInterface { @RequestLine("POST /") String post() throws TestInterfaceException; + @RequestLine("POST /") + String postThrowsProtocolException() throws ProtocolException; + + @RequestLine("POST /") + String postThrowsIOException() throws IOException; + @RequestLine("POST /") @Body( "%7B\"customer_name\": \"{customer_name}\", \"user_name\": \"{user_name}\", \"password\":" diff --git a/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java b/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java index 3506aae5be..4ab3601425 100644 --- a/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java +++ b/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java @@ -23,6 +23,8 @@ import feign.Feign.Builder; import feign.FeignException; import feign.Request.Options; +import feign.RetryableException; +import feign.Retryer; import feign.client.AbstractClientTest; import feign.jaxrs.JAXRSContract; import java.nio.charset.StandardCharsets; @@ -32,6 +34,8 @@ import javax.ws.rs.QueryParam; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.RecordedRequest; +import org.apache.http.ProtocolException; +import org.apache.http.client.ClientProtocolException; import org.apache.http.impl.client.HttpClientBuilder; import org.junit.jupiter.api.Test; @@ -43,6 +47,25 @@ public Builder newBuilder() { return Feign.builder().client(new ApacheHttpClient()); } + @Test + void redirectWithoutLocationHeaderKeepsRetryableExceptionWhenPropagationPolicyIsUnwrap() { + JaxRsTestInterface api = + Feign.builder() + .contract(new JAXRSContract()) + .exceptionPropagationPolicy(feign.ExceptionPropagationPolicy.UNWRAP) + .retryer(Retryer.NEVER_RETRY) + .client(new ApacheHttpClient(HttpClientBuilder.create().build())) + .target(JaxRsTestInterface.class, "http://localhost:" + server.getPort()); + + server.enqueue(new MockResponse().setResponseCode(303)); + + RetryableException exception = + assertThrows(RetryableException.class, () -> api.withoutBody("foo")); + + assertThat(exception.getCause()).isInstanceOf(ClientProtocolException.class); + assertThat(exception.getCause()).hasCauseInstanceOf(ProtocolException.class); + } + @Test void queryParamsAreRespectedWhenBodyIsEmpty() throws InterruptedException { final JaxRsTestInterface testInterface = buildTestInterface(); From 7110d11b1be14c22205d127ec1646807daf8e8a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 05:27:05 +0000 Subject: [PATCH 543/615] build(deps-dev): Bump com.github.siom79.japicmp:japicmp-maven-plugin Bumps [com.github.siom79.japicmp:japicmp-maven-plugin](https://github.com/siom79/japicmp) from 0.26.0 to 0.26.1. - [Release notes](https://github.com/siom79/japicmp/releases) - [Changelog](https://github.com/siom79/japicmp/blob/master/release.py) - [Commits](https://github.com/siom79/japicmp/compare/japicmp-base-0.26.0...japicmp-base-0.26.1) --- updated-dependencies: - dependency-name: com.github.siom79.japicmp:japicmp-maven-plugin dependency-version: 0.26.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f78eedb78..42bd188c9f 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ 6.40.0 3.36.0 3.35.0 - 0.26.0 + 0.26.1 1.0 From d83dfd798cc99ecc878b81fd71de9b6304e6b052 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 05:27:29 +0000 Subject: [PATCH 544/615] build(deps): Bump maven-surefire-plugin.version from 3.5.5 to 3.5.6 Bumps `maven-surefire-plugin.version` from 3.5.5 to 3.5.6. Updates `org.apache.maven.plugins:maven-surefire-plugin` from 3.5.5 to 3.5.6 - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.5...surefire-3.5.6) Updates `org.apache.maven.plugins:maven-failsafe-plugin` from 3.5.5 to 3.5.6 - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.5...surefire-3.5.6) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-version: 3.5.6 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-version: 3.5.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f78eedb78..46ad4b2b9a 100644 --- a/pom.xml +++ b/pom.xml @@ -191,7 +191,7 @@ 6.0.2 0.1.1 0.10.0 - 3.5.5 + 3.5.6 0.300.0 file://${project.basedir}/src/config/bom.xml 2.2.1 From 644438896ecad4a312c376e0e2e279116c35c5bf Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Wed, 3 Jun 2026 12:38:41 -0300 Subject: [PATCH 545/615] Publish feign-bom as a real module so it auto-deploys to Central Signed-off-by: Marvin Froeder --- feign-bom/pom.xml | 265 +++++++++++++++++++++++++++++++++++++++++++++ pom.xml | 12 ++ src/config/bom.xml | 77 ++++--------- 3 files changed, 301 insertions(+), 53 deletions(-) create mode 100644 feign-bom/pom.xml diff --git a/feign-bom/pom.xml b/feign-bom/pom.xml new file mode 100644 index 0000000000..cc24c5f34c --- /dev/null +++ b/feign-bom/pom.xml @@ -0,0 +1,265 @@ + + + + 4.0.0 + + + + + io.github.openfeign + feign-parent + 13.13-SNAPSHOT + ../pom.xml + + + feign-bom + pom + Feign (Bill Of Materials) + Bill of material + + + + + io.github.openfeign + feign-core + 13.13-SNAPSHOT + + + io.github.openfeign + feign-gson + 13.13-SNAPSHOT + + + io.github.openfeign + feign-http-cache + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jaxrs + 13.13-SNAPSHOT + + + io.github.openfeign + feign-httpclient + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jaxrs2 + 13.13-SNAPSHOT + + + io.github.openfeign + feign-hc5 + 13.13-SNAPSHOT + + + io.github.openfeign + feign-hystrix + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jackson + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jackson3 + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jackson-jaxb + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jackson-jr + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jaxb + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jaxb-jakarta + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jaxrs3 + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jaxrs4 + 13.13-SNAPSHOT + + + io.github.openfeign + feign-java11 + 13.13-SNAPSHOT + + + io.github.openfeign + feign-jakarta + 13.13-SNAPSHOT + + + io.github.openfeign + feign-mock + 13.13-SNAPSHOT + + + io.github.openfeign + feign-json + 13.13-SNAPSHOT + + + io.github.openfeign + feign-okhttp + 13.13-SNAPSHOT + + + io.github.openfeign + feign-googlehttpclient + 13.13-SNAPSHOT + + + io.github.openfeign + feign-ribbon + 13.13-SNAPSHOT + + + io.github.openfeign + feign-sax + 13.13-SNAPSHOT + + + io.github.openfeign + feign-slf4j + 13.13-SNAPSHOT + + + io.github.openfeign + feign-spring + 13.13-SNAPSHOT + + + io.github.openfeign + feign-soap + 13.13-SNAPSHOT + + + io.github.openfeign + feign-soap-jakarta + 13.13-SNAPSHOT + + + io.github.openfeign + feign-reactive-wrappers + 13.13-SNAPSHOT + + + io.github.openfeign + feign-micrometer + 13.13-SNAPSHOT + + + io.github.openfeign + feign-dropwizard-metrics4 + 13.13-SNAPSHOT + + + io.github.openfeign + feign-dropwizard-metrics5 + 13.13-SNAPSHOT + + + io.github.openfeign + feign-kotlin + 13.13-SNAPSHOT + + + io.github.openfeign + feign-graphql + 13.13-SNAPSHOT + + + io.github.openfeign + feign-annotation-error-decoder + 13.13-SNAPSHOT + + + io.github.openfeign + feign-form + 13.13-SNAPSHOT + + + io.github.openfeign + feign-form-spring + 13.13-SNAPSHOT + + + io.github.openfeign + feign-moshi + 13.13-SNAPSHOT + + + io.github.openfeign + feign-fastjson2 + 13.13-SNAPSHOT + + + io.github.openfeign + feign-validation + 13.13-SNAPSHOT + + + io.github.openfeign + feign-validation-jakarta + 13.13-SNAPSHOT + + + io.github.openfeign + feign-vertx + 13.13-SNAPSHOT + + + io.github.openfeign + feign-vertx4-test + 13.13-SNAPSHOT + + + io.github.openfeign + feign-vertx5-test + 13.13-SNAPSHOT + + + + + diff --git a/pom.xml b/pom.xml index 6636d71805..0644b4cb4e 100644 --- a/pom.xml +++ b/pom.xml @@ -133,6 +133,7 @@ validation validation-jakarta vertx + feign-bom @@ -894,11 +895,22 @@ true + + + + install + deploy + + + io.github.openfeign:* + *:feign-bom *:feign-example-* *:feign-benchmark diff --git a/src/config/bom.xml b/src/config/bom.xml index 01d4f76058..a7f2fdab3b 100644 --- a/src/config/bom.xml +++ b/src/config/bom.xml @@ -1,70 +1,41 @@ 4.0.0 - ${model.groupId} + + + + io.github.openfeign + feign-parent + ${model.version} + ../pom.xml + + ${model.artifactId} - ${model.version} - ${model.name} pom + ${model.name} Bill of material - #if ($model.url) - - ${model.url}#end - #if ($model.licenses && !$model.licenses.isEmpty()) - - #foreach($l in $model.licenses) - - - ${l.name} - ${l.url} - ${l.distribution} - #end - - - #end - - - https://github.com/openfeign/feign - scm:git:https://github.com/openfeign/feign.git - scm:git:git@github.com:OpenFeign/feign.git - HEAD - - -#if ($model.developers && !$model.developers.isEmpty()) - #foreach($d in $model.developers) - - - ${d.id} - ${d.name}#if($d.email) - - ${d.email}#end#if($d.url) - - ${d.url}#end#if($d.organization) - - ${d.organization}#end#if($d.organizationUrl) - - ${d.organizationUrl}#end - - #end - - -#end #foreach($d in $model.dependencyManagement.dependencies) From 6769d9ad4ae3f6a00ebde2932b7b938619e7ee51 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Wed, 3 Jun 2026 13:11:23 -0300 Subject: [PATCH 546/615] Fix flaky vertx http2NoConnectionLeak test by using h2c prior knowledge Signed-off-by: Marvin Froeder --- .../src/test/java/feign/vertx/ConnectionsLeakTests.java | 9 ++++++++- .../src/test/java/feign/vertx/ConnectionsLeakTests.java | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java b/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java index dae2645f3e..5931c7acb4 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java @@ -95,7 +95,14 @@ void http2NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { int poolSize = 1; int nbRequests = 100; - WebClientOptions options = new WebClientOptions().setProtocolVersion(HttpVersion.HTTP_2); + // Use h2c with prior knowledge instead of the default HTTP/1.1 upgrade: during the upgrade + // handshake the connection is still HTTP/1.1, so the pool applies http1MaxSize (5) rather than + // http2MaxSize (1) and can open several connections under load before the first upgrades to + // HTTP/2 - which made this test flaky on CI. + WebClientOptions options = + new WebClientOptions() + .setProtocolVersion(HttpVersion.HTTP_2) + .setHttp2ClearTextUpgrade(false); PoolOptions poolOptions = new PoolOptions().setHttp2MaxSize(1); WebClient webClient = WebClient.create(vertx, options, poolOptions); diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java index 15669e2c7f..b76b751ed0 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java @@ -98,8 +98,15 @@ void http2NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { int poolSize = 1; int nbRequests = 100; + // Use h2c with prior knowledge instead of the default HTTP/1.1 upgrade: during the upgrade + // handshake the connection is still HTTP/1.1, so the pool applies the HTTP/1.1 max pool size + // rather than the HTTP/2 one and can open several connections under load before the first + // upgrades to HTTP/2 - which made this test flaky on CI. WebClientOptions options = - new WebClientOptions().setProtocolVersion(HttpVersion.HTTP_2).setHttp2MaxPoolSize(1); + new WebClientOptions() + .setProtocolVersion(HttpVersion.HTTP_2) + .setHttp2MaxPoolSize(1) + .setHttp2ClearTextUpgrade(false); WebClient webClient = WebClient.create(vertx, options); HelloServiceAPI client = From 46c4acd1b45eef4ff8d8c5050eabb41ebf1cc432 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:23:46 +0000 Subject: [PATCH 547/615] build(deps): Bump netty.version from 4.2.14.Final to 4.2.15.Final Bumps `netty.version` from 4.2.14.Final to 4.2.15.Final. Updates `io.netty:netty-bom` from 4.2.14.Final to 4.2.15.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.14.Final...netty-4.2.15.Final) Updates `io.netty:netty-handler` from 4.2.14.Final to 4.2.15.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.14.Final...netty-4.2.15.Final) Updates `io.netty:netty-codec-http` from 4.2.14.Final to 4.2.15.Final - [Release notes](https://github.com/netty/netty/releases) - [Commits](https://github.com/netty/netty/compare/netty-4.2.14.Final...netty-4.2.15.Final) --- updated-dependencies: - dependency-name: io.netty:netty-bom dependency-version: 4.2.15.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-handler dependency-version: 4.2.15.Final dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.netty:netty-codec-http dependency-version: 4.2.15.Final dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- benchmark/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 235e578c3f..6f79e261e1 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -32,7 +32,7 @@ 1.37 0.5.3 1.3.8 - 4.2.14.Final + 4.2.15.Final true From bfcc81caee99b7ee5b935b48503c37855e2f23b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:25:24 +0000 Subject: [PATCH 548/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx5-test Bumps `vertx.version` from 5.1.0 to 5.1.1. Updates `io.vertx:vertx-junit5` from 5.1.0 to 5.1.1 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/5.1.0...5.1.1) Updates `io.vertx:vertx-web-client` from 5.1.0 to 5.1.1 - [Commits](https://github.com/vert-x3/vertx-web/compare/5.1.0...5.1.1) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 5.1.1 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 5.1.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx5-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 4ebdd7ef5a..3cd071e05d 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.1.0 + 5.1.1 From f14b7e61768a8e327a0740ffc11d3cd6414e85b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:25:38 +0000 Subject: [PATCH 549/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx4-test Bumps `vertx.version` from 4.5.27 to 4.5.28. Updates `io.vertx:vertx-junit5` from 4.5.27 to 4.5.28 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.27...4.5.28) Updates `io.vertx:vertx-web-client` from 4.5.27 to 4.5.28 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.27...4.5.28) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 4.5.28 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 4.5.28 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx4-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index c58aab329c..8b48f808a7 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 4.x. - 4.5.27 + 4.5.28 From 334e888a337e34e0f8c08790b33792e1049e6e69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:30:40 +0000 Subject: [PATCH 550/615] build(deps): Bump kotlin.version from 2.3.21 to 2.4.0 Bumps `kotlin.version` from 2.3.21 to 2.4.0. Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 2.3.21 to 2.4.0 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.3.21...v2.4.0) Updates `org.jetbrains.kotlin:kotlin-reflect` from 2.3.21 to 2.4.0 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.3.21...v2.4.0) Updates `org.jetbrains.kotlin:kotlin-maven-plugin` from 2.3.21 to 2.4.0 --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8 dependency-version: 2.4.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.jetbrains.kotlin:kotlin-reflect dependency-version: 2.4.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.jetbrains.kotlin:kotlin-maven-plugin dependency-version: 2.4.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/pom.xml b/kotlin/pom.xml index 34a6e57d7b..a3d5857bc0 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -30,7 +30,7 @@ Feign Kotlin - 2.3.21 + 2.4.0 1.11.0 From 05e421f840e4a1302c8db51af1809fb01d9c40b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:30:51 +0000 Subject: [PATCH 551/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.35.0 to 3.36.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.35.0...v3.36.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.36.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0644b4cb4e..5e3eeb5ecb 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ 4.0.0 6.40.0 3.36.0 - 3.35.0 + 3.36.0 0.26.1 1.0 From 03b9d7eabe668f40b94dc457b62341b2abed9bed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:31:34 +0000 Subject: [PATCH 552/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.40.0 to 6.41.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.40.0...v6.41.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.41.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0644b4cb4e..d09a6be7cc 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,7 @@ 3.2.0 1.2.8 4.0.0 - 6.40.0 + 6.41.0 3.36.0 3.35.0 0.26.1 From 5866ebb455714cec440bd5be17d20ed2ba26963a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 22:44:15 +0000 Subject: [PATCH 553/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.36.0 to 3.37.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.36.0...v3.37.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.37.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e22544ef57..3b613d5f81 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ 1.2.8 4.0.0 6.41.0 - 3.36.0 + 3.37.0 3.36.0 0.26.1 1.0 From f9159cfa7845e3323c285bd45cfa60acb35bc562 Mon Sep 17 00:00:00 2001 From: Marvin Date: Sat, 6 Jun 2026 06:46:02 -0300 Subject: [PATCH 554/615] fix: prevent Content-Length smuggling, log format-string injection, and common-pool starvation in streaming bodies * feat!: make `feign.Request.Body` streaming-ready Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * chore: remove `ThrowingConsumer` Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * chore: remove unused `FeignBodyEntity`; improve Javadoc redability Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * docs: add `@apiNote` to request body factory methods Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * fix: propagate `IOException` from async IO operation Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * feat: make Executor injectable Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * chore: code format Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * feat: make `Request.Body` a `@FunctionalInterface` Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * docs: add migration guide for Feign v14 (Request Body Streaming) Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * build(pom.xml): exclude breaking classes from japicmp plugin scope Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * build(pom.xml): add TODO comment to remove japicmp exclusion later Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * docs: update migration guide for Feign v14 with details on breaking changes and replacements Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * fix: make Request implement Serializable Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> * fix: prevent Content-Length smuggling, log format-string injection, and common-pool starvation in streaming bodies Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder Co-authored-by: Yevhen Vasyliev Co-authored-by: trumpetinc <6618744+trumpetinc@users.noreply.github.com> --- MIGRATION-v14.md | 421 +++++++++++++ .../java/feign/error/ExceptionGenerator.java | 4 +- .../AbstractAnnotationErrorDecoderTest.java | 4 +- ...ErrorDecoderExceptionConstructorsTest.java | 7 +- .../benchmark/DecoderIteratorsBenchmark.java | 2 +- core/src/main/java/feign/DefaultClient.java | 9 +- core/src/main/java/feign/DefaultContract.java | 2 +- core/src/main/java/feign/FeignException.java | 6 +- core/src/main/java/feign/Logger.java | 22 +- core/src/main/java/feign/Request.java | 573 +++++++++--------- core/src/main/java/feign/RequestTemplate.java | 60 +- .../main/java/feign/codec/DefaultEncoder.java | 5 +- .../feign/AlwaysEncodeBodyContractTest.java | 15 +- core/src/test/java/feign/AsyncFeignTest.java | 11 +- core/src/test/java/feign/ClientTest.java | 6 +- .../test/java/feign/DefaultContractTest.java | 31 +- .../src/test/java/feign/FeignBuilderTest.java | 3 +- .../test/java/feign/FeignExceptionTest.java | 39 +- core/src/test/java/feign/FeignTest.java | 11 +- .../test/java/feign/FeignUnderAsyncTest.java | 11 +- .../test/java/feign/LoggerMethodsTest.java | 2 +- .../test/java/feign/RequestTemplateTest.java | 13 +- core/src/test/java/feign/ResponseTest.java | 23 +- .../java/feign/RetryableExceptionTest.java | 6 +- core/src/test/java/feign/RetryerTest.java | 2 +- core/src/test/java/feign/TargetTest.java | 4 +- .../feign/assertj/RequestTemplateAssert.java | 26 +- .../java/feign/codec/DefaultDecoderTest.java | 5 +- .../java/feign/codec/DefaultEncoderTest.java | 17 +- .../DefaultErrorDecoderHttpErrorTest.java | 6 +- .../feign/codec/DefaultErrorDecoderTest.java | 19 +- .../java/feign/stream/StreamDecoderTest.java | 4 +- .../java/feign/metrics4/MeteredEncoder.java | 18 +- .../java/feign/metrics5/MeteredEncoder.java | 18 +- .../feign/fastjson2/Fastjson2Encoder.java | 4 +- .../feign/fastjson2/FastJsonCodecTest.java | 16 +- .../form/MultipartFormContentProcessor.java | 3 +- .../form/UrlencodedFormContentProcessor.java | 3 +- .../feign/form/multipart/DelegateWriter.java | 16 +- .../googlehttpclient/GoogleHttpClient.java | 60 +- .../java/feign/graphql/GraphqlDecoder.java | 11 +- .../graphql/GraphqlRequestInterceptor.java | 2 +- .../feign/graphql/GraphqlDecoderTest.java | 6 +- .../feign/graphql/GraphqlEncoderTest.java | 33 +- .../src/main/java/feign/gson/GsonEncoder.java | 3 +- .../test/java/feign/gson/GsonCodecTest.java | 19 +- .../java/feign/hc5/ApacheHttp5Client.java | 22 +- .../feign/hc5/AsyncApacheHttp5Client.java | 125 +++- .../main/java/feign/hc5/FeignBodyEntity.java | 97 +++ .../feign/hc5/AsyncApacheHttp5ClientTest.java | 11 +- .../feign/httpclient/ApacheHttpClient.java | 64 +- .../jackson/jaxb/JacksonJaxbJsonEncoder.java | 4 +- .../jackson/jaxb/JacksonJaxbCodecTest.java | 7 +- .../feign/jackson/jr/JacksonJrEncoder.java | 5 +- .../feign/jackson/jr/JacksonCodecTest.java | 32 +- .../java/feign/jackson/JacksonEncoder.java | 4 +- .../java/feign/jackson/JacksonCodecTest.java | 31 +- .../feign/jackson/JacksonIteratorTest.java | 10 +- .../java/feign/jackson3/Jackson3Encoder.java | 4 +- .../feign/jackson3/Jackson3CodecTest.java | 31 +- .../java/feign/http2client/Http2Client.java | 110 +++- .../test/Http2ClientAsyncTest.java | 11 +- .../src/main/java/feign/jaxb/JAXBEncoder.java | 3 +- .../test/java/feign/jaxb/JAXBCodecTest.java | 27 +- .../jaxb/examples/AWSSignatureVersion4.java | 11 +- .../src/main/java/feign/jaxb/JAXBEncoder.java | 3 +- .../test/java/feign/jaxb/JAXBCodecTest.java | 27 +- .../jaxb/examples/AWSSignatureVersion4.java | 11 +- .../main/java/feign/jaxrs2/JAXRSClient.java | 29 +- .../src/main/java/feign/json/JsonEncoder.java | 3 +- .../test/java/feign/json/JsonCodecTest.java | 7 +- .../test/java/feign/json/JsonDecoderTest.java | 4 +- .../test/java/feign/json/JsonEncoderTest.java | 18 +- .../kotlin/feign/kotlin/CoroutineFeignTest.kt | 5 +- .../java/feign/micrometer/MeteredEncoder.java | 16 +- mock/src/main/java/feign/mock/RequestKey.java | 47 +- .../test/java/feign/mock/MockClientTest.java | 41 +- .../test/java/feign/mock/RequestKeyTest.java | 35 +- .../main/java/feign/moshi/MoshiEncoder.java | 3 +- .../java/feign/moshi/MoshiDecoderTest.java | 19 +- .../main/java/feign/okhttp/OkHttpClient.java | 56 +- .../feign/okhttp/OkHttpClientAsyncTest.java | 11 +- pom.xml | 8 + .../src/main/java/feign/ribbon/LBClient.java | 13 +- .../test/java/feign/ribbon/LBClientTest.java | 4 +- .../test/java/feign/sax/SAXDecoderTest.java | 9 +- .../sax/examples/AWSSignatureVersion4.java | 11 +- .../java/feign/slf4j/Slf4jLoggerTest.java | 3 +- .../src/main/java/feign/soap/SOAPEncoder.java | 9 +- .../test/java/feign/soap/SOAPCodecTest.java | 27 +- .../java/feign/soap/SOAPFaultDecoderTest.java | 13 +- .../src/main/java/feign/soap/SOAPEncoder.java | 3 +- .../test/java/feign/soap/SOAPCodecTest.java | 27 +- .../java/feign/soap/SOAPFaultDecoderTest.java | 13 +- .../java/feign/spring/SpringContractTest.java | 11 +- .../src/main/java/feign/VertxFeign.java | 11 +- .../java/feign/vertx/OutputToReadStream.java | 308 ++++++++++ .../java/feign/vertx/VertxHttpClient.java | 26 +- .../feign/vertx/ConnectionsLeakTests.java | 2 + .../vertx/Http11ClientReconnectTest.java | 1 + .../java/feign/vertx/QueryMapEncoderTest.java | 1 + .../java/feign/vertx/RawContractTest.java | 1 + .../feign/vertx/RequestPreProcessorTest.java | 1 + .../test/java/feign/vertx/RetryingTest.java | 1 + .../java/feign/vertx/TimeoutHandlingTest.java | 1 + .../java/feign/vertx/VertxHttpClientTest.java | 20 + .../feign/vertx/VertxHttpOptionsTest.java | 2 + .../feign/vertx/ConnectionsLeakTests.java | 2 + .../vertx/Http11ClientReconnectTest.java | 1 + .../java/feign/vertx/QueryMapEncoderTest.java | 1 + .../java/feign/vertx/RawContractTest.java | 1 + .../feign/vertx/RequestPreProcessorTest.java | 1 + .../test/java/feign/vertx/RetryingTest.java | 1 + .../java/feign/vertx/TimeoutHandlingTest.java | 1 + .../java/feign/vertx/VertxHttpClientTest.java | 20 + .../feign/vertx/VertxHttpOptionsTest.java | 2 + 116 files changed, 2069 insertions(+), 1012 deletions(-) create mode 100644 MIGRATION-v14.md create mode 100644 hc5/src/main/java/feign/hc5/FeignBodyEntity.java create mode 100644 vertx/feign-vertx/src/main/java/feign/vertx/OutputToReadStream.java diff --git a/MIGRATION-v14.md b/MIGRATION-v14.md new file mode 100644 index 0000000000..e489aa707a --- /dev/null +++ b/MIGRATION-v14.md @@ -0,0 +1,421 @@ +# Migration Guide — Feign v14 (Request Body Streaming) + +This guide covers the breaking changes introduced in #3360 and explains how to update your code. + +> **Target release:** `v14.rc.1` + +--- + +## Overview + +`feign.Request.Body` has been redesigned from a `byte[]`-backed concrete class into a **streaming-ready interface**. +Request bodies are no longer eagerly buffered in memory unless you explicitly use the `byte[]`/`String` factory methods. + +For most users, regular Feign usage via interface annotations and `Feign.builder().target(...)` is unchanged. +The **breaking changes** primarily affect code that interacts directly with request body internals, including: + +- Custom `Encoder` implementations +- Custom `Client` implementations +- Any code that directly reads `Request.body()`, `Request.length()`, `Request.charset()`, or `RequestTemplate.body()`/ + `RequestTemplate.requestBody()` + +--- + +## Breaking Changes + +### 1. `Request.Body` is now an interface + +**Before:** + +```java +// Body was a concrete class with public fields/methods +Request.Body body = Request.Body.create("hello", StandardCharsets.UTF_8); +byte[] bytes = body.asBytes(); +String str = body.asString(); +int len = body.length(); +Optional charset = body.getEncoding(); +boolean binary = body.isBinary(); +``` + +**After:** + +```java +// Body is now an interface — use the factory methods +Request.Body body = Request.Body.of("hello", StandardCharsets.UTF_8); + +// To read content, write it to a stream (note: these methods throw checked IOException): +byte[] bytes = body.writeToByteArray(); +String str = body.writeToString(StandardCharsets.UTF_8); +long len = body.contentLength(); // -1 if unknown/streaming +boolean repeatable = body.isRepeatable(); +``` + +**Removed methods on `Request.Body`:** + +| Removed | Replacement | +|---------------------------------|---------------------------------------------------------------------------------------| +| `Body.create(String)` | `Body.of(String)` | +| `Body.create(String, Charset)` | `Body.of(String, Charset)` | +| `Body.create(byte[])` | `Body.of(byte[])` | +| `Body.create(byte[], Charset)` | `Body.of(byte[], Charset)` | +| `Body.encoded(byte[], Charset)` | `Body.of(byte[], Charset)` | +| `Body.empty()` | Pass `null` for no body | +| `body.asBytes()` | `body.writeToByteArray()` | +| `body.asString()` | `body.writeToString(charset)` | +| `body.length()` → `int` | `body.contentLength()` → `long` (returns `-1` if unknown) | +| `body.getEncoding()` | Read charset from `Content-Type` header | +| `body.isBinary()` | No direct replacement; `body.isRepeatable()` may be useful depending on your use case | + +--- + +### 2. `Request.body()` now returns `Optional` + +**Before:** + +```java +byte[] body = request.body(); // nullable byte[] +if (body != null) { + out.write(body); +} +``` + +**After:** + +```java +// writeTo(OutputStream) throws checked IOException, so a plain Consumer lambda +// (as used in Optional.ifPresent) cannot propagate it. Use an explicit if-block instead. +Optional body = request.body(); +if (body.isPresent()) { + body.get().writeTo(out); +} +``` + +--- + +### 3. `Request.length()` removed + +**Before:** + +```java +int length = request.length(); +``` + +**After:** + +```java +// contentLength() does not throw, so Optional.map is safe here. +long length = request.body() + .map(Request.Body::contentLength) + .orElse(0L); +``` + +--- + +### 4. `Request.charset()` removed + +**Before:** + +```java +Charset charset = request.charset(); +``` + +**After:** Read the charset from the `Content-Type` request header. There is no longer a charset field on `Request` +itself. + +--- + +### 5. `Request.isBinary()` removed + +**Before:** + +```java +boolean binary = request.isBinary(); +``` + +**After:** + +```java +// There is no direct replacement for request.isBinary(). +// Depending on why you were checking it, request body repeatability may be useful: +boolean repeatable = request.body() + .map(Request.Body::isRepeatable) + .orElse(false); +``` + +--- + +### 6. `Request.create(...)` overloads removed + +The `byte[]` + `Charset`-based `Request.create(...)` overloads have been removed. + +**Before:** + +```java +Request.create(HttpMethod.GET, url, headers, bodyBytes, charset); +Request.create(HttpMethod.GET, url, headers, bodyBytes, charset, requestTemplate); +// Deprecated String-based variant: +Request.create("GET", url, headers, bodyBytes, charset); +``` + +**After:** + +```java +// With a body: +Request.create(HttpMethod.GET, url, headers, Request.Body.of(bodyBytes), requestTemplate); + +// Without a body: +Request.create(HttpMethod.GET, url, headers, null, null); +``` + +--- + +### 7. `RequestTemplate` API changes + +#### `RequestTemplate.body(String)` removed + +**Before:** + +```java +template.body("hello world"); +``` + +**After:** + +```java +template.body(Request.Body.of("hello world")); +``` + +#### `RequestTemplate.body(byte[], Charset)` deprecated + +**Before:** + +```java +template.body(bytes, StandardCharsets.UTF_8); +``` + +**After:** + +```java +template.body(Request.Body.of(bytes, StandardCharsets.UTF_8)); +// or, if charset is irrelevant for your use case: +template.body(Request.Body.of(bytes)); +``` + +#### `RequestTemplate.body()` (returns `byte[]`) removed + +**Before:** + +```java +byte[] body = template.body(); +``` + +**After:** + +```java +// writeToByteArray() throws checked IOException, so a plain Function lambda +// (as used in Optional.map) cannot propagate it. Use an explicit if-block instead. +byte[] body = null; +Optional requestBody = template.requestBody(); +if (requestBody.isPresent()) { + body = requestBody.get().writeToByteArray(); +} +``` + +#### `RequestTemplate.requestBody()` is no longer `@Deprecated` + +The method now returns `Optional` and is the primary accessor. + +#### `RequestTemplate.requestCharset()` removed + +**Before:** + +```java +Charset charset = template.requestCharset(); +``` + +**After:** Read charset from the `Content-Type` header. There is no longer a charset tracked on the template itself. + +--- + +### 8. Custom `Encoder` implementations + +If you implement a custom `Encoder`, update calls to `template.body(...)`: + +**Before:** + +```java +template.body(serialized.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); +// or +template.body(serialized); +``` + +**After:** + +```java +template.body(Request.Body.of(serialized, StandardCharsets.UTF_8)); +// or, for UTF-8 strings: +template.body(Request.Body.of(serialized)); +``` + +--- + +### 9. Custom `Client` implementations + +If you implement a custom `Client`, update how you write the request body: + +**Before:** + +```java +byte[] body = request.body(); +if (body != null) { + outputStream.write(body); +} +``` + +**After:** + +```java +// writeTo(OutputStream) throws checked IOException, so a plain Consumer lambda +// (as used in Optional.ifPresent) cannot propagate it. Use an explicit if-block instead. +Optional body = request.body(); +if (body.isPresent()) { + body.get().writeTo(outputStream); +} +``` + +For retry-capable clients, check `body.isRepeatable()` before attempting a retry — non-repeatable (streaming) bodies +cannot be re-sent. + +--- + +### 10. `FeignException.errorReading(...)` — request body no longer captured + +`FeignException` no longer captures the request body when a read error occurs, because the body may be a non-repeatable +stream. Code asserting `exception.contentUTF8()` returns the request body must be updated: + +**Before:** + +```java +assertThat(exception.contentUTF8()).isEqualTo("Request body"); +``` + +**After:** + +```java +assertThat(exception.contentUTF8()).isEmpty(); +``` + +--- + +### 11. `mock` module — `RequestKey` no longer stores `Charset` + +**Before:** + +```java +RequestKey.builder(...).charset(StandardCharsets.UTF_8).build(); +``` + +**After:** The `charset(Charset)` method has been removed from `RequestKey.Builder`. Remove it from your mock setup +code. + +--- + +### 12. `Request.Body` no longer implements `Serializable` + +`feign.Request.Body` previously implemented `java.io.Serializable`. This has been removed. +If you were serializing `Request.Body` objects (e.g., for caching or distributed tracing), you will need an alternative +serialization strategy. + +--- + +### 13. Vert.x integration — `VertxFeign.Builder` now requires `.vertx(Vertx)` + +**Before:** + +```java +VertxFeign.builder() + .webClient(webClient) + .target(MyApi.class, url); +``` + +**After:** + +```java +VertxFeign.builder() + .vertx(vertx) // required — NPE with descriptive message if missing + .webClient(webClient) + .target(MyApi.class, url); +``` + +--- + +## Implementing a Custom Streaming Body + +If you want to stream a body (e.g., from a file or `InputStream`), implement `Request.Body` directly. Because +`writeTo(OutputStream)` itself declares `throws IOException`, the lambda **can** propagate it freely — the restriction +only applies to standard functional interfaces (`Consumer`, `Function`, etc.) that don't +declare checked exceptions. + +```java +// One-shot InputStream — non-repeatable (isRepeatable() defaults to false) +Request.Body streamingBody = outputStream -> { + try (InputStream in = Files.newInputStream(path)) { + byte[] buffer = new byte[8192]; + int read; + while ((read = in.read(buffer)) != -1) { + outputStream.write(buffer, 0, read); + } + // or, with Java 9+: + // in.transferTo(outputStream); + } + // IOException propagates naturally — no try-catch needed here +}; +template.body(streamingBody); +``` + +For a repeatable streaming body (e.g., backed by a file that can be re-read): + +```java +public class FileBody implements Request.Body { + private final Path path; + + public FileBody(Path path) { + this.path = path; + } + + @Override + public void writeTo(OutputStream out) throws IOException { + try (InputStream in = Files.newInputStream(path)) { + byte[] buffer = new byte[8192]; + int read; + while ((read = in.read(buffer)) != -1) { + out.write(buffer, 0, read); + } + // or, with Java 9+: + // in.transferTo(out); + } + } + + @Override + public boolean isRepeatable() { + return true; + } + + @Override + public long contentLength() { + try { + return Files.size(path); + } catch (IOException e) { + return super.contentLength(); // returns -1 + } + } +} +``` + +--- + +## Spring Cloud OpenFeign Compatibility + +`RequestTemplate#body(byte[], Charset)` is kept `@Deprecated` for backward compatibility with +`spring-cloud-openfeign-core`. Spring Cloud OpenFeign users are not required to make any changes immediately, but should +migrate to `body(Request.Body)` once the Spring team provides an updated release. diff --git a/annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java b/annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java index 2d2c0fe74b..23d5f317b4 100644 --- a/annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java +++ b/annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java @@ -45,9 +45,7 @@ class ExceptionGenerator { .status(500) .body((Response.Body) null) .headers(testHeaders) - .request( - Request.create( - Request.HttpMethod.GET, "http://test", testHeaders, Request.Body.empty(), null)) + .request(Request.create(Request.HttpMethod.GET, "http://test", testHeaders, null, null)) .build(); } diff --git a/annotation-error-decoder/src/test/java/feign/error/AbstractAnnotationErrorDecoderTest.java b/annotation-error-decoder/src/test/java/feign/error/AbstractAnnotationErrorDecoderTest.java index e66a25a9f4..1d7375b30e 100644 --- a/annotation-error-decoder/src/test/java/feign/error/AbstractAnnotationErrorDecoderTest.java +++ b/annotation-error-decoder/src/test/java/feign/error/AbstractAnnotationErrorDecoderTest.java @@ -45,9 +45,7 @@ Response testResponse(int status, String body, Map> h .status(status) .body(body, StandardCharsets.UTF_8) .headers(headers) - .request( - Request.create( - Request.HttpMethod.GET, "http://test", headers, Request.Body.empty(), null)) + .request(Request.create(Request.HttpMethod.GET, "http://test", headers, null, null)) .build(); } } diff --git a/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java b/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java index 9728a46f5e..82f0d9231c 100644 --- a/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java +++ b/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java @@ -17,7 +17,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import feign.Request; import feign.codec.DefaultDecoder; import feign.error.AnnotationErrorDecoderExceptionConstructorsTest.TestClientInterfaceWithDifferentExceptionConstructors; import feign.error.AnnotationErrorDecoderExceptionConstructorsTest.TestClientInterfaceWithDifferentExceptionConstructors.DeclaredDefaultConstructorException; @@ -56,11 +55,7 @@ public class AnnotationErrorDecoderExceptionConstructorsTest private static final String NON_NULL_BODY = "A GIVEN BODY"; private static final feign.Request REQUEST = feign.Request.create( - feign.Request.HttpMethod.GET, - "http://test", - Collections.emptyMap(), - Request.Body.empty(), - null); + feign.Request.HttpMethod.GET, "http://test", Collections.emptyMap(), null, null); private static final feign.Request NO_REQUEST = null; private static final Map> NON_NULL_HEADERS = new HashMap<>(); private static final Map> NO_HEADERS = null; diff --git a/benchmark/src/main/java/feign/benchmark/DecoderIteratorsBenchmark.java b/benchmark/src/main/java/feign/benchmark/DecoderIteratorsBenchmark.java index 76fbc1e1b3..ebe9ad7188 100644 --- a/benchmark/src/main/java/feign/benchmark/DecoderIteratorsBenchmark.java +++ b/benchmark/src/main/java/feign/benchmark/DecoderIteratorsBenchmark.java @@ -82,7 +82,7 @@ public void buildResponse() { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(carsJson(Integer.parseInt(size)), Util.UTF_8) .build(); diff --git a/core/src/main/java/feign/DefaultClient.java b/core/src/main/java/feign/DefaultClient.java index d8e02fb4ad..ec0df4644b 100644 --- a/core/src/main/java/feign/DefaultClient.java +++ b/core/src/main/java/feign/DefaultClient.java @@ -32,6 +32,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.TreeMap; import java.util.zip.DeflaterOutputStream; import java.util.zip.GZIPInputStream; @@ -187,9 +188,9 @@ else if (field.equals(ACCEPT_ENCODING)) { connection.addRequestProperty("Accept", "*/*"); } - byte[] body = request.body(); + Optional body = request.body(); - if (body != null) { + if (body.isPresent()) { /* * Ignore disableRequestBuffering flag if the empty body was set, to ensure that internal * retry logic applies to such requests. @@ -209,7 +210,7 @@ else if (field.equals(ACCEPT_ENCODING)) { out = new DeflaterOutputStream(out); } try { - out.write(body); + body.get().writeTo(out); } finally { try { out.close(); @@ -218,7 +219,7 @@ else if (field.equals(ACCEPT_ENCODING)) { } } - if (body == null && request.httpMethod().isWithBody()) { + if (!body.isPresent() && request.httpMethod().isWithBody()) { // To use this Header, set 'sun.net.http.allowRestrictedHeaders' property true. connection.addRequestProperty("Content-Length", "0"); } diff --git a/core/src/main/java/feign/DefaultContract.java b/core/src/main/java/feign/DefaultContract.java index 79edadde82..a59b1183c9 100644 --- a/core/src/main/java/feign/DefaultContract.java +++ b/core/src/main/java/feign/DefaultContract.java @@ -76,7 +76,7 @@ public DefaultContract() { "Body annotation was empty on method %s.", data.configKey()); if (body.indexOf('{') == -1) { - data.template().body(body); + data.template().body(Request.Body.of(body)); } else { data.template().bodyTemplate(body); } diff --git a/core/src/main/java/feign/FeignException.java b/core/src/main/java/feign/FeignException.java index b7ea794cae..f053591c96 100644 --- a/core/src/main/java/feign/FeignException.java +++ b/core/src/main/java/feign/FeignException.java @@ -15,7 +15,9 @@ */ package feign; -import static feign.Util.*; +import static feign.Util.UTF_8; +import static feign.Util.caseInsensitiveCopyOf; +import static feign.Util.checkNotNull; import static java.lang.String.format; import static java.util.regex.Pattern.CASE_INSENSITIVE; @@ -182,7 +184,7 @@ static FeignException errorReading(Request request, Response response, IOExcepti format("%s reading %s %s", cause.getMessage(), request.httpMethod(), request.url()), request, cause, - request.body(), + null, request.headers()); } diff --git a/core/src/main/java/feign/Logger.java b/core/src/main/java/feign/Logger.java index a460251a6a..ae297d3861 100644 --- a/core/src/main/java/feign/Logger.java +++ b/core/src/main/java/feign/Logger.java @@ -78,16 +78,18 @@ protected void logRequest(String configKey, Level logLevel, Request request) { } } - int bodyLength = 0; - if (request.body() != null) { - bodyLength = request.length(); - if (logLevel.ordinal() >= Level.FULL.ordinal()) { - String bodyText = - request.charset() != null ? new String(request.body(), request.charset()) : null; - log(configKey, ""); // CRLF - log(configKey, "%s", bodyText != null ? bodyText : "Binary data"); - } - } + long bodyLength = + request + .body() + .map( + body -> { + if (logLevel.ordinal() >= Level.FULL.ordinal()) { + log(configKey, ""); // CRLF + log(configKey, "%s", body.toString()); + } + return body.contentLength(); + }) + .orElse(0L); log(configKey, "---> END HTTP (%s-byte body)", bodyLength); } } diff --git a/core/src/main/java/feign/Request.java b/core/src/main/java/feign/Request.java index a3627a164d..00ff8ad039 100644 --- a/core/src/main/java/feign/Request.java +++ b/core/src/main/java/feign/Request.java @@ -19,150 +19,30 @@ import static feign.Util.getThreadIdentifier; import static feign.Util.valuesOrEmpty; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.io.Serializable; import java.net.HttpURLConnection; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; /** An immutable request to an http server. */ public final class Request implements Serializable { - - public enum HttpMethod { - GET, - HEAD, - POST(true), - PUT(true), - DELETE, - CONNECT, - OPTIONS, - TRACE, - PATCH(true); - - private final boolean withBody; - - HttpMethod() { - this(false); - } - - HttpMethod(boolean withBody) { - this.withBody = withBody; - } - - public boolean isWithBody() { - return this.withBody; - } - } - - public enum ProtocolVersion { - HTTP_1_0("HTTP/1.0"), - HTTP_1_1("HTTP/1.1"), - HTTP_2("HTTP/2.0"), - MOCK; - - final String protocolVersion; - - ProtocolVersion() { - protocolVersion = name(); - } - - ProtocolVersion(String protocolVersion) { - this.protocolVersion = protocolVersion; - } - - @Override - public String toString() { - return protocolVersion; - } - } - - /** - * No parameters can be null except {@code body} and {@code charset}. All parameters must be - * effectively immutable, via safe copies, not mutating or otherwise. - * - * @deprecated {@link #create(HttpMethod, String, Map, byte[], Charset)} - */ - @Deprecated - public static Request create( - String method, - String url, - Map> headers, - byte[] body, - Charset charset) { - checkNotNull(method, "httpMethod of %s", method); - final HttpMethod httpMethod = HttpMethod.valueOf(method.toUpperCase()); - return create(httpMethod, url, headers, body, charset, null); - } - - /** - * Builds a Request. All parameters must be effectively immutable, via safe copies. - * - * @param httpMethod for the request. - * @param url for the request. - * @param headers to include. - * @param body of the request, can be {@literal null} - * @param charset of the request, can be {@literal null} - * @return a Request - */ - @Deprecated - public static Request create( - HttpMethod httpMethod, - String url, - Map> headers, - byte[] body, - Charset charset) { - return create(httpMethod, url, headers, Body.create(body, charset), null); - } - - /** - * Builds a Request. All parameters must be effectively immutable, via safe copies. - * - * @param httpMethod for the request. - * @param url for the request. - * @param headers to include. - * @param body of the request, can be {@literal null} - * @param charset of the request, can be {@literal null} - * @return a Request - */ - public static Request create( - HttpMethod httpMethod, - String url, - Map> headers, - byte[] body, - Charset charset, - RequestTemplate requestTemplate) { - return create(httpMethod, url, headers, Body.create(body, charset), requestTemplate); - } - - /** - * Builds a Request. All parameters must be effectively immutable, via safe copies. - * - * @param httpMethod for the request. - * @param url for the request. - * @param headers to include. - * @param body of the request, can be {@literal null} - * @return a Request - */ - public static Request create( - HttpMethod httpMethod, - String url, - Map> headers, - Body body, - RequestTemplate requestTemplate) { - return new Request(httpMethod, url, headers, body, requestTemplate); - } - private final HttpMethod httpMethod; private final String url; private final Map> headers; - private final Body body; + private final transient Body body; private final RequestTemplate requestTemplate; private final ProtocolVersion protocolVersion; @@ -190,41 +70,40 @@ public static Request create( } /** - * Http Method for this request. + * Builds a Request. All parameters must be effectively immutable, via safe copies. * - * @return the HttpMethod string - * @deprecated @see {@link #httpMethod()} + * @param httpMethod for the request. + * @param url for the request. + * @param headers to include. + * @param body of the request, can be {@literal null} + * @return a Request */ - @Deprecated - public String method() { - return httpMethod.name(); + public static Request create( + HttpMethod httpMethod, + String url, + Map> headers, + Body body, + RequestTemplate requestTemplate) { + return new Request(httpMethod, url, headers, body, requestTemplate); } /** - * Http Method for the request. + * Returns the body of the request, if any. * - * @return the HttpMethod. + * @return the body of the request, if any */ - public HttpMethod httpMethod() { - return this.httpMethod; + public Optional body() { + return Optional.ofNullable(body); } /** - * URL for the request. - * - * @return URL as a String. - */ - public String url() { - return url; - } - - /** - * Request Headers. + * Add new entries to request Headers. It overrides existing entries * - * @return the request headers. + * @param key + * @param values */ - public Map> headers() { - return Collections.unmodifiableMap(headers); + public void header(String key, Collection values) { + headers.put(key, values); } /** @@ -238,54 +117,44 @@ public void header(String key, String value) { } /** - * Add new entries to request Headers. It overrides existing entries + * Request Headers. * - * @param key - * @param values + * @return the request headers. */ - public void header(String key, Collection values) { - headers.put(key, values); + public Map> headers() { + return Collections.unmodifiableMap(headers); } /** - * Charset of the request. + * Http Method for the request. * - * @return the current character set for the request, may be {@literal null} for binary data. + * @return the HttpMethod. */ - public Charset charset() { - return body.encoding; + public HttpMethod httpMethod() { + return this.httpMethod; } /** - * If present, this is the replayable body to send to the server. In some cases, this may be - * interpretable as text. + * Request HTTP protocol version * - * @see #charset() + * @return HTTP protocol version */ - public byte[] body() { - return body.data; - } - - public boolean isBinary() { - return body.isBinary(); + public ProtocolVersion protocolVersion() { + return protocolVersion; } - /** - * Request Length. - * - * @return size of the request body. - */ - public int length() { - return this.body.length(); + @Experimental + public RequestTemplate requestTemplate() { + return this.requestTemplate; } /** - * Request HTTP protocol version + * URL for the request. * - * @return HTTP protocol version + * @return URL as a String. */ - public ProtocolVersion protocolVersion() { - return protocolVersion; + public String url() { + return url; } /** @@ -309,52 +178,186 @@ public String toString() { } } if (body != null) { - builder.append('\n').append(body.asString()); + builder.append('\n').append(body); } return builder.toString(); } + public enum HttpMethod { + GET, + HEAD, + POST(true), + PUT(true), + DELETE, + CONNECT, + OPTIONS, + TRACE, + PATCH(true); + + private final boolean withBody; + + HttpMethod() { + this(false); + } + + HttpMethod(boolean withBody) { + this.withBody = withBody; + } + + public boolean isWithBody() { + return this.withBody; + } + } + + public enum ProtocolVersion { + HTTP_1_0("HTTP/1.0"), + HTTP_1_1("HTTP/1.1"), + HTTP_2("HTTP/2.0"), + MOCK; + + final String protocolVersion; + + ProtocolVersion() { + protocolVersion = name(); + } + + ProtocolVersion(String protocolVersion) { + this.protocolVersion = protocolVersion; + } + + @Override + public String toString() { + return protocolVersion; + } + } + /** - * Controls the per-request settings currently required to be implemented by all {@link Client - * clients} + * Request Body + * + *

Considered experimental, will most likely be made internal going forward. */ - public static class Options { + @Experimental + @FunctionalInterface + public interface Body { + /** + * Creates a new {@link Body} instance from the provided string content. + * + * @param content the string content to be used as the body of the request + * @return a new {@link Body} instance containing the provided string content + * @apiNote It's assumed that the content was constructed using {@link StandardCharsets#UTF_8} + * charset. + */ + static Body of(String content) { + return of(content, StandardCharsets.UTF_8); + } - private final long connectTimeout; - private final TimeUnit connectTimeoutUnit; - private final long readTimeout; - private final TimeUnit readTimeoutUnit; - private final boolean followRedirects; - private final Map> threadToMethodOptions; + /** + * Creates a new {@link Body} instance from the provided byte array. + * + * @param content the byte array representing the body content + * @return a new {@link Body} instance + * @apiNote It's assumed that the byte array can be converted to a string using {@link + * StandardCharsets#UTF_8} charset. + */ + static Body of(byte[] content) { + return of(content, StandardCharsets.UTF_8); + } /** - * Get an Options by methodName + * Creates a new {@link Body} instance from the provided string content, using the specified + * charset. * - * @param methodName it's your FeignInterface method name. - * @return method Options + * @param content the string content to be used as the body content + * @param charset the content charset + * @return a new {@link Body} instance containing the provided content */ - @Experimental - public Options getMethodOptions(String methodName) { - Map methodOptions = - threadToMethodOptions.getOrDefault(getThreadIdentifier(), new HashMap<>()); - return methodOptions.getOrDefault(methodName, this); + static Body of(String content, Charset charset) { + Objects.requireNonNull(content, "content is required"); + Objects.requireNonNull(charset, "charset is required"); + + return of(content.getBytes(charset), charset); } /** - * Set methodOptions by methodKey and options + * Creates a new {@link Body} instance from the provided byte array, using the specified + * charset. * - * @param methodName it's your FeignInterface method name. - * @param options it's the Options for this method. + * @param content the byte array representing the body content + * @param charset the content charset + * @return a new {@link Body} instance */ - @Experimental - public void setMethodOptions(String methodName, Options options) { - String threadIdentifier = getThreadIdentifier(); - Map methodOptions = - threadToMethodOptions.getOrDefault(threadIdentifier, new HashMap<>()); - threadToMethodOptions.put(threadIdentifier, methodOptions); - methodOptions.put(methodName, options); + static Body of(byte[] content, Charset charset) { + return new Request.BodyImpl(content, charset); + } + + /** + * Writes the body content to the provided {@link OutputStream}. + * + * @param outputStream the output stream to which the body content should be written + * @throws IOException if an I/O error occurs while writing the body content + */ + void writeTo(OutputStream outputStream) throws IOException; + + /** + * Writes the body content to a byte array. + * + * @return a byte array containing the body content + * @throws IOException if an I/O error occurs while writing the body content to a byte array + */ + default byte[] writeToByteArray() throws IOException { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + writeTo(outputStream); + return outputStream.toByteArray(); + } } + /** + * Writes the body content to a string using the specified charset for decoding. + * + * @param charset the charset to be used for decoding the body content + * @return a string representation of the body content + * @throws IOException if an I/O error occurs while writing the body content to a string + */ + default String writeToString(Charset charset) throws IOException { + Objects.requireNonNull(charset, "charset is required"); + return new String(writeToByteArray(), charset); + } + + /** + * Returns the content length of the body, or {@code -1} if unknown. This can be used by clients + * to set the {@code Content-Length} header. Defaults to {@code -1}. + * + * @return the content length, or {@code -1} if unknown + */ + default long contentLength() { + return -1; + } + + /** + * Indicates whether the body can be written multiple times. This is important for clients that + * may need to retry requests, as non-repeatable bodies (e.g., streaming data) cannot be + * re-sent. Defaults to {@code false}. + * + * @return {@code true} if the body can be written multiple times, {@code false} otherwise + */ + default boolean isRepeatable() { + return false; + } + } + + /** + * Controls the per-request settings currently required to be implemented by all {@link Client + * clients} + */ + public static class Options { + + private final long connectTimeout; + private final TimeUnit connectTimeoutUnit; + private final long readTimeout; + private final TimeUnit readTimeoutUnit; + private final boolean followRedirects; + private final Map> threadToMethodOptions; + /** * Creates a new Options instance. * @@ -439,48 +442,52 @@ public Options() { } /** - * Defaults to 10 seconds. {@code 0} implies no timeout. + * Connect Timeout Value. * - * @see java.net.HttpURLConnection#getConnectTimeout() + * @return current timeout value. */ - public int connectTimeoutMillis() { - return (int) connectTimeoutUnit.toMillis(connectTimeout); + public long connectTimeout() { + return connectTimeout; } /** - * Defaults to 60 seconds. {@code 0} implies no timeout. + * Defaults to 10 seconds. {@code 0} implies no timeout. * - * @see java.net.HttpURLConnection#getReadTimeout() + * @see java.net.HttpURLConnection#getConnectTimeout() */ - public int readTimeoutMillis() { - return (int) readTimeoutUnit.toMillis(readTimeout); + public int connectTimeoutMillis() { + return (int) connectTimeoutUnit.toMillis(connectTimeout); } /** - * Defaults to true. {@code false} tells the client to not follow the redirections. + * TimeUnit for the Connection Timeout value. * - * @see HttpURLConnection#getFollowRedirects() + * @return TimeUnit */ - public boolean isFollowRedirects() { - return followRedirects; + public TimeUnit connectTimeoutUnit() { + return connectTimeoutUnit; } /** - * Connect Timeout Value. + * Get an Options by methodName * - * @return current timeout value. + * @param methodName it's your FeignInterface method name. + * @return method Options */ - public long connectTimeout() { - return connectTimeout; + @Experimental + public Options getMethodOptions(String methodName) { + Map methodOptions = + threadToMethodOptions.getOrDefault(getThreadIdentifier(), new HashMap<>()); + return methodOptions.getOrDefault(methodName, this); } /** - * TimeUnit for the Connection Timeout value. + * Defaults to true. {@code false} tells the client to not follow the redirections. * - * @return TimeUnit + * @see HttpURLConnection#getFollowRedirects() */ - public TimeUnit connectTimeoutUnit() { - return connectTimeoutUnit; + public boolean isFollowRedirects() { + return followRedirects; } /** @@ -492,6 +499,15 @@ public long readTimeout() { return readTimeout; } + /** + * Defaults to 60 seconds. {@code 0} implies no timeout. + * + * @see java.net.HttpURLConnection#getReadTimeout() + */ + public int readTimeoutMillis() { + return (int) readTimeoutUnit.toMillis(readTimeout); + } + /** * TimeUnit for the Read Timeout value. * @@ -500,91 +516,50 @@ public long readTimeout() { public TimeUnit readTimeoutUnit() { return readTimeoutUnit; } - } - - @Experimental - public RequestTemplate requestTemplate() { - return this.requestTemplate; - } - - /** - * Request Body - * - *

Considered experimental, will most likely be made internal going forward. - */ - @Experimental - public static class Body implements Serializable { - - private transient Charset encoding; - - private byte[] data; - - private Body() { - super(); - } - - private Body(byte[] data) { - this.data = data; - } - private Body(byte[] data, Charset encoding) { - this.data = data; - this.encoding = encoding; - } - - public Optional getEncoding() { - return Optional.ofNullable(this.encoding); - } - - public int length() { - /* calculate the content length based on the data provided */ - return data != null ? data.length : 0; - } - - public byte[] asBytes() { - return data; - } - - public String asString() { - return !isBinary() ? new String(data, encoding) : "Binary data"; - } - - public boolean isBinary() { - return encoding == null || data == null; + /** + * Set methodOptions by methodKey and options + * + * @param methodName it's your FeignInterface method name. + * @param options it's the Options for this method. + */ + @Experimental + public void setMethodOptions(String methodName, Options options) { + String threadIdentifier = getThreadIdentifier(); + Map methodOptions = + threadToMethodOptions.getOrDefault(threadIdentifier, new HashMap<>()); + threadToMethodOptions.put(threadIdentifier, methodOptions); + methodOptions.put(methodName, options); } + } - public static Body create(String data) { - return new Body(data.getBytes()); - } + private static class BodyImpl implements Body { + private final byte[] content; + private final Charset charset; - public static Body create(String data, Charset charset) { - return new Body(data.getBytes(charset), charset); + private BodyImpl(byte[] content, Charset charset) { + this.content = Objects.requireNonNull(content, "content must not be null"); + this.charset = Objects.requireNonNull(charset, "charset must not be null"); } - public static Body create(byte[] data) { - return new Body(data); + @Override + public void writeTo(OutputStream outputStream) throws IOException { + Objects.requireNonNull(outputStream, "outputStream is required").write(content); } - public static Body create(byte[] data, Charset charset) { - return new Body(data, charset); + @Override + public long contentLength() { + return content.length; } - /** - * Creates a new Request Body with charset encoded data. - * - * @param data to be encoded. - * @param charset to encode the data with. if {@literal null}, then data will be considered - * binary and will not be encoded. - * @return a new Request.Body instance with the encoded data. - * @deprecated please use {@link Request.Body#create(byte[], Charset)} - */ - @Deprecated - public static Body encoded(byte[] data, Charset charset) { - return create(data, charset); + @Override + public boolean isRepeatable() { + return true; } - public static Body empty() { - return new Body(); + @Override + public String toString() { + return new String(content, charset); } } } diff --git a/core/src/main/java/feign/RequestTemplate.java b/core/src/main/java/feign/RequestTemplate.java index 5ac205e6dd..2f767d067f 100644 --- a/core/src/main/java/feign/RequestTemplate.java +++ b/core/src/main/java/feign/RequestTemplate.java @@ -38,6 +38,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -62,7 +63,7 @@ public final class RequestTemplate implements Serializable { private BodyTemplate bodyTemplate; private HttpMethod method; private transient Charset charset = Util.UTF_8; - private Request.Body body = Request.Body.empty(); + private transient Request.Body body; private boolean decodeSlash = true; private CollectionFormat collectionFormat = CollectionFormat.EXPLODED; private MethodMetadata methodMetadata; @@ -253,7 +254,7 @@ public RequestTemplate resolve(Map variables) { } if (this.bodyTemplate != null) { - resolved.body(this.bodyTemplate.expand(variables)); + resolved.body(Request.Body.of(this.bodyTemplate.expand(variables))); } /* mark the new template resolved */ @@ -865,22 +866,14 @@ public Map> headers() { * Sets the Body and Charset for this request. * * @param data to send, can be null. - * @param charset of the encoded data. + * @param ignoredCharset of the encoded data. * @return a RequestTemplate for chaining. + * @deprecated this method is kept to maintain compatibility with {@code + * spring-cloud-openfeign-core}. Please use {@link #body(Request.Body)} instead. */ - public RequestTemplate body(byte[] data, Charset charset) { - this.body(Request.Body.create(data, charset)); - return this; - } - - /** - * Set the Body for this request. Charset is assumed to be UTF_8. Data must be encoded. - * - * @param bodyText to send. - * @return a RequestTemplate for chaining. - */ - public RequestTemplate body(String bodyText) { - this.body(Request.Body.create(bodyText.getBytes(this.charset), this.charset)); + @Deprecated + public RequestTemplate body(byte[] data, Charset ignoredCharset) { + this.body(Request.Body.of(data)); return this; } @@ -889,53 +882,30 @@ public RequestTemplate body(String bodyText) { * * @param body to send. * @return a RequestTemplate for chaining. - * @deprecated use {@link #body(byte[], Charset)} instead. */ - @Deprecated public RequestTemplate body(Request.Body body) { this.body = body; /* body template must be cleared to prevent double processing */ this.bodyTemplate = null; - header(CONTENT_LENGTH, Collections.emptyList()); - if (body.length() > 0) { - header(CONTENT_LENGTH, String.valueOf(body.length())); + /* reset any prior Content-Length so it cannot be duplicated or left stale */ + this.header(CONTENT_LENGTH, Collections.emptyList()); + if (body.contentLength() >= 0) { + this.header(CONTENT_LENGTH, String.valueOf(body.contentLength())); } return this; } - /** - * Charset of the Request Body, if known. - * - * @return the currently applied Charset. - */ - public Charset requestCharset() { - if (this.body != null) { - return this.body.getEncoding().orElse(this.charset); - } - return this.charset; - } - - /** - * The Request Body. - * - * @return the request body. - */ - public byte[] body() { - return body.asBytes(); - } - /** * The Request.Body internal object. * * @return the internal Request.Body. * @deprecated this abstraction is leaky and will be removed in later releases. */ - @Deprecated - public Request.Body requestBody() { - return this.body; + public Optional requestBody() { + return Optional.ofNullable(this.body); } /** diff --git a/core/src/main/java/feign/codec/DefaultEncoder.java b/core/src/main/java/feign/codec/DefaultEncoder.java index 39a0f8daba..a32cf2065a 100644 --- a/core/src/main/java/feign/codec/DefaultEncoder.java +++ b/core/src/main/java/feign/codec/DefaultEncoder.java @@ -17,6 +17,7 @@ import static java.lang.String.format; +import feign.Request; import feign.RequestTemplate; import java.lang.reflect.Type; @@ -25,9 +26,9 @@ public class DefaultEncoder implements Encoder { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { if (bodyType == String.class) { - template.body(object.toString()); + template.body(Request.Body.of(object.toString())); } else if (bodyType == byte[].class) { - template.body((byte[]) object, null); + template.body(Request.Body.of((byte[]) object)); } else if (object != null) { throw new EncodeException( format("%s is not a type supported by this encoder.", object.getClass())); diff --git a/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java b/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java index 7a626d6ef0..a3100d882d 100644 --- a/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java +++ b/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java @@ -17,6 +17,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -65,7 +66,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) Object[] methodParameters = (Object[]) object; String body = Arrays.stream(methodParameters).map(String::valueOf).collect(Collectors.joining()); - template.body(body); + template.body(Request.Body.of(body)); } } @@ -73,14 +74,22 @@ private static class BodyParameterSampleEncoder implements Encoder { @Override public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { - template.body(String.valueOf(object)); + template.body(Request.Body.of(String.valueOf(object))); } } private static class SampleClient implements Client { @Override public Response execute(Request request, Request.Options options) throws IOException { - return Response.builder().status(200).request(request).body(request.body()).build(); + return Response.builder() + .status(200) + .request(request) + .body(request.body().map(this::bodyAsBytes).orElse(null)) + .build(); + } + + private byte[] bodyAsBytes(Request.Body body) { + return assertDoesNotThrow(body::writeToByteArray); } } diff --git a/core/src/test/java/feign/AsyncFeignTest.java b/core/src/test/java/feign/AsyncFeignTest.java index efd965632e..08c70f19c4 100644 --- a/core/src/test/java/feign/AsyncFeignTest.java +++ b/core/src/test/java/feign/AsyncFeignTest.java @@ -18,7 +18,6 @@ import static feign.ExceptionPropagationPolicy.UNWRAP; import static feign.Util.UTF_8; import static feign.assertj.MockWebServerAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; @@ -584,7 +583,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (FeignException e) { assertThat(e.getMessage()) .contains("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + assertThat(e.contentUTF8()).isEmpty(); return; } fail(""); @@ -699,7 +698,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); @@ -970,7 +969,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(new HashMap<>()) .build(); } @@ -1227,9 +1226,9 @@ static final class TestInterfaceAsyncBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(new Gson().toJson(object)); + template.body(Request.Body.of(new Gson().toJson(object))); } else { - template.body(object.toString()); + template.body(Request.Body.of(object.toString())); } }); diff --git a/core/src/test/java/feign/ClientTest.java b/core/src/test/java/feign/ClientTest.java index cdfe54d292..c094cadabf 100644 --- a/core/src/test/java/feign/ClientTest.java +++ b/core/src/test/java/feign/ClientTest.java @@ -61,13 +61,12 @@ void testConvertAndSendWithAcceptEncoding() throws IOException { headers.put(Util.ACCEPT_ENCODING, acceptEncoding); RequestTemplate requestTemplate = mock(RequestTemplate.class); - Request.Body body = mock(Request.Body.class); Request.Options options = mock(Request.Options.class); Client client = mock(Client.class); Request request = Request.create( - Request.HttpMethod.GET, "http://example.com", headers, body, requestTemplate); + Request.HttpMethod.GET, "http://example.com", headers, null, requestTemplate); DefaultClient defaultClient = new DefaultClient(null, null); HttpURLConnection urlConnection = defaultClient.convertAndSend(request, options); Map> requestProperties = urlConnection.getRequestProperties(); @@ -82,13 +81,12 @@ void testConvertAndSendWithContentLength() throws IOException { headers.put(Util.CONTENT_LENGTH, Collections.singletonList("100")); RequestTemplate requestTemplate = mock(RequestTemplate.class); - Request.Body body = mock(Request.Body.class); Request.Options options = mock(Request.Options.class); Client client = mock(Client.class); Request request = Request.create( - Request.HttpMethod.GET, "http://example.com", headers, body, requestTemplate); + Request.HttpMethod.GET, "http://example.com", headers, null, requestTemplate); DefaultClient defaultClient = new DefaultClient(null, null); HttpURLConnection urlConnection = defaultClient.convertAndSend(request, options); Map> requestProperties = urlConnection.getRequestProperties(); diff --git a/core/src/test/java/feign/DefaultContractTest.java b/core/src/test/java/feign/DefaultContractTest.java index 6b26d1ed0e..0ecf46f4ae 100644 --- a/core/src/test/java/feign/DefaultContractTest.java +++ b/core/src/test/java/feign/DefaultContractTest.java @@ -17,7 +17,6 @@ import static feign.assertj.FeignAssertions.assertThat; import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.MapEntry.entry; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -145,7 +144,15 @@ void headersOnMethodAddsContentTypeHeader() throws Exception { assertThat(md.template()) .hasHeaders( entry("Content-Type", asList("application/xml")), - entry("Content-Length", asList(String.valueOf(md.template().body().length)))); + entry( + "Content-Length", + asList( + md.template() + .requestBody() + .map(Request.Body::contentLength) + .filter(contentLength -> contentLength >= 0) + .map(String::valueOf) + .orElse("0")))); } @Test @@ -155,7 +162,15 @@ void headersOnTypeAddsContentTypeHeader() throws Exception { assertThat(md.template()) .hasHeaders( entry("Content-Type", asList("application/xml")), - entry("Content-Length", asList(String.valueOf(md.template().body().length)))); + entry( + "Content-Length", + asList( + md.template() + .requestBody() + .map(Request.Body::contentLength) + .filter(contentLength -> contentLength >= 0) + .map(String::valueOf) + .orElse("0")))); } @Test @@ -165,7 +180,15 @@ void headersContainsWhitespaces() throws Exception { assertThat(md.template()) .hasHeaders( entry("Content-Type", Collections.singletonList("application/xml")), - entry("Content-Length", asList(String.valueOf(md.template().body().length)))); + entry( + "Content-Length", + asList( + md.template() + .requestBody() + .map(Request.Body::contentLength) + .filter(contentLength -> contentLength >= 0) + .map(String::valueOf) + .orElse("0")))); } @Test diff --git a/core/src/test/java/feign/FeignBuilderTest.java b/core/src/test/java/feign/FeignBuilderTest.java index 2db2fd9df5..d9ff04604d 100644 --- a/core/src/test/java/feign/FeignBuilderTest.java +++ b/core/src/test/java/feign/FeignBuilderTest.java @@ -16,7 +16,6 @@ package feign; import static feign.assertj.MockWebServerAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; @@ -210,7 +209,7 @@ void overrideEncoder() throws Exception { server.enqueue(new MockResponse().setBody("response data")); String url = "http://localhost:" + server.getPort(); - Encoder encoder = (object, _, template) -> template.body(object.toString()); + Encoder encoder = (object, _, template) -> template.body(Request.Body.of(object.toString())); TestInterface api = Feign.builder().encoder(encoder).target(TestInterface.class, url); api.encodedPost(Arrays.asList("This", "is", "my", "request")); diff --git a/core/src/test/java/feign/FeignExceptionTest.java b/core/src/test/java/feign/FeignExceptionTest.java index f86d35fe19..660af75fcf 100644 --- a/core/src/test/java/feign/FeignExceptionTest.java +++ b/core/src/test/java/feign/FeignExceptionTest.java @@ -39,8 +39,7 @@ void canCreateWithRequestAndResponse() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - "data".getBytes(StandardCharsets.UTF_8), - StandardCharsets.UTF_8, + Request.Body.of("data".getBytes(StandardCharsets.UTF_8)), null); Response response = @@ -52,7 +51,7 @@ void canCreateWithRequestAndResponse() { FeignException exception = FeignException.errorReading(request, response, new IOException("socket closed")); - assertThat(exception.responseBody()).isNotEmpty(); + assertThat(exception.responseBody()).isEmpty(); assertThat(exception.hasRequest()).isTrue(); assertThat(exception.request()).isNotNull(); } @@ -64,14 +63,12 @@ void canCreateWithRequestOnly() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - "data".getBytes(StandardCharsets.UTF_8), - StandardCharsets.UTF_8, + Request.Body.of("data".getBytes(StandardCharsets.UTF_8)), null); FeignException exception = FeignException.errorExecuting(request, new IOException("connection timeout")); assertThat(exception.responseBody()).isEmpty(); - assertThat(exception.content()).isNullOrEmpty(); assertThat(exception.hasRequest()).isTrue(); assertThat(exception.request()).isNotNull(); } @@ -90,8 +87,7 @@ void createFeignExceptionWithCorrectCharsetResponse() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - "data".getBytes(StandardCharsets.UTF_16BE), - StandardCharsets.UTF_16BE, + Request.Body.of("data".getBytes(StandardCharsets.UTF_16BE)), null); Response response = @@ -127,8 +123,7 @@ void createFeignExceptionWithCorrectCharsetResponseButDifferentContentTypeFormat Request.HttpMethod.GET, "/home", Collections.emptyMap(), - "data".getBytes(StandardCharsets.UTF_16BE), - StandardCharsets.UTF_16BE, + Request.Body.of("data".getBytes(StandardCharsets.UTF_16BE)), null); Response response = @@ -158,8 +153,7 @@ void createFeignExceptionWithErrorCharsetResponse() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - "data".getBytes(StandardCharsets.UTF_16BE), - StandardCharsets.UTF_16BE, + Request.Body.of("data".getBytes(StandardCharsets.UTF_16BE)), null); Response response = @@ -182,8 +176,7 @@ void canGetResponseHeadersFromException() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - "data".getBytes(StandardCharsets.UTF_8), - StandardCharsets.UTF_8, + Request.Body.of("data".getBytes(StandardCharsets.UTF_8)), null); Map> responseHeaders = new HashMap<>(); @@ -241,8 +234,7 @@ void lengthOfBodyExceptionTest() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - "data".getBytes(StandardCharsets.UTF_8), - StandardCharsets.UTF_8, + Request.Body.of("data".getBytes(StandardCharsets.UTF_8)), null); Response response = @@ -273,7 +265,12 @@ void nullRequestShouldThrowNPEwThrowableAndBytes() { NullPointerException.class, () -> new Derived( - 404, "message", null, new Throwable(), new byte[1], Collections.emptyMap())); + 404, + "message", + null, + new Throwable(), + "content".getBytes(StandardCharsets.UTF_8), + Collections.emptyMap())); } @Test @@ -285,7 +282,13 @@ void nullRequestShouldThrowNPE() { void nullRequestShouldThrowNPEwBytes() { assertThrows( NullPointerException.class, - () -> new Derived(404, "message", null, new byte[1], Collections.emptyMap())); + () -> + new Derived( + 404, + "message", + null, + "content".getBytes(StandardCharsets.UTF_8), + Collections.emptyMap())); } static class Derived extends FeignException { diff --git a/core/src/test/java/feign/FeignTest.java b/core/src/test/java/feign/FeignTest.java index 47a348bfaf..41b3e0e331 100755 --- a/core/src/test/java/feign/FeignTest.java +++ b/core/src/test/java/feign/FeignTest.java @@ -19,7 +19,6 @@ import static feign.Util.UTF_8; import static feign.assertj.MockWebServerAssertions.assertThat; import static java.util.Collections.emptyList; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; @@ -607,7 +606,7 @@ void throwsFeignExceptionIncludingBody() { } catch (FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + assertThat(e.contentUTF8()).isEmpty(); } } @@ -772,7 +771,7 @@ void whenReturnTypeIsResponseNoErrorHandling() { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); @@ -962,7 +961,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(new HashMap<>()) .build(); } @@ -1492,9 +1491,9 @@ static final class TestInterfaceBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(new Gson().toJson(object)); + template.body(Request.Body.of(new Gson().toJson(object))); } else { - template.body(object.toString()); + template.body(Request.Body.of(object.toString())); } }); diff --git a/core/src/test/java/feign/FeignUnderAsyncTest.java b/core/src/test/java/feign/FeignUnderAsyncTest.java index f18fd5d747..0440fad8a6 100644 --- a/core/src/test/java/feign/FeignUnderAsyncTest.java +++ b/core/src/test/java/feign/FeignUnderAsyncTest.java @@ -17,7 +17,6 @@ import static feign.Util.UTF_8; import static feign.assertj.MockWebServerAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -493,7 +492,7 @@ void throwsFeignExceptionIncludingBody() { } catch (FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + assertThat(e.contentUTF8()).isEmpty(); } } @@ -527,7 +526,7 @@ void whenReturnTypeIsResponseNoErrorHandling() { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); @@ -722,7 +721,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(new HashMap<>()) .build(); } @@ -964,9 +963,9 @@ static final class TestInterfaceBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(new Gson().toJson(object)); + template.body(Request.Body.of(new Gson().toJson(object))); } else { - template.body(object.toString()); + template.body(Request.Body.of(object.toString())); } }); diff --git a/core/src/test/java/feign/LoggerMethodsTest.java b/core/src/test/java/feign/LoggerMethodsTest.java index bee76be63b..36c8c6a913 100644 --- a/core/src/test/java/feign/LoggerMethodsTest.java +++ b/core/src/test/java/feign/LoggerMethodsTest.java @@ -36,7 +36,7 @@ protected void log(String configKey, String format, Object... args) {} @Test void responseIsClosedAfterRebuffer() throws IOException { Request request = - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, UTF_8, null); + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null); Response response = Response.builder() .status(200) diff --git a/core/src/test/java/feign/RequestTemplateTest.java b/core/src/test/java/feign/RequestTemplateTest.java index 973ee2104c..183aaca0d4 100644 --- a/core/src/test/java/feign/RequestTemplateTest.java +++ b/core/src/test/java/feign/RequestTemplateTest.java @@ -17,7 +17,6 @@ import static feign.assertj.FeignAssertions.assertThat; import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.MapEntry.entry; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -92,11 +91,9 @@ void resolveTemplateWithParameterizedPathSkipsEncodingSlash() { @Test void resolveTemplateWithBinaryBody() { + byte[] body = new byte[] {7, 3, -3, -7}; RequestTemplate template = - new RequestTemplate() - .method(HttpMethod.GET) - .uri("{zoneId}") - .body(new byte[] {7, 3, -3, -7}, null); + new RequestTemplate().method(HttpMethod.GET).uri("{zoneId}").body(Request.Body.of(body)); template = template.resolve(mapOf("zoneId", "/hostedzone/Z1PA6795UKMFR9")); assertThat(template).hasUrl("/hostedzone/Z1PA6795UKMFR9"); @@ -345,7 +342,11 @@ void resolveTemplateWithBodyTemplateSetsBodyAndContentLength() { .hasHeaders( entry( "Content-Length", - Collections.singletonList(String.valueOf(template.body().length)))); + Collections.singletonList( + template + .requestBody() + .map(body -> String.valueOf(body.contentLength())) + .orElse("0")))); } @Test diff --git a/core/src/test/java/feign/ResponseTest.java b/core/src/test/java/feign/ResponseTest.java index 9af1ceb887..5a7020f0ff 100644 --- a/core/src/test/java/feign/ResponseTest.java +++ b/core/src/test/java/feign/ResponseTest.java @@ -36,8 +36,7 @@ void reasonPhraseIsOptional() { Response.builder() .status(200) .headers(Collections.>emptyMap()) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); @@ -54,8 +53,7 @@ void canAccessHeadersCaseInsensitively() { Response.builder() .status(200) .headers(headersMap) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); assertThat(response.headers()) @@ -80,8 +78,7 @@ void charsetSupportsMediaTypesWithQuotedCharset() { Response.builder() .status(200) .headers(headersMap) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); assertThat(response.charset()).isEqualTo(Util.UTF_8); @@ -97,8 +94,7 @@ void headerValuesWithSameNameOnlyVaryingInCaseAreMerged() { Response.builder() .status(200) .headers(headersMap) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); @@ -115,8 +111,7 @@ void headersAreOptional() { Response response = Response.builder() .status(200) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); assertThat(response.headers()).isNotNull().isEmpty(); @@ -127,8 +122,7 @@ void support1xxStatusCodes() { Response response = Response.builder() .status(103) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body((Response.Body) null) .build(); @@ -145,7 +139,7 @@ void statusCodesOfAnyValueAreAllowed() { .status(statusCode) .request( Request.create( - HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body((Response.Body) null) .build(); @@ -158,8 +152,7 @@ void protocolVersionDefaultsToHttp1_1() { Response response = Response.builder() .status(200) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .protocolVersion(null) .body(new byte[0]) .build(); diff --git a/core/src/test/java/feign/RetryableExceptionTest.java b/core/src/test/java/feign/RetryableExceptionTest.java index 0bd9a73127..90fc028eb9 100644 --- a/core/src/test/java/feign/RetryableExceptionTest.java +++ b/core/src/test/java/feign/RetryableExceptionTest.java @@ -33,7 +33,7 @@ void createRetryableExceptionWithResponseAndResponseHeader() { // given Long retryAfter = 5000L; Request request = - Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8); + Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, null); byte[] response = "response".getBytes(StandardCharsets.UTF_8); Map> responseHeader = new HashMap<>(); responseHeader.put("TEST_HEADER", Arrays.asList("TEST_CONTENT")); @@ -56,7 +56,7 @@ void createRetryableExceptionWithMethodKey() { Long retryAfter = 5000L; String methodKey = "TestClient#testMethod()"; Request request = - Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8); + Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, null); Throwable cause = new RuntimeException("test cause"); // when @@ -81,7 +81,7 @@ void createRetryableExceptionWithMethodKey() { void methodKeyIsNullWhenNotProvided() { // given Request request = - Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8); + Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, null); // when RetryableException retryableException = diff --git a/core/src/test/java/feign/RetryerTest.java b/core/src/test/java/feign/RetryerTest.java index 74ed8e832b..d2656b8686 100644 --- a/core/src/test/java/feign/RetryerTest.java +++ b/core/src/test/java/feign/RetryerTest.java @@ -26,7 +26,7 @@ class RetryerTest { private static final Request REQUEST = - Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8); + Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, null); @Test void only5TriesAllowedAndExponentialBackoff() { diff --git a/core/src/test/java/feign/TargetTest.java b/core/src/test/java/feign/TargetTest.java index 024a9514f5..73e9fb5e92 100644 --- a/core/src/test/java/feign/TargetTest.java +++ b/core/src/test/java/feign/TargetTest.java @@ -66,8 +66,8 @@ public Request apply(RequestTemplate input) { urlEncoded.httpMethod(), urlEncoded.url().replace("%2F", "/"), urlEncoded.headers(), - urlEncoded.body(), - urlEncoded.charset()); + urlEncoded.body().orElse(null), + null); } }; diff --git a/core/src/test/java/feign/assertj/RequestTemplateAssert.java b/core/src/test/java/feign/assertj/RequestTemplateAssert.java index 0a571ebb36..d3ccb7a7b9 100644 --- a/core/src/test/java/feign/assertj/RequestTemplateAssert.java +++ b/core/src/test/java/feign/assertj/RequestTemplateAssert.java @@ -15,9 +15,11 @@ */ package feign.assertj; -import static feign.Util.UTF_8; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import feign.Request; import feign.RequestTemplate; +import java.nio.charset.StandardCharsets; import org.assertj.core.api.AbstractAssert; import org.assertj.core.data.MapEntry; import org.assertj.core.internal.ByteArrays; @@ -58,7 +60,8 @@ public RequestTemplateAssert hasBody(String utf8Expected) { if (actual.bodyTemplate() != null) { failWithMessage("\nExpecting bodyTemplate to be null, but was:<%s>", actual.bodyTemplate()); } - objects.assertEqual(info, new String(actual.body(), UTF_8), utf8Expected); + objects.assertEqual( + info, actual.requestBody().map(this::bodyAsUtf8String).orElse(null), utf8Expected); return this; } @@ -67,13 +70,13 @@ public RequestTemplateAssert hasBody(byte[] expected) { if (actual.bodyTemplate() != null) { failWithMessage("\nExpecting bodyTemplate to be null, but was:<%s>", actual.bodyTemplate()); } - arrays.assertContains(info, actual.body(), expected); + arrays.assertContains(info, actual.requestBody().map(this::bodyAsBytes).orElse(null), expected); return this; } public RequestTemplateAssert hasBodyTemplate(String expected) { isNotNull(); - if (actual.body() != null) { + if (actual.requestBody().isPresent()) { failWithMessage("\nExpecting body to be null, but was:<%s>", actual.bodyTemplate()); } objects.assertEqual(info, actual.bodyTemplate(), expected); @@ -99,17 +102,24 @@ public RequestTemplateAssert hasNoHeader(final String encoded) { public RequestTemplateAssert noRequestBody() { isNotNull(); - if (actual.body() != null) { + if (actual.requestBody().isPresent()) { if (actual.bodyTemplate() != null) { failWithMessage( "\nExpecting requestBody.bodyTemplate to be null, but was:<%s>", actual.bodyTemplate()); } - if (actual.body() != null) { + if (actual.requestBody().isPresent()) { failWithMessage( - "\nExpecting requestBody.data to be null, but was:<%s>", - new String(actual.body(), actual.requestCharset())); + "\nExpecting requestBody.data to be null, but was:<%s>", actual.requestBody().get()); } } return this; } + + private String bodyAsUtf8String(Request.Body body) { + return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); + } + + private byte[] bodyAsBytes(Request.Body body) { + return assertDoesNotThrow(body::writeToByteArray); + } } diff --git a/core/src/test/java/feign/codec/DefaultDecoderTest.java b/core/src/test/java/feign/codec/DefaultDecoderTest.java index 23ba1d4d06..f1856c2946 100644 --- a/core/src/test/java/feign/codec/DefaultDecoderTest.java +++ b/core/src/test/java/feign/codec/DefaultDecoderTest.java @@ -22,7 +22,6 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; -import feign.Util; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Collection; @@ -74,7 +73,7 @@ private Response knownResponse() { .status(200) .reason("OK") .headers(headers) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(inputStream, content.length()) .build(); } @@ -84,7 +83,7 @@ private Response nullBodyResponse() { .status(200) .reason("OK") .headers(Collections.>emptyMap()) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .build(); } } diff --git a/core/src/test/java/feign/codec/DefaultEncoderTest.java b/core/src/test/java/feign/codec/DefaultEncoderTest.java index 9aecbb9059..94f5183229 100644 --- a/core/src/test/java/feign/codec/DefaultEncoderTest.java +++ b/core/src/test/java/feign/codec/DefaultEncoderTest.java @@ -15,13 +15,15 @@ */ package feign.codec; -import static feign.Util.UTF_8; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; +import feign.Request; import feign.RequestTemplate; +import java.nio.charset.StandardCharsets; import java.time.Clock; -import java.util.Arrays; +import java.util.Optional; import org.junit.jupiter.api.Test; class DefaultEncoderTest { @@ -33,7 +35,11 @@ void encodesStrings() throws Exception { String content = "This is my content"; RequestTemplate template = new RequestTemplate(); encoder.encode(content, String.class, template); - assertThat(new String(template.body(), UTF_8)).isEqualTo(content); + Optional optionalBody = template.requestBody(); + assertThat(optionalBody).isPresent(); + String body = + assertDoesNotThrow(() -> optionalBody.get().writeToString(StandardCharsets.UTF_8)); + assertThat(body).contains(content); } @Test @@ -41,7 +47,10 @@ void encodesByteArray() throws Exception { byte[] content = {12, 34, 56}; RequestTemplate template = new RequestTemplate(); encoder.encode(content, byte[].class, template); - assertThat(Arrays.equals(content, template.body())).isTrue(); + Optional optionalBody = template.requestBody(); + assertThat(optionalBody).isPresent(); + byte[] body = assertDoesNotThrow(() -> optionalBody.get().writeToByteArray()); + assertThat(body).isEqualTo(content); } @Test diff --git a/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java b/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java index c9dae156bd..0d546b1cd7 100644 --- a/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java +++ b/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java @@ -141,11 +141,7 @@ void exceptionIsHttpSpecific(int httpStatus, Class expectedExceptionClass, Strin .reason("anything") .request( Request.create( - HttpMethod.GET, - "http://example.com/api", - Collections.emptyMap(), - null, - Util.UTF_8)) + HttpMethod.GET, "http://example.com/api", Collections.emptyMap(), null, null)) .headers(headers) .body("response body", Util.UTF_8) .build(); diff --git a/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java b/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java index 1967e77632..6088ea54b1 100644 --- a/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java +++ b/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java @@ -26,6 +26,7 @@ import feign.Util; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -47,8 +48,7 @@ void throwsFeignException() throws Throwable { Response.builder() .status(500) .reason("Internal server error") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(headers) .build(); @@ -63,8 +63,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { Response.builder() .status(500) .reason("Internal server error") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(headers) .body("hello world", UTF_8) .build(); @@ -86,8 +85,7 @@ void throwsFeignExceptionIncludingLongBody() throws Throwable { Response.builder() .status(500) .reason("Internal server error") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(headers) .body(actualBody, UTF_8) .build(); @@ -119,8 +117,7 @@ void feignExceptionIncludesStatus() { Response.builder() .status(400) .reason("Bad request") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(headers) .build(); @@ -138,8 +135,7 @@ void retryAfterHeaderThrowsRetryableException() throws Throwable { Response.builder() .status(503) .reason("Service Unavailable") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(headers) .build(); @@ -194,8 +190,7 @@ private Response bigBodyResponse() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - "data".getBytes(Util.UTF_8), - Util.UTF_8, + Request.Body.of("data".getBytes(StandardCharsets.UTF_8)), null)) .body(content, Util.UTF_8) .build(); diff --git a/core/src/test/java/feign/stream/StreamDecoderTest.java b/core/src/test/java/feign/stream/StreamDecoderTest.java index d514dcc6b7..86a6d8509e 100644 --- a/core/src/test/java/feign/stream/StreamDecoderTest.java +++ b/core/src/test/java/feign/stream/StreamDecoderTest.java @@ -24,7 +24,6 @@ import feign.Request.HttpMethod; import feign.RequestLine; import feign.Response; -import feign.Util; import java.io.BufferedReader; import java.io.Closeable; import java.io.IOException; @@ -138,8 +137,7 @@ void shouldCloseIteratorWhenStreamClosed() throws IOException { .status(200) .reason("OK") .headers(Collections.emptyMap()) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body("", UTF_8) .build(); diff --git a/dropwizard-metrics4/src/main/java/feign/metrics4/MeteredEncoder.java b/dropwizard-metrics4/src/main/java/feign/metrics4/MeteredEncoder.java index 2a2c644c5f..4263d14d51 100644 --- a/dropwizard-metrics4/src/main/java/feign/metrics4/MeteredEncoder.java +++ b/dropwizard-metrics4/src/main/java/feign/metrics4/MeteredEncoder.java @@ -50,13 +50,15 @@ public void encode(Object object, Type bodyType, RequestTemplate template) encoder.encode(object, bodyType, template); } - if (template.body() != null) { - metricRegistry - .histogram( - metricName.metricName( - template.methodMetadata(), template.feignTarget(), "request_size"), - metricSuppliers.histograms()) - .update(template.body().length); - } + template + .requestBody() + .ifPresent( + body -> + metricRegistry + .histogram( + metricName.metricName( + template.methodMetadata(), template.feignTarget(), "request_size"), + metricSuppliers.histograms()) + .update(body.contentLength())); } } diff --git a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java index 77cc7b78cb..09f3058be4 100644 --- a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java +++ b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java @@ -62,13 +62,15 @@ public void encode(Object object, Type bodyType, RequestTemplate template) encoder.encode(object, bodyType, template); } - if (template.body() != null) { - metricRegistry - .histogram( - metricName.metricName( - template.methodMetadata(), template.feignTarget(), "request_size"), - metricSuppliers.histograms()) - .update(template.body().length); - } + template + .requestBody() + .ifPresent( + body -> + metricRegistry + .histogram( + metricName.metricName( + template.methodMetadata(), template.feignTarget(), "request_size"), + metricSuppliers.histograms()) + .update(body.contentLength())); } } diff --git a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java index 06a98e8dd2..7e79af331a 100644 --- a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java +++ b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java @@ -17,8 +17,8 @@ import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONWriter; +import feign.Request; import feign.RequestTemplate; -import feign.Util; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.JsonEncoder; @@ -42,6 +42,6 @@ public Fastjson2Encoder(JSONWriter.Feature[] features) { @Override public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { - template.body(JSON.toJSONBytes(object, features), Util.UTF_8); + template.body(Request.Body.of(JSON.toJSONBytes(object, features))); } } diff --git a/fastjson2/src/test/java/feign/fastjson2/FastJsonCodecTest.java b/fastjson2/src/test/java/feign/fastjson2/FastJsonCodecTest.java index 606ccf2511..06c00502d5 100644 --- a/fastjson2/src/test/java/feign/fastjson2/FastJsonCodecTest.java +++ b/fastjson2/src/test/java/feign/fastjson2/FastJsonCodecTest.java @@ -22,7 +22,6 @@ import feign.Request; import feign.RequestTemplate; import feign.Response; -import feign.Util; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -107,8 +106,7 @@ void decodes() throws Exception { .status(200) .reason("OK") .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -124,8 +122,7 @@ void nullBodyDecodesToNull() throws Exception { .status(204) .reason("OK") .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat(new Fastjson2Decoder().decode(response, String.class)).isNull(); @@ -138,8 +135,7 @@ void emptyBodyDecodesToNull() throws Exception { .status(204) .reason("OK") .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -158,8 +154,7 @@ void decoderCharset() throws IOException { .status(200) .reason("OK") .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(headers) .body( new String( @@ -205,8 +200,7 @@ void notFoundDecodesToEmpty() throws Exception { .status(404) .reason("NOT FOUND") .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new Fastjson2Decoder().decode(response, byte[].class)).isEmpty(); diff --git a/form/src/main/java/feign/form/MultipartFormContentProcessor.java b/form/src/main/java/feign/form/MultipartFormContentProcessor.java index af31d36eb6..d8c6e9228f 100644 --- a/form/src/main/java/feign/form/MultipartFormContentProcessor.java +++ b/form/src/main/java/feign/form/MultipartFormContentProcessor.java @@ -18,6 +18,7 @@ import static feign.form.ContentType.MULTIPART; import static lombok.AccessLevel.PRIVATE; +import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -103,7 +104,7 @@ public void process(RequestTemplate template, Charset charset, MapemptyList()); // reset header template.header(CONTENT_TYPE_HEADER, contentTypeValue); - template.body(bytes, charset); + template.body(Request.Body.of(bytes)); } @Override diff --git a/form/src/main/java/feign/form/multipart/DelegateWriter.java b/form/src/main/java/feign/form/multipart/DelegateWriter.java index 7161c21a46..3295741e4e 100644 --- a/form/src/main/java/feign/form/multipart/DelegateWriter.java +++ b/form/src/main/java/feign/form/multipart/DelegateWriter.java @@ -17,9 +17,12 @@ import static lombok.AccessLevel.PRIVATE; +import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import lombok.val; @@ -46,8 +49,15 @@ public boolean isApplicable(Object value) { protected void write(Output output, String key, Object value) throws EncodeException { val fake = new RequestTemplate(); delegate.encode(value, value.getClass(), fake); - val bytes = fake.body(); - val string = new String(bytes, output.getCharset()).replaceAll("\n", ""); - parameterWriter.write(output, key, string); + fake.requestBody().ifPresent(body -> write(output, key, body)); + } + + private void write(Output output, String key, Request.Body body) { + try { + val encoded = body.writeToString(StandardCharsets.UTF_8).replaceAll("\n", ""); + parameterWriter.write(output, key, encoded); + } catch (IOException e) { + throw new EncodeException("Failed to write request body for key: " + key, e); + } } } diff --git a/googlehttpclient/src/main/java/feign/googlehttpclient/GoogleHttpClient.java b/googlehttpclient/src/main/java/feign/googlehttpclient/GoogleHttpClient.java index a57101a89c..65aa8f1180 100644 --- a/googlehttpclient/src/main/java/feign/googlehttpclient/GoogleHttpClient.java +++ b/googlehttpclient/src/main/java/feign/googlehttpclient/GoogleHttpClient.java @@ -15,7 +15,6 @@ */ package feign.googlehttpclient; -import com.google.api.client.http.ByteArrayContent; import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpContent; import com.google.api.client.http.HttpHeaders; @@ -28,6 +27,7 @@ import feign.Request; import feign.Response; import java.io.IOException; +import java.io.OutputStream; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -66,18 +66,7 @@ public final Response execute(final Request inputRequest, final Request.Options private final HttpRequest convertRequest( final Request inputRequest, final Request.Options options) throws IOException { - // Setup the request body - HttpContent content = null; - if (inputRequest.length() > 0) { - final Collection contentTypeValues = inputRequest.headers().get("Content-Type"); - String contentType = null; - if (contentTypeValues != null && contentTypeValues.size() > 0) { - contentType = contentTypeValues.iterator().next(); - } else { - contentType = "application/octet-stream"; - } - content = new ByteArrayContent(contentType, inputRequest.body()); - } + final HttpContent content = toHttpContent(inputRequest); // Build the request final HttpRequest request = @@ -108,6 +97,21 @@ private final HttpRequest convertRequest( return request; } + private HttpContent toHttpContent(final Request inputRequest) { + if (!inputRequest.httpMethod().isWithBody() || !inputRequest.body().isPresent()) { + return null; + } + + final Request.Body requestBody = inputRequest.body().get(); + final Collection contentTypeValues = inputRequest.headers().get("Content-Type"); + final String contentType = + contentTypeValues != null && !contentTypeValues.isEmpty() + ? contentTypeValues.stream().findFirst().get() + : "application/octet-stream"; + + return new FeignBodyContent(requestBody, contentType); + } + private final Response convertResponse( final Request inputRequest, final HttpResponse inputResponse) throws IOException { final HttpHeaders headers = inputResponse.getHeaders(); @@ -131,4 +135,34 @@ private final Map> toMap(final HttpHeaders headers) { } return map; } + + private static final class FeignBodyContent implements HttpContent { + private final Request.Body body; + private final String contentType; + + private FeignBodyContent(Request.Body body, String contentType) { + this.body = body; + this.contentType = contentType; + } + + @Override + public long getLength() { + return body.contentLength(); + } + + @Override + public String getType() { + return contentType; + } + + @Override + public boolean retrySupported() { + return body.isRepeatable(); + } + + @Override + public void writeTo(OutputStream outputStream) throws IOException { + body.writeTo(outputStream); + } + } } diff --git a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java index 4486a239f4..78d8d25efe 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java @@ -16,6 +16,7 @@ package feign.graphql; import feign.Experimental; +import feign.Request; import feign.Response; import feign.Util; import feign.codec.Decoder; @@ -111,14 +112,14 @@ private String resolveOperationField(Map root, Response response } } - if (response.request() != null && response.request().body() != null) { + if (response.request() != null && response.request().body().isPresent()) { try { var fakeResponse = Response.builder() .status(200) .headers(Collections.emptyMap()) .request(response.request()) - .body(response.request().body()) + .body(bodyAsByteArray(response.request())) .build(); var requestBody = (Map) jsonDecoder.decode(fakeResponse, Map.class); if (requestBody != null) { @@ -135,6 +136,12 @@ private String resolveOperationField(Map root, Response response return "unknown"; } + private byte[] bodyAsByteArray(Request request) throws IOException { + var body = request.body(); + + return body.isPresent() ? body.get().writeToByteArray() : null; + } + private boolean isOptionalType(Type type) { if (type instanceof ParameterizedType pt && pt.getRawType() instanceof Class cls) { return cls == Optional.class; diff --git a/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java b/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java index 252834fc3d..5a318958ca 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java +++ b/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java @@ -34,7 +34,7 @@ public GraphqlRequestInterceptor(Encoder delegate, GraphqlContract contract) { @Override public void apply(RequestTemplate template) { - if (template.body() != null) { + if (template.requestBody().isPresent()) { return; } diff --git a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java index b796a68612..13d92f3aac 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java @@ -332,11 +332,7 @@ private Response buildResponse(String body) { private Request buildRequest() { return Request.create( - HttpMethod.POST, - "http://localhost/graphql", - Collections.emptyMap(), - Request.Body.empty(), - null); + HttpMethod.POST, "http://localhost/graphql", Collections.emptyMap(), null, null); } private static ParameterizedType optionalOf(Type inner) { diff --git a/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java index 07a22ed8a9..21444de39a 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java @@ -16,10 +16,13 @@ package feign.graphql; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import com.fasterxml.jackson.databind.ObjectMapper; +import feign.Request; import feign.RequestTemplate; import feign.jackson.JacksonEncoder; +import java.nio.charset.StandardCharsets; import java.util.Map; import org.junit.jupiter.api.Test; @@ -51,13 +54,29 @@ private RequestTemplate templateFor(Class apiClass) { return template; } + private byte[] bodyAsByteArray(Request.Body body) { + return assertDoesNotThrow(body::writeToByteArray); + } + + private String bodyAsUtf8String(Request.Body body) { + return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); + } + + private byte[] requestBodyBytes(RequestTemplate template) { + return template.requestBody().map(this::bodyAsByteArray).orElse(null); + } + + private String requestBodyString(RequestTemplate template) { + return template.requestBody().map(this::bodyAsUtf8String).orElse(null); + } + @Test void encodesBodyWithVariables() throws Exception { var template = templateFor(MutationApi.class); var body = Map.of("name", "John", "email", "john@example.com"); encoder.encode(body, Map.class, template); - var result = mapper.readTree(template.body()); + var result = mapper.readTree(requestBodyBytes(template)); assertThat(result.has("query")).isTrue(); assertThat(result.get("query").asText()).contains("createUser"); assertThat(result.has("variables")).isTrue(); @@ -69,7 +88,7 @@ void encodesBodyWithVariables() throws Exception { void delegatesToWrappedEncoderForNonGraphql() { var template = new RequestTemplate(); encoder.encode("plain body", String.class, template); - assertThat(template.body()).isNotNull(); + assertThat(template.requestBody()).isNotEmpty(); } @Test @@ -77,7 +96,7 @@ void interceptorSetsBodyForNoVariableQuery() throws Exception { var template = templateFor(NoVariableApi.class); interceptor.apply(template); - var result = mapper.readTree(template.body()); + var result = mapper.readTree(requestBodyBytes(template)); assertThat(result.get("query").asText()).contains("pending"); assertThat(result.has("variables")).isFalse(); } @@ -85,16 +104,16 @@ void interceptorSetsBodyForNoVariableQuery() throws Exception { @Test void interceptorSkipsWhenBodyAlreadySet() { var template = templateFor(MutationApi.class); - template.body("already set"); + template.body(Request.Body.of("already set")); interceptor.apply(template); - assertThat(new String(template.body())).isEqualTo("already set"); + assertThat(requestBodyString(template)).isEqualTo("already set"); } @Test void interceptorSkipsForNonGraphql() { var template = new RequestTemplate(); - template.body("some body"); + template.body(Request.Body.of("some body")); interceptor.apply(template); - assertThat(new String(template.body())).isEqualTo("some body"); + assertThat(requestBodyString(template)).isEqualTo("some body"); } } diff --git a/gson/src/main/java/feign/gson/GsonEncoder.java b/gson/src/main/java/feign/gson/GsonEncoder.java index c4484bc6eb..c0c3d0eb2f 100644 --- a/gson/src/main/java/feign/gson/GsonEncoder.java +++ b/gson/src/main/java/feign/gson/GsonEncoder.java @@ -17,6 +17,7 @@ import com.google.gson.Gson; import com.google.gson.TypeAdapter; +import feign.Request; import feign.RequestTemplate; import feign.codec.Encoder; import feign.codec.JsonEncoder; @@ -41,6 +42,6 @@ public GsonEncoder(Gson gson) { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { - template.body(gson.toJson(object, bodyType)); + template.body(Request.Body.of(gson.toJson(object, bodyType))); } } diff --git a/gson/src/test/java/feign/gson/GsonCodecTest.java b/gson/src/test/java/feign/gson/GsonCodecTest.java index 1ec47b8918..f1a99670bb 100644 --- a/gson/src/test/java/feign/gson/GsonCodecTest.java +++ b/gson/src/test/java/feign/gson/GsonCodecTest.java @@ -27,7 +27,6 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; -import feign.Util; import java.io.IOException; import java.util.Arrays; import java.util.Collections; @@ -66,8 +65,7 @@ void decodesMapObjectNumericalValuesAsInteger() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body("{\"foo\": 1}", UTF_8) .build(); @@ -131,8 +129,7 @@ void decodes() throws Exception { .status(200) .reason("OK") .headers(Collections.emptyMap()) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(zonesJson, UTF_8) .build(); assertThat(new GsonDecoder().decode(response, new TypeToken>() {}.getType())) @@ -146,8 +143,7 @@ void nullBodyDecodesToNull() throws Exception { .status(204) .reason("OK") .headers(Collections.emptyMap()) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .build(); assertThat(new GsonDecoder().decode(response, String.class)).isNull(); } @@ -159,8 +155,7 @@ void emptyBodyDecodesToNull() throws Exception { .status(204) .reason("OK") .headers(Collections.emptyMap()) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); assertThat(new GsonDecoder().decode(response, String.class)).isNull(); @@ -216,8 +211,7 @@ void customDecoder() throws Exception { .status(200) .reason("OK") .headers(Collections.emptyMap()) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(zonesJson, UTF_8) .build(); assertThat(decoder.decode(response, new TypeToken>() {}.getType())).isEqualTo(zones); @@ -256,8 +250,7 @@ void notFoundDecodesToEmpty() throws Exception { .status(404) .reason("NOT FOUND") .headers(Collections.emptyMap()) - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .build(); assertThat((byte[]) new GsonDecoder().decode(response, byte[].class)).isEmpty(); } diff --git a/hc5/src/main/java/feign/hc5/ApacheHttp5Client.java b/hc5/src/main/java/feign/hc5/ApacheHttp5Client.java index 65edd9e71c..daaac3b77a 100644 --- a/hc5/src/main/java/feign/hc5/ApacheHttp5Client.java +++ b/hc5/src/main/java/feign/hc5/ApacheHttp5Client.java @@ -49,7 +49,6 @@ import org.apache.hc.core5.http.NameValuePair; import org.apache.hc.core5.http.io.entity.ByteArrayEntity; import org.apache.hc.core5.http.io.entity.EntityUtils; -import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.io.support.ClassicRequestBuilder; import org.apache.hc.core5.net.URIBuilder; import org.apache.hc.core5.net.URLEncodedUtils; @@ -157,22 +156,8 @@ ClassicHttpRequest toClassicHttpRequest(Request request, Request.Options options } // request body - // final Body requestBody = request.requestBody(); - byte[] data = request.body(); - if (data != null) { - HttpEntity entity; - if (request.isBinary()) { - entity = new ByteArrayEntity(data, null); - } else { - final ContentType contentType = getContentType(request); - String content; - if (request.charset() != null) { - content = new String(data, request.charset()); - } else { - content = new String(data); - } - entity = new StringEntity(content, contentType); - } + if (request.body().isPresent()) { + HttpEntity entity = new FeignBodyEntity(request.body().get(), getContentType(request)); if (isGzip) { entity = new GzipCompressingEntity(entity); } @@ -191,9 +176,6 @@ private ContentType getContentType(Request request) { final Collection values = entry.getValue(); if (values != null && !values.isEmpty()) { contentType = ContentType.parse(values.iterator().next()); - if (contentType.getCharset() == null) { - contentType = contentType.withCharset(request.charset()); - } break; } } diff --git a/hc5/src/main/java/feign/hc5/AsyncApacheHttp5Client.java b/hc5/src/main/java/feign/hc5/AsyncApacheHttp5Client.java index f51c1c2221..8a1adb5fd8 100644 --- a/hc5/src/main/java/feign/hc5/AsyncApacheHttp5Client.java +++ b/hc5/src/main/java/feign/hc5/AsyncApacheHttp5Client.java @@ -17,24 +17,45 @@ import static feign.Util.enumForName; -import feign.*; +import feign.AsyncClient; +import feign.Request; import feign.Request.Options; -import java.io.ByteArrayOutputStream; +import feign.Response; +import feign.Util; import java.io.IOException; -import java.util.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.zip.GZIPOutputStream; -import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; +import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer; import org.apache.hc.client5.http.config.Configurable; import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.entity.GzipCompressingEntity; import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.impl.async.HttpAsyncClients; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.core5.concurrent.FutureCallback; +import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.io.entity.ByteArrayEntity; +import org.apache.hc.core5.http.io.support.ClassicRequestBuilder; +import org.apache.hc.core5.http.nio.support.classic.ClassicToAsyncRequestProducer; import org.apache.hc.core5.io.CloseMode; +import org.apache.hc.core5.net.URIBuilder; +import org.apache.hc.core5.net.URLEncodedUtils; +import org.apache.hc.core5.util.Timeout; /** * This module directs Feign's http requests to Apache's @@ -50,14 +71,34 @@ public final class AsyncApacheHttp5Client implements AsyncClient { + Thread thread = new Thread(runnable, "feign-hc5-async-body-writer"); + thread.setDaemon(true); + return thread; + }); + private final CloseableHttpAsyncClient client; + private final Executor executor; + public AsyncApacheHttp5Client() { this(createStartedClient()); } public AsyncApacheHttp5Client(CloseableHttpAsyncClient client) { - this.client = client; + this(client, DEFAULT_EXECUTOR); + } + + public AsyncApacheHttp5Client(CloseableHttpAsyncClient client, Executor executor) { + this.client = Objects.requireNonNull(client, "client must not be null"); + this.executor = Objects.requireNonNull(executor, "executor must not be null"); } private static CloseableHttpAsyncClient createStartedClient() { @@ -69,7 +110,15 @@ private static CloseableHttpAsyncClient createStartedClient() { @Override public CompletableFuture execute( Request request, Options options, Optional requestContext) { - final SimpleHttpRequest httpUriRequest = toClassicHttpRequest(request, options); + ClassicHttpRequest httpUriRequest; + try { + httpUriRequest = toClassicHttpRequest(request, options); + } catch (final URISyntaxException e) { + CompletableFuture failedFuture = new CompletableFuture<>(); + failedFuture.completeExceptionally( + new IOException("URL '" + request.url() + "' couldn't be parsed into a URI", e)); + return failedFuture; + } final CompletableFuture result = new CompletableFuture<>(); final FutureCallback callback = @@ -90,12 +139,25 @@ public void cancelled() { result.cancel(false); } }; + final ClassicToAsyncRequestProducer requestProducer = + new ClassicToAsyncRequestProducer( + httpUriRequest, Timeout.of(options.connectTimeout(), options.connectTimeoutUnit())); client.execute( - httpUriRequest, + requestProducer, + SimpleResponseConsumer.create(), configureTimeoutsAndRedirection(options, requestContext.orElseGet(HttpClientContext::new)), callback); + executor.execute( + () -> { + try { + requestProducer.blockWaiting().execute(); + } catch (IOException | InterruptedException e) { + result.completeExceptionally(e); + } + }); + return result; } @@ -114,9 +176,20 @@ protected HttpClientContext configureTimeoutsAndRedirection( return context; } - SimpleHttpRequest toClassicHttpRequest(Request request, Request.Options options) { - final SimpleHttpRequest httpRequest = - new SimpleHttpRequest(request.httpMethod().name(), request.url()); + ClassicHttpRequest toClassicHttpRequest(Request request, Request.Options options) + throws URISyntaxException { + final ClassicRequestBuilder requestBuilder = + ClassicRequestBuilder.create(request.httpMethod().name()); + + final URI uri = new URIBuilder(request.url()).build(); + + requestBuilder.setUri(uri.getScheme() + "://" + uri.getAuthority() + uri.getRawPath()); + + // request query params + final List queryParams = URLEncodedUtils.parse(uri, requestBuilder.getCharset()); + for (final NameValuePair queryParam : queryParams) { + requestBuilder.addParameter(queryParam); + } // request headers boolean hasAcceptHeader = false; @@ -142,34 +215,27 @@ SimpleHttpRequest toClassicHttpRequest(Request request, Request.Options options) "Deflate Content-Encoding is not supported by feign-hc5"); } } - for (final String headerValue : headerEntry.getValue()) { - httpRequest.addHeader(headerName, headerValue); + requestBuilder.addHeader(headerName, headerValue); } } // some servers choke on the default accept string, so we'll set it to anything if (!hasAcceptHeader) { - httpRequest.addHeader(ACCEPT_HEADER_NAME, "*/*"); + requestBuilder.addHeader(ACCEPT_HEADER_NAME, "*/*"); } // request body - // final Body requestBody = request.requestBody(); - byte[] data = request.body(); - if (isGzip && data != null && data.length > 0) { - // compress if needed - try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); - GZIPOutputStream gzipOs = new GZIPOutputStream(baos, true)) { - gzipOs.write(data); - gzipOs.flush(); - data = baos.toByteArray(); - } catch (IOException suppressed) { // NOPMD + if (request.body().isPresent()) { + HttpEntity entity = new FeignBodyEntity(request.body().get(), getContentType(request)); + if (isGzip) { + entity = new GzipCompressingEntity(entity); } - } - if (data != null) { - httpRequest.setBody(data, getContentType(request)); + requestBuilder.setEntity(entity); + } else { + requestBuilder.setEntity(new ByteArrayEntity(new byte[0], null)); } - return httpRequest; + return requestBuilder.build(); } private ContentType getContentType(Request request) { @@ -179,9 +245,6 @@ private ContentType getContentType(Request request) { final Collection values = entry.getValue(); if (values != null && !values.isEmpty()) { contentType = ContentType.parse(values.iterator().next()); - if (contentType.getCharset() == null) { - contentType = contentType.withCharset(request.charset()); - } break; } } diff --git a/hc5/src/main/java/feign/hc5/FeignBodyEntity.java b/hc5/src/main/java/feign/hc5/FeignBodyEntity.java new file mode 100644 index 0000000000..18504848df --- /dev/null +++ b/hc5/src/main/java/feign/hc5/FeignBodyEntity.java @@ -0,0 +1,97 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.hc5; + +import feign.Request; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.io.entity.AbstractHttpEntity; + +/** + * A wrapper for {@link Request.Body} that implements Apache HttpClient's {@link + * AbstractHttpEntity}. + */ +final class FeignBodyEntity extends AbstractHttpEntity { + private final Request.Body body; + + /** + * Creates a new {@link FeignBodyEntity} with the given body and content type. + * + * @param body the body to wrap + * @param contentType the content type of the body + */ + FeignBodyEntity(Request.Body body, ContentType contentType) { + super(contentType, null, body.contentLength() < 0); + this.body = body; + } + + /** + * {@inheritDoc} + * + * @return {@inheritDoc} + */ + @Override + public long getContentLength() { + return body.contentLength(); + } + + /** + * {@inheritDoc} + * + * @return {@inheritDoc} + */ + @Override + public InputStream getContent() { + throw new UnsupportedOperationException("Streaming request body does not expose InputStream"); + } + + /** + * {@inheritDoc} + * + * @param outStream {@inheritDoc} + * @throws {@inheritDoc} + */ + @Override + public void writeTo(OutputStream outStream) throws IOException { + body.writeTo(outStream); + } + + /** + * {@inheritDoc} + * + * @return {@inheritDoc} + */ + @Override + public boolean isRepeatable() { + return body.isRepeatable(); + } + + /** + * {@inheritDoc} + * + * @return {@inheritDoc} + */ + @Override + public boolean isStreaming() { + return !isRepeatable(); + } + + /** Does nothing. The caller is responsible for closing the output stream. */ + @Override + public void close() {} +} diff --git a/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java b/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java index 6d5902d9c0..cb33e46dae 100644 --- a/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java +++ b/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java @@ -17,7 +17,6 @@ import static feign.assertj.MockWebServerAssertions.assertThat; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; @@ -535,7 +534,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (final FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + assertThat(e.contentUTF8()).isEmpty(); return; } fail(""); @@ -572,7 +571,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); @@ -773,7 +772,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(new HashMap<>()) .build(); } @@ -1084,9 +1083,9 @@ static final class TestInterfaceAsyncBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(new Gson().toJson(object)); + template.body(Request.Body.of(new Gson().toJson(object))); } else { - template.body(object.toString()); + template.body(Request.Body.of(object.toString())); } }); diff --git a/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java b/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java index 010c229cb7..45e627bf27 100644 --- a/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java +++ b/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.Reader; import java.net.URI; import java.net.URISyntaxException; @@ -40,12 +41,15 @@ import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.*; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.Configurable; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.entity.AbstractHttpEntity; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; @@ -134,24 +138,51 @@ HttpUriRequest toHttpUriRequest(Request request, Request.Options options) } // request body - if (request.body() != null) { - HttpEntity entity = null; - if (request.charset() != null) { - ContentType contentType = getContentType(request); - String content = new String(request.body(), request.charset()); - entity = new StringEntity(content, contentType); - } else { - entity = new ByteArrayEntity(request.body()); - } + HttpEntity entity = + request + .body() + .map(body -> toHttpEntity(body, getContentType(request))) + .orElseGet(() -> new ByteArrayEntity(new byte[0])); - requestBuilder.setEntity(entity); - } else { - requestBuilder.setEntity(new ByteArrayEntity(new byte[0])); - } + requestBuilder.setEntity(entity); return requestBuilder.build(); } + private HttpEntity toHttpEntity(Request.Body body, ContentType contentType) { + AbstractHttpEntity httpEntity = + new AbstractHttpEntity() { + @Override + public long getContentLength() { + return body.contentLength(); + } + + @Override + public InputStream getContent() { + throw new UnsupportedOperationException( + "Streaming request body does not expose InputStream"); + } + + @Override + public void writeTo(OutputStream outStream) throws IOException { + body.writeTo(outStream); + } + + @Override + public boolean isRepeatable() { + return body.isRepeatable(); + } + + @Override + public boolean isStreaming() { + return !isRepeatable(); + } + }; + httpEntity.setContentType(contentType != null ? contentType.toString() : null); + httpEntity.setChunked(body.contentLength() < 0); + return httpEntity; + } + private ContentType getContentType(Request request) { ContentType contentType = null; for (Map.Entry> entry : request.headers().entrySet()) @@ -159,9 +190,6 @@ private ContentType getContentType(Request request) { Collection values = entry.getValue(); if (values != null && !values.isEmpty()) { contentType = ContentType.parse(values.iterator().next()); - if (contentType.getCharset() == null) { - contentType = contentType.withCharset(request.charset()); - } break; } } diff --git a/jackson-jaxb/src/main/java/feign/jackson/jaxb/JacksonJaxbJsonEncoder.java b/jackson-jaxb/src/main/java/feign/jackson/jaxb/JacksonJaxbJsonEncoder.java index 3786edb36e..6e4caeaede 100644 --- a/jackson-jaxb/src/main/java/feign/jackson/jaxb/JacksonJaxbJsonEncoder.java +++ b/jackson-jaxb/src/main/java/feign/jackson/jaxb/JacksonJaxbJsonEncoder.java @@ -20,13 +20,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; +import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.Type; -import java.nio.charset.Charset; public final class JacksonJaxbJsonEncoder implements Encoder { private final JacksonJaxbJsonProvider jacksonJaxbJsonProvider; @@ -46,7 +46,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) try { jacksonJaxbJsonProvider.writeTo( object, bodyType.getClass(), null, null, APPLICATION_JSON_TYPE, null, outputStream); - template.body(outputStream.toByteArray(), Charset.defaultCharset()); + template.body(Request.Body.of(outputStream.toByteArray())); } catch (IOException e) { throw new EncodeException(e.getMessage(), e); } diff --git a/jackson-jaxb/src/test/java/feign/jackson/jaxb/JacksonJaxbCodecTest.java b/jackson-jaxb/src/test/java/feign/jackson/jaxb/JacksonJaxbCodecTest.java index 8e0225d192..29670826ea 100644 --- a/jackson-jaxb/src/test/java/feign/jackson/jaxb/JacksonJaxbCodecTest.java +++ b/jackson-jaxb/src/test/java/feign/jackson/jaxb/JacksonJaxbCodecTest.java @@ -23,7 +23,6 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; -import feign.Util; import java.util.Collections; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -50,8 +49,7 @@ void decodeTest() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body("{\"value\":\"Test\"}", UTF_8) .build(); @@ -67,8 +65,7 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new JacksonJaxbJsonDecoder().decode(response, byte[].class)).isEmpty(); diff --git a/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrEncoder.java b/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrEncoder.java index 44118eed76..26fe78179c 100644 --- a/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrEncoder.java +++ b/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrEncoder.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.jr.ob.JSON; import com.fasterxml.jackson.jr.ob.JacksonJrExtension; +import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -53,9 +54,9 @@ public JacksonJrEncoder(Iterable iterable) { public void encode(Object object, Type bodyType, RequestTemplate template) { try { if (bodyType == byte[].class) { - template.body(mapper.asBytes(object), null); + template.body(Request.Body.of(mapper.asBytes(object))); } else { - template.body(mapper.asString(object)); + template.body(Request.Body.of(mapper.asString(object))); } } catch (IOException e) { throw new EncodeException(e.getMessage(), e); diff --git a/jackson-jr/src/test/java/feign/jackson/jr/JacksonCodecTest.java b/jackson-jr/src/test/java/feign/jackson/jr/JacksonCodecTest.java index c7c70bd67b..c716bc8194 100644 --- a/jackson-jr/src/test/java/feign/jackson/jr/JacksonCodecTest.java +++ b/jackson-jr/src/test/java/feign/jackson/jr/JacksonCodecTest.java @@ -25,7 +25,6 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; -import feign.Util; import java.io.IOException; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; @@ -96,8 +95,7 @@ void decodes() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -112,8 +110,7 @@ void nullBodyDecodesToEmpty() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new JacksonJrDecoder().decode(response, byte[].class)).isEmpty(); @@ -125,8 +122,7 @@ void emptyBodyDecodesToEmpty() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -145,8 +141,7 @@ void customDecoder() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(DATES_JSON, UTF_8) .build(); @@ -167,8 +162,7 @@ void customDecoderExpressedAsMapper() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(DATES_JSON, UTF_8) .build(); @@ -201,8 +195,7 @@ void decoderCharset() throws IOException { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(headers) .body( new String( @@ -228,8 +221,7 @@ void decodesToMap() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(json, UTF_8) .build(); @@ -307,8 +299,7 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new JacksonJrDecoder().decode(response, byte[].class)).isEmpty(); @@ -348,12 +339,7 @@ static Stream decodeGenericsArguments() { Response.Builder responseBuilder = Response.builder() .request( - Request.create( - HttpMethod.GET, - "/v1/dummy", - Collections.emptyMap(), - Request.Body.empty(), - null)); + Request.create(HttpMethod.GET, "/v1/dummy", Collections.emptyMap(), null, null)); return Stream.of( Arguments.of( responseBuilder.body("{\"data\":2024}", StandardCharsets.UTF_8).build(), diff --git a/jackson/src/main/java/feign/jackson/JacksonEncoder.java b/jackson/src/main/java/feign/jackson/JacksonEncoder.java index 48b169a8d3..280cd3bb58 100644 --- a/jackson/src/main/java/feign/jackson/JacksonEncoder.java +++ b/jackson/src/main/java/feign/jackson/JacksonEncoder.java @@ -21,8 +21,8 @@ import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import feign.Request; import feign.RequestTemplate; -import feign.Util; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.JsonEncoder; @@ -53,7 +53,7 @@ public JacksonEncoder(ObjectMapper mapper) { public void encode(Object object, Type bodyType, RequestTemplate template) { try { JavaType javaType = mapper.getTypeFactory().constructType(bodyType); - template.body(mapper.writerFor(javaType).writeValueAsBytes(object), Util.UTF_8); + template.body(Request.Body.of(mapper.writerFor(javaType).writeValueAsBytes(object))); } catch (JsonProcessingException e) { throw new EncodeException(e.getMessage(), e); } diff --git a/jackson/src/test/java/feign/jackson/JacksonCodecTest.java b/jackson/src/test/java/feign/jackson/JacksonCodecTest.java index 7de8ec3ad4..0097e066ee 100644 --- a/jackson/src/test/java/feign/jackson/JacksonCodecTest.java +++ b/jackson/src/test/java/feign/jackson/JacksonCodecTest.java @@ -32,7 +32,6 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; -import feign.Util; import java.io.Closeable; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -121,8 +120,7 @@ void decodes() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -136,8 +134,7 @@ void nullBodyDecodesToNull() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat(new JacksonDecoder().decode(response, String.class)).isNull(); @@ -149,8 +146,7 @@ void emptyBodyDecodesToNull() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -171,8 +167,7 @@ void customDecoder() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -220,8 +215,7 @@ void decoderCharset() throws IOException { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(headers) .body( new String( @@ -250,8 +244,7 @@ void decodesIterator() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -277,8 +270,7 @@ void nullBodyDecodesToEmptyIterator() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) JacksonIteratorDecoder.create().decode(response, byte[].class)).isEmpty(); @@ -290,8 +282,7 @@ void emptyBodyDecodesToEmptyIterator() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -364,8 +355,7 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new JacksonDecoder().decode(response, byte[].class)).isEmpty(); @@ -378,8 +368,7 @@ void notFoundDecodesToEmptyIterator() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) JacksonIteratorDecoder.create().decode(response, byte[].class)).isEmpty(); diff --git a/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java b/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java index 48bc1be058..e935b6d0f8 100644 --- a/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java +++ b/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java @@ -25,7 +25,6 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; -import feign.Util; import feign.codec.DecodeException; import feign.jackson.JacksonIteratorDecoder.JacksonIterator; import java.io.ByteArrayInputStream; @@ -123,8 +122,7 @@ public void close() throws IOException { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(inputStream, jsonBytes.length) .build(); @@ -150,8 +148,7 @@ public void close() throws IOException { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(inputStream, jsonBytes.length) .build(); @@ -181,8 +178,7 @@ JacksonIterator iterator(Class type, String json) throws IOException { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(json, UTF_8) .build(); diff --git a/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java b/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java index 90342c0162..273e6d8f79 100644 --- a/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java +++ b/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java @@ -16,8 +16,8 @@ package feign.jackson3; import com.fasterxml.jackson.annotation.JsonInclude; +import feign.Request; import feign.RequestTemplate; -import feign.Util; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.JsonEncoder; @@ -55,7 +55,7 @@ public Jackson3Encoder(JsonMapper mapper) { public void encode(Object object, Type bodyType, RequestTemplate template) { try { JavaType javaType = mapper.getTypeFactory().constructType(bodyType); - template.body(mapper.writerFor(javaType).writeValueAsBytes(object), Util.UTF_8); + template.body(Request.Body.of(mapper.writerFor(javaType).writeValueAsBytes(object))); } catch (JacksonException e) { throw new EncodeException(e.getMessage(), e); } diff --git a/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java b/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java index d91683033c..16236b2c6d 100644 --- a/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java +++ b/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java @@ -23,7 +23,6 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; -import feign.Util; import java.io.Closeable; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -122,8 +121,7 @@ void decodes() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -137,8 +135,7 @@ void nullBodyDecodesToNull() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat(new Jackson3Decoder().decode(response, String.class)).isNull(); @@ -150,8 +147,7 @@ void emptyBodyDecodesToNull() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -172,8 +168,7 @@ void customDecoder() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -221,8 +216,7 @@ void decoderCharset() throws IOException { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(headers) .body( new String( @@ -251,8 +245,7 @@ void decodesIterator() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -278,8 +271,7 @@ void nullBodyDecodesToEmptyIterator() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) Jackson3IteratorDecoder.create().decode(response, byte[].class)).isEmpty(); @@ -291,8 +283,7 @@ void emptyBodyDecodesToEmptyIterator() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -365,8 +356,7 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new Jackson3Decoder().decode(response, byte[].class)).isEmpty(); @@ -379,8 +369,7 @@ void notFoundDecodesToEmptyIterator() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) Jackson3IteratorDecoder.create().decode(response, byte[].class)).isEmpty(); diff --git a/java11/src/main/java/feign/http2client/Http2Client.java b/java11/src/main/java/feign/http2client/Http2Client.java index 40d4548a22..f1f4bb49b8 100644 --- a/java11/src/main/java/feign/http2client/Http2Client.java +++ b/java11/src/main/java/feign/http2client/Http2Client.java @@ -15,7 +15,10 @@ */ package feign.http2client; -import static feign.Util.*; +import static feign.Util.CONTENT_ENCODING; +import static feign.Util.ENCODING_DEFLATE; +import static feign.Util.ENCODING_GZIP; +import static feign.Util.enumForName; import feign.AsyncClient; import feign.Client; @@ -26,6 +29,9 @@ import feign.Util; import java.io.IOException; import java.io.InputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.io.UncheckedIOException; import java.lang.ref.SoftReference; import java.net.URI; import java.net.URISyntaxException; @@ -52,6 +58,9 @@ import java.util.TreeSet; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.stream.Collectors; import java.util.zip.GZIPInputStream; @@ -59,8 +68,23 @@ public class Http2Client implements Client, AsyncClient { + /** + * Dedicated default executor for the blocking body-writing bridge. Avoids starving the JVM-wide + * {@link java.util.concurrent.ForkJoinPool#commonPool()} when a thread is pinned per in-flight + * request. + */ + private static final Executor DEFAULT_EXECUTOR = + Executors.newCachedThreadPool( + runnable -> { + Thread thread = new Thread(runnable, "feign-http2-body-writer"); + thread.setDaemon(true); + return thread; + }); + private final HttpClient client; + private final Executor executor; + private final Map> clients = new ConcurrentHashMap<>(); /** @@ -83,12 +107,21 @@ public Http2Client() { .build()); } + public Http2Client(HttpClient client) { + this(client, DEFAULT_EXECUTOR); + } + public Http2Client(Options options) { - this(newClientBuilder(options).version(Version.HTTP_2).build()); + this(options, DEFAULT_EXECUTOR); } - public Http2Client(HttpClient client) { + public Http2Client(Options options, Executor executor) { + this(newClientBuilder(options).version(Version.HTTP_2).build(), executor); + } + + public Http2Client(HttpClient client, Executor executor) { this.client = Util.checkNotNull(client, "HttpClient must not be null"); + this.executor = Util.checkNotNull(executor, "Executor must not be null"); } @Override @@ -215,13 +248,8 @@ private static java.net.http.HttpClient.Builder newClientBuilder(Options options private Builder newRequestBuilder(Request request, Options options) throws URISyntaxException { URI uri = new URI(request.url()); - final BodyPublisher body; - final byte[] data = request.body(); - if (data == null) { - body = BodyPublishers.noBody(); - } else { - body = BodyPublishers.ofByteArray(data); - } + final BodyPublisher body = + request.body().map(this::createBodyPublisher).orElseGet(BodyPublishers::noBody); final Builder requestBuilder = HttpRequest.newBuilder() @@ -237,6 +265,31 @@ private Builder newRequestBuilder(Request request, Options options) throws URISy return requestBuilder.method(request.httpMethod().toString(), body); } + private BodyPublisher createBodyPublisher(Request.Body body) { + BodyPublisher publisher = + BodyPublishers.ofInputStream( + () -> { + PropagatingPipedInputStream inputStream = new PropagatingPipedInputStream(); + try { + PipedOutputStream outputStream = new PipedOutputStream(inputStream); + executor.execute( + () -> { + try (outputStream) { + body.writeTo(outputStream); + } catch (IOException e) { + inputStream.setException(e); + } + }); + return inputStream; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + return body.contentLength() > 0 + ? BodyPublishers.fromPublisher(publisher, body.contentLength()) + : publisher; + } + /** * There is a bunch o headers that the http2 client do not allow to be set. * @@ -278,4 +331,41 @@ private String[] asString(Map> headers) { .flatMap(List::stream)) .toArray(String[]::new); } + + /** + * A {@link PipedInputStream} that allows a writer thread to record an {@link IOException} via + * {@link #setException(IOException)} so subsequent reader calls throw an {@link IOException} + * wrapping the original cause; used to propagate write failures from the body-writer thread to + * the HTTP client reader. + */ + private static class PropagatingPipedInputStream extends PipedInputStream { + private final AtomicReference exception = new AtomicReference<>(); + + @Override + public synchronized int read() throws IOException { + checkException(); + int result = super.read(); + checkException(); + return result; + } + + @Override + public synchronized int read(byte[] b, int off, int len) throws IOException { + checkException(); + int result = super.read(b, off, len); + checkException(); + return result; + } + + public void setException(IOException e) { + exception.set(e); + } + + private void checkException() throws IOException { + IOException e = exception.get(); + if (e != null) { + throw new IOException("Body write failed", e); + } + } + } } diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java index 0d3cd6570b..d205f51470 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java @@ -16,7 +16,6 @@ package feign.http2client.test; import static feign.assertj.MockWebServerAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; @@ -529,7 +528,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (final FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + assertThat(e.contentUTF8()).isEmpty(); return; } fail(""); @@ -566,7 +565,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); @@ -770,7 +769,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(new HashMap<>()) .build(); } @@ -1028,9 +1027,9 @@ static final class TestInterfaceAsyncBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(new Gson().toJson(object)); + template.body(Request.Body.of(new Gson().toJson(object))); } else { - template.body(object.toString()); + template.body(Request.Body.of(object.toString())); } }); diff --git a/jaxb-jakarta/src/main/java/feign/jaxb/JAXBEncoder.java b/jaxb-jakarta/src/main/java/feign/jaxb/JAXBEncoder.java index 4ea3b7e998..a25845800b 100644 --- a/jaxb-jakarta/src/main/java/feign/jaxb/JAXBEncoder.java +++ b/jaxb-jakarta/src/main/java/feign/jaxb/JAXBEncoder.java @@ -15,6 +15,7 @@ */ package feign.jaxb; +import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -60,7 +61,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) { Marshaller marshaller = jaxbContextFactory.createMarshaller((Class) bodyType); StringWriter stringWriter = new StringWriter(); marshaller.marshal(object, stringWriter); - template.body(stringWriter.toString()); + template.body(Request.Body.of(stringWriter.toString())); } catch (JAXBException e) { throw new EncodeException(e.toString(), e); } diff --git a/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java b/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java index d79d3c4725..a4f62453de 100644 --- a/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java +++ b/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java @@ -17,14 +17,13 @@ import static feign.Util.UTF_8; import static feign.assertj.FeignAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; import feign.Request; import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; -import feign.Util; import feign.codec.DecodeException; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -199,8 +198,7 @@ void decodesXml() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -223,8 +221,7 @@ class ParameterizedHolder { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body("", UTF_8) .build(); @@ -272,10 +269,9 @@ void decodeAnnotatedParameterizedTypes() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) - .body(template.body()) + .body(template.requestBody().map(this::bodyAsBytes).orElse(null)) .build(); new JAXBDecoder(new JAXBContextFactory.Builder().build()).decode(response, Box.class); @@ -288,8 +284,7 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .build(); assertThat( @@ -312,8 +307,7 @@ void decodeThrowsExceptionWhenUnmarshallingFailsWithSetSchema() throws Exception Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -341,8 +335,7 @@ void decodesIgnoringErrorsWithEventHandler() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -393,6 +386,10 @@ void encodesIgnoringErrorsWithEventHandler() throws Exception { """); } + private byte[] bodyAsBytes(Request.Body body) { + return assertDoesNotThrow(body::writeToByteArray); + } + @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) static class MockIntObject { diff --git a/jaxb-jakarta/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java b/jaxb-jakarta/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java index d355afb691..b1f98bd8a2 100644 --- a/jaxb-jakarta/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java +++ b/jaxb-jakarta/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java @@ -16,10 +16,12 @@ package feign.jaxb.examples; import static feign.Util.UTF_8; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.Request; import feign.RequestTemplate; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.time.Clock; import javax.crypto.Mac; @@ -72,8 +74,7 @@ private static String canonicalString(RequestTemplate input, String host) { canonicalRequest.append("host").append('\n'); // HexEncode(Hash(Payload)) - byte[] data = input.body(); - String bodyText = (data != null) ? new String(data, input.requestCharset()) : null; + String bodyText = input.requestBody().map(AWSSignatureVersion4::bodyAsUtf8String).orElse(null); if (bodyText != null) { canonicalRequest.append(hex(sha256(bodyText))); } else { @@ -82,6 +83,10 @@ private static String canonicalString(RequestTemplate input, String host) { return canonicalRequest.toString(); } + private static String bodyAsUtf8String(Request.Body body) { + return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); + } + private static String toSign(String timestamp, String credentialScope, String canonicalRequest) { StringBuilder toSign = new StringBuilder(); // Algorithm + '\n' + @@ -116,7 +121,7 @@ public Request apply(RequestTemplate input) { if (!input.headers().isEmpty()) { throw new UnsupportedOperationException("headers not supported"); } - if (input.body() != null) { + if (input.requestBody().isPresent()) { throw new UnsupportedOperationException("body not supported"); } diff --git a/jaxb/src/main/java/feign/jaxb/JAXBEncoder.java b/jaxb/src/main/java/feign/jaxb/JAXBEncoder.java index aae439cae6..4c05d82e71 100644 --- a/jaxb/src/main/java/feign/jaxb/JAXBEncoder.java +++ b/jaxb/src/main/java/feign/jaxb/JAXBEncoder.java @@ -15,6 +15,7 @@ */ package feign.jaxb; +import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -60,7 +61,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) { Marshaller marshaller = jaxbContextFactory.createMarshaller((Class) bodyType); StringWriter stringWriter = new StringWriter(); marshaller.marshal(object, stringWriter); - template.body(stringWriter.toString()); + template.body(Request.Body.of(stringWriter.toString())); } catch (JAXBException e) { throw new EncodeException(e.toString(), e); } diff --git a/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java b/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java index 464d857b8c..139615175f 100644 --- a/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java +++ b/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java @@ -17,14 +17,13 @@ import static feign.Util.UTF_8; import static feign.assertj.FeignAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; import feign.Request; import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; -import feign.Util; import feign.codec.DecodeException; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -199,8 +198,7 @@ void decodesXml() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -223,8 +221,7 @@ class ParameterizedHolder { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body("", UTF_8) .build(); @@ -272,10 +269,9 @@ void decodeAnnotatedParameterizedTypes() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) - .body(template.body()) + .body(template.requestBody().map(this::bodyAsBytes).orElse(null)) .build(); new JAXBDecoder(new JAXBContextFactory.Builder().build()).decode(response, Box.class); @@ -288,8 +284,7 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .build(); assertThat( @@ -312,8 +307,7 @@ void decodeThrowsExceptionWhenUnmarshallingFailsWithSetSchema() throws Exception Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -341,8 +335,7 @@ void decodesIgnoringErrorsWithEventHandler() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -394,6 +387,10 @@ void encodesIgnoringErrorsWithEventHandler() throws Exception { """); } + private byte[] bodyAsBytes(Request.Body body) { + return assertDoesNotThrow(body::writeToByteArray); + } + @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) static class MockIntObject { diff --git a/jaxb/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java b/jaxb/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java index d355afb691..b1f98bd8a2 100644 --- a/jaxb/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java +++ b/jaxb/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java @@ -16,10 +16,12 @@ package feign.jaxb.examples; import static feign.Util.UTF_8; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.Request; import feign.RequestTemplate; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.time.Clock; import javax.crypto.Mac; @@ -72,8 +74,7 @@ private static String canonicalString(RequestTemplate input, String host) { canonicalRequest.append("host").append('\n'); // HexEncode(Hash(Payload)) - byte[] data = input.body(); - String bodyText = (data != null) ? new String(data, input.requestCharset()) : null; + String bodyText = input.requestBody().map(AWSSignatureVersion4::bodyAsUtf8String).orElse(null); if (bodyText != null) { canonicalRequest.append(hex(sha256(bodyText))); } else { @@ -82,6 +83,10 @@ private static String canonicalString(RequestTemplate input, String host) { return canonicalRequest.toString(); } + private static String bodyAsUtf8String(Request.Body body) { + return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); + } + private static String toSign(String timestamp, String credentialScope, String canonicalRequest) { StringBuilder toSign = new StringBuilder(); // Algorithm + '\n' + @@ -116,7 +121,7 @@ public Request apply(RequestTemplate input) { if (!input.headers().isEmpty()) { throw new UnsupportedOperationException("headers not supported"); } - if (input.body() != null) { + if (input.requestBody().isPresent()) { throw new UnsupportedOperationException("body not supported"); } diff --git a/jaxrs2/src/main/java/feign/jaxrs2/JAXRSClient.java b/jaxrs2/src/main/java/feign/jaxrs2/JAXRSClient.java index 5ecdb94511..555012f4b8 100644 --- a/jaxrs2/src/main/java/feign/jaxrs2/JAXRSClient.java +++ b/jaxrs2/src/main/java/feign/jaxrs2/JAXRSClient.java @@ -19,7 +19,6 @@ import feign.Request.Options; import java.io.IOException; import java.io.InputStream; -import java.nio.charset.Charset; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; @@ -32,7 +31,7 @@ import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import javax.ws.rs.core.Variant; +import javax.ws.rs.core.StreamingOutput; /** * This module directs Feign's http requests to javax.ws.rs.client.Client . Ex: @@ -77,15 +76,11 @@ public feign.Response execute(feign.Request request, Options options) throws IOE .build(); } - private Entity createRequestEntity(feign.Request request) { - if (request.body() == null) { - return null; - } - - return Entity.entity( - request.body(), - new Variant( - mediaType(request.headers()), locale(request.headers()), encoding(request.charset()))); + private Entity createRequestEntity(feign.Request request) { + return request + .body() + .map(body -> Entity.entity((StreamingOutput) body::writeTo, mediaType(request.headers()))) + .orElse(null); } private Integer integerHeader(Response response, String header) { @@ -102,22 +97,16 @@ private Integer integerHeader(Response response, String header) { } } - private String encoding(Charset charset) { - if (charset == null) return null; - - return charset.name(); - } - private String locale(Map> headers) { if (!headers.containsKey(HttpHeaders.CONTENT_LANGUAGE)) return null; return headers.get(HttpHeaders.CONTENT_LANGUAGE).iterator().next(); } - private MediaType mediaType(Map> headers) { - if (!headers.containsKey(HttpHeaders.CONTENT_TYPE)) return null; + private String mediaType(Map> headers) { + if (!headers.containsKey(HttpHeaders.CONTENT_TYPE)) return MediaType.APPLICATION_OCTET_STREAM; - return MediaType.valueOf(headers.get(HttpHeaders.CONTENT_TYPE).iterator().next()); + return headers.get(HttpHeaders.CONTENT_TYPE).iterator().next(); } private MultivaluedMap toMultivaluedMap(Map> headers) { diff --git a/json/src/main/java/feign/json/JsonEncoder.java b/json/src/main/java/feign/json/JsonEncoder.java index 655bb7594a..1ef3cd6fb1 100644 --- a/json/src/main/java/feign/json/JsonEncoder.java +++ b/json/src/main/java/feign/json/JsonEncoder.java @@ -17,6 +17,7 @@ import static java.lang.String.format; +import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -58,7 +59,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { if (object == null) return; if (object instanceof JSONArray || object instanceof JSONObject) { - template.body(object.toString()); + template.body(Request.Body.of(object.toString())); } else { throw new EncodeException(format("%s is not a type supported by this encoder.", bodyType)); } diff --git a/json/src/test/java/feign/json/JsonCodecTest.java b/json/src/test/java/feign/json/JsonCodecTest.java index becd040ee5..502b32eb9b 100644 --- a/json/src/test/java/feign/json/JsonCodecTest.java +++ b/json/src/test/java/feign/json/JsonCodecTest.java @@ -17,6 +17,7 @@ import static feign.Util.toByteArray; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.Feign; import feign.Param; @@ -27,6 +28,7 @@ import feign.mock.MockTarget; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import org.json.JSONArray; import org.json.JSONObject; import org.junit.jupiter.api.BeforeEach; @@ -80,8 +82,9 @@ void encodes() { "{\"login\":\"radio-rogal\",\"contributions\":0}"); JSONObject response = github.create("openfeign", "feign", contributor); Request request = mockClient.verifyOne(HttpMethod.POST, "/repos/openfeign/feign/contributors"); - assertThat(request.body()).isNotNull(); - String json = new String(request.body()); + assertThat(request.body()).isPresent(); + String json = + assertDoesNotThrow(() -> request.body().get().writeToString(StandardCharsets.UTF_8)); assertThat(json).contains("\"login\":\"radio-rogal\""); assertThat(json).contains("\"contributions\":0"); assertThat(response.getString("login")).isEqualTo("radio-rogal"); diff --git a/json/src/test/java/feign/json/JsonDecoderTest.java b/json/src/test/java/feign/json/JsonDecoderTest.java index 1635aa7f67..4147e3c469 100644 --- a/json/src/test/java/feign/json/JsonDecoderTest.java +++ b/json/src/test/java/feign/json/JsonDecoderTest.java @@ -26,7 +26,6 @@ import feign.Response; import feign.codec.DecodeException; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.time.Clock; import java.util.Collections; import org.json.JSONArray; @@ -54,8 +53,7 @@ static void setUpClass() { Request.HttpMethod.GET, "/qwerty", Collections.emptyMap(), - "xyz".getBytes(StandardCharsets.UTF_8), - StandardCharsets.UTF_8, + Request.Body.of("xyz"), null); } diff --git a/json/src/test/java/feign/json/JsonEncoderTest.java b/json/src/test/java/feign/json/JsonEncoderTest.java index a8d2d1f360..d7cb951026 100644 --- a/json/src/test/java/feign/json/JsonEncoderTest.java +++ b/json/src/test/java/feign/json/JsonEncoderTest.java @@ -15,12 +15,14 @@ */ package feign.json; -import static feign.Util.UTF_8; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; +import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; +import java.nio.charset.StandardCharsets; import java.time.Clock; import org.json.JSONArray; import org.json.JSONObject; @@ -49,20 +51,24 @@ void setUp() { void encodesArray() { new JsonEncoder().encode(jsonArray, JSONArray.class, requestTemplate); JSONAssert.assertEquals( - "[{\"a\":\"b\",\"c\":1},123]", new String(requestTemplate.body(), UTF_8), false); + "[{\"a\":\"b\",\"c\":1},123]", + requestTemplate.requestBody().map(this::bodyAsUtf8String).orElse(null), + false); } @Test void encodesObject() { new JsonEncoder().encode(jsonObject, JSONObject.class, requestTemplate); JSONAssert.assertEquals( - "{\"a\":\"b\",\"c\":1}", new String(requestTemplate.body(), UTF_8), false); + "{\"a\":\"b\",\"c\":1}", + requestTemplate.requestBody().map(this::bodyAsUtf8String).orElse(null), + false); } @Test void encodesNull() { new JsonEncoder().encode(null, JSONObject.class, new RequestTemplate()); - assertThat(requestTemplate.body()).isNull(); + assertThat(requestTemplate.requestBody()).isEmpty(); } @Test @@ -74,4 +80,8 @@ void unknownTypeThrowsEncodeException() { assertThat(exception.getMessage()) .isEqualTo("class java.time.Clock is not a type supported by this encoder."); } + + private String bodyAsUtf8String(Request.Body body) { + return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); + } } diff --git a/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt b/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt index aa1d25266b..3f02011df5 100644 --- a/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt +++ b/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt @@ -19,6 +19,7 @@ import com.google.gson.Gson import com.google.gson.JsonIOException import feign.Param import feign.QueryMapEncoder +import feign.Request import feign.RequestInterceptor import feign.RequestLine import feign.Response @@ -177,9 +178,9 @@ class CoroutineFeignTest { private val delegate = CoroutineFeign.builder() .decoder(DefaultDecoder()).encoder { `object`, bodyType, template -> if (`object` is Map<*, *>) { - template.body(Gson().toJson(`object`)) + template.body(Request.Body.of(Gson().toJson(`object`))) } else { - template.body(`object`.toString()) + template.body(Request.Body.of(`object`.toString())) } } diff --git a/micrometer/src/main/java/feign/micrometer/MeteredEncoder.java b/micrometer/src/main/java/feign/micrometer/MeteredEncoder.java index 2fb73d12f5..784aa86c3b 100644 --- a/micrometer/src/main/java/feign/micrometer/MeteredEncoder.java +++ b/micrometer/src/main/java/feign/micrometer/MeteredEncoder.java @@ -15,13 +15,19 @@ */ package feign.micrometer; +import static feign.Util.CONTENT_LENGTH; import static feign.micrometer.MetricTagResolver.EMPTY_TAGS_ARRAY; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; -import io.micrometer.core.instrument.*; +import io.micrometer.core.instrument.DistributionSummary; +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.Timer; import java.lang.reflect.Type; +import java.util.Collections; /** Wrap feign {@link Encoder} with metrics. */ public class MeteredEncoder implements Encoder { @@ -52,9 +58,11 @@ public void encode(Object object, Type bodyType, RequestTemplate template) createTimer(object, bodyType, template) .record(() -> encoder.encode(object, bodyType, template)); - if (template.body() != null) { - createSummary(object, bodyType, template).record(template.body().length); - } + template.headers().getOrDefault(CONTENT_LENGTH, Collections.emptySet()).stream() + .findFirst() + .ifPresent( + contentLength -> + createSummary(object, bodyType, template).record(Long.parseLong(contentLength))); } protected Timer createTimer(Object object, Type bodyType, RequestTemplate template) { diff --git a/mock/src/main/java/feign/mock/RequestKey.java b/mock/src/main/java/feign/mock/RequestKey.java index 50ed918e48..1d572875e3 100644 --- a/mock/src/main/java/feign/mock/RequestKey.java +++ b/mock/src/main/java/feign/mock/RequestKey.java @@ -18,10 +18,9 @@ import static feign.Util.UTF_8; import feign.Request; -import feign.Util; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; -import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collection; import java.util.Map; @@ -36,8 +35,6 @@ public static class Builder { private RequestHeaders headers; - private Charset charset; - private byte[] body; private Builder(HttpMethod method, String url) { @@ -56,11 +53,6 @@ public Builder headers(RequestHeaders headers) { return this; } - public Builder charset(Charset charset) { - this.charset = charset; - return this; - } - public Builder body(String body) { return body(body.getBytes(UTF_8)); } @@ -85,7 +77,7 @@ public static RequestKey create(Request request) { private static String buildUrl(Request request) { try { - return URLDecoder.decode(request.url(), Util.UTF_8.name()); + return URLDecoder.decode(request.url(), UTF_8.name()); } catch (final UnsupportedEncodingException e) { throw new RuntimeException(e); } @@ -97,15 +89,12 @@ private static String buildUrl(Request request) { private final RequestHeaders headers; - private final Charset charset; - private final byte[] body; private RequestKey(Builder builder) { this.method = builder.method; this.url = builder.url; this.headers = builder.headers; - this.charset = builder.charset; this.body = builder.body; } @@ -113,8 +102,19 @@ private RequestKey(Request request) { this.method = HttpMethod.valueOf(request.httpMethod().name()); this.url = buildUrl(request); this.headers = RequestHeaders.of(request.headers()); - this.charset = request.charset(); - this.body = request.body(); + this.body = + request + .body() + .filter(Request.Body::isRepeatable) + .map( + body -> { + try { + return body.writeToByteArray(); + } catch (IOException ignored) { + return null; + } + }) + .orElse(null); } public HttpMethod getMethod() { @@ -129,10 +129,6 @@ public RequestHeaders getHeaders() { return headers; } - public Charset getCharset() { - return charset; - } - public byte[] getBody() { return body; } @@ -171,10 +167,8 @@ public boolean equalsExtended(Object obj) { RequestKey other = (RequestKey) obj; boolean headersEqual = other.headers == null || headers == null || headers.equals(other.headers); - boolean charsetEqual = - other.charset == null || charset == null || charset.equals(other.charset); - boolean bodyEqual = other.body == null || body == null || Arrays.equals(other.body, body); - return headersEqual && charsetEqual && bodyEqual; + boolean bodyEqual = other.body == null || body == null || Arrays.equals(body, other.body); + return headersEqual && bodyEqual; } return false; } @@ -182,10 +176,7 @@ public boolean equalsExtended(Object obj) { @Override public String toString() { return String.format( - "Request [%s %s: %s headers and %s]", - method, - url, - headers == null ? "without" : "with " + headers, - charset == null ? "no charset" : "charset " + charset); + "Request [%s %s: %s headers]", + method, url, headers == null ? "without" : "with " + headers); } } diff --git a/mock/src/test/java/feign/mock/MockClientTest.java b/mock/src/test/java/feign/mock/MockClientTest.java index 77916f4194..3f14d92d90 100644 --- a/mock/src/test/java/feign/mock/MockClientTest.java +++ b/mock/src/test/java/feign/mock/MockClientTest.java @@ -15,10 +15,10 @@ */ package feign.mock; -import static feign.Util.UTF_8; import static feign.Util.toByteArray; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.Body; import feign.Feign; @@ -36,7 +36,9 @@ import java.io.InputStream; import java.lang.reflect.Type; import java.net.HttpURLConnection; +import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -97,16 +99,6 @@ public Object decode(Response response, Type type) void setup() throws IOException { try (InputStream input = getClass().getResourceAsStream("/fixtures/contributors.json")) { byte[] data = toByteArray(input); - RequestKey postContributorKey = - RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") - .charset(UTF_8) - .headers( - RequestHeaders.builder() - .add("Content-Length", "55") - .add("Content-Type", "application/json") - .build()) - .body("{\"login\":\"velo_at_github\",\"type\":\"preposterous hacker\"}") - .build(); mockClient = new MockClient(); github = Feign.builder() @@ -119,7 +111,10 @@ void setup() throws IOException { HttpMethod.GET, "/repos/netflix/feign/contributors?client_id=7 7", new ByteArrayInputStream(data)) - .ok(postContributorKey, "{\"login\":\"velo\",\"contributions\":0}") + .ok( + HttpMethod.POST, + "/repos/netflix/feign/contributors", + "{\"login\":\"velo\",\"contributions\":0}") .noContent(HttpMethod.PATCH, "/repos/velo/feign-mock/contributors") .add( HttpMethod.GET, @@ -180,16 +175,6 @@ void paramsEncoding() { @Test void verifyInvocation() { - RequestKey testRequestKey = - RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") - .headers( - RequestHeaders.builder() - .add("Content-Length", "55") - .add("Content-Type", "application/json") - .build()) - .body("{\"login\":\"velo_at_github\",\"type\":\"preposterous hacker\"}") - .build(); - Contributor contribution = github.create("netflix", "feign", "velo_at_github", "preposterous hacker"); // making sure it received a proper response @@ -200,14 +185,12 @@ void verifyInvocation() { List results = mockClient.verifyTimes(HttpMethod.POST, "/repos/netflix/feign/contributors", 1); assertThat(results).hasSize(1); - results = mockClient.verifyTimes(testRequestKey, 1); - assertThat(results).hasSize(1); - assertThat(mockClient.verifyOne(testRequestKey).body()).isNotNull(); - byte[] body = mockClient.verifyOne(HttpMethod.POST, "/repos/netflix/feign/contributors").body(); - assertThat(body).isNotNull(); + Optional body = + mockClient.verifyOne(HttpMethod.POST, "/repos/netflix/feign/contributors").body(); + assertThat(body).isPresent(); - String message = new String(body); + String message = assertDoesNotThrow(() -> body.get().writeToString(StandardCharsets.UTF_8)); assertThat(message).contains("velo_at_github"); assertThat(message).contains("preposterous hacker"); @@ -222,7 +205,6 @@ void verifyNone() { testRequestKey = RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") - .charset(UTF_8) .headers( RequestHeaders.builder() .add("Content-Length", "55") @@ -243,7 +225,6 @@ void verifyNone() { testRequestKey = RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") - .charset(UTF_8) .headers( RequestHeaders.builder() .add("Content-Length", "55") diff --git a/mock/src/test/java/feign/mock/RequestKeyTest.java b/mock/src/test/java/feign/mock/RequestKeyTest.java index 23d6d75fb2..9b03f3c0eb 100644 --- a/mock/src/test/java/feign/mock/RequestKeyTest.java +++ b/mock/src/test/java/feign/mock/RequestKeyTest.java @@ -18,7 +18,6 @@ import static org.assertj.core.api.Assertions.assertThat; import feign.Request; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; @@ -33,12 +32,7 @@ class RequestKeyTest { @BeforeEach void setUp() { RequestHeaders headers = RequestHeaders.builder().add("my-header", "val").build(); - requestKey = - RequestKey.builder(HttpMethod.GET, "a") - .headers(headers) - .charset(StandardCharsets.UTF_16) - .body("content") - .build(); + requestKey = RequestKey.builder(HttpMethod.GET, "a").headers(headers).body("content").build(); } @Test @@ -47,7 +41,6 @@ void builder() throws Exception { assertThat(requestKey.getUrl()).isEqualTo("a"); assertThat(requestKey.getHeaders().size()).isEqualTo(1); assertThat(requestKey.getHeaders().fetch("my-header")).isEqualTo(Arrays.asList("val")); - assertThat(requestKey.getCharset()).isEqualTo(StandardCharsets.UTF_16); } @SuppressWarnings("deprecation") @@ -56,20 +49,13 @@ void create() throws Exception { Map> map = new HashMap<>(); map.put("my-header", Arrays.asList("val")); Request request = - Request.create( - Request.HttpMethod.GET, - "a", - map, - "content".getBytes(StandardCharsets.UTF_8), - StandardCharsets.UTF_16); + Request.create(Request.HttpMethod.GET, "a", map, Request.Body.of("content"), null); requestKey = RequestKey.create(request); assertThat(requestKey.getMethod()).isEqualTo(HttpMethod.GET); assertThat(requestKey.getUrl()).isEqualTo("a"); assertThat(requestKey.getHeaders().size()).isEqualTo(1); assertThat(requestKey.getHeaders().fetch("my-header")).isEqualTo(Arrays.asList("val")); - assertThat(requestKey.getCharset()).isEqualTo(StandardCharsets.UTF_16); - assertThat(requestKey.getBody()).isEqualTo("content".getBytes(StandardCharsets.UTF_8)); } @Test @@ -117,11 +103,7 @@ void equalMinimum() { @Test void equalExtra() { RequestHeaders headers = RequestHeaders.builder().add("my-other-header", "other value").build(); - RequestKey requestKey2 = - RequestKey.builder(HttpMethod.GET, "a") - .headers(headers) - .charset(StandardCharsets.ISO_8859_1) - .build(); + RequestKey requestKey2 = RequestKey.builder(HttpMethod.GET, "a").headers(headers).build(); assertThat(requestKey.hashCode()).isEqualTo(requestKey2.hashCode()); assertThat(requestKey).isEqualTo(requestKey2); @@ -138,11 +120,7 @@ void equalsExtended() { @Test void equalsExtendedExtra() { RequestHeaders headers = RequestHeaders.builder().add("my-other-header", "other value").build(); - RequestKey requestKey2 = - RequestKey.builder(HttpMethod.GET, "a") - .headers(headers) - .charset(StandardCharsets.ISO_8859_1) - .build(); + RequestKey requestKey2 = RequestKey.builder(HttpMethod.GET, "a").headers(headers).build(); assertThat(requestKey.hashCode()).isEqualTo(requestKey2.hashCode()); assertThat(requestKey.equalsExtended(requestKey2)).isEqualTo(false); @@ -151,7 +129,7 @@ void equalsExtendedExtra() { @Test void testToString() throws Exception { assertThat(requestKey.toString()).startsWith("Request [GET a: "); - assertThat(requestKey.toString()).contains(" with my-header=[val] ", " UTF-16]"); + assertThat(requestKey.toString()).contains(" with my-header=[val] "); } @Test @@ -159,7 +137,6 @@ void toStringSimple() throws Exception { requestKey = RequestKey.builder(HttpMethod.GET, "a").build(); assertThat(requestKey.toString()).startsWith("Request [GET a: "); - assertThat(requestKey.toString()).contains(" without ", " no charset"); + assertThat(requestKey.toString()).contains(" without "); } } -// diff --git a/moshi/src/main/java/feign/moshi/MoshiEncoder.java b/moshi/src/main/java/feign/moshi/MoshiEncoder.java index b65f705e27..fdd7507741 100644 --- a/moshi/src/main/java/feign/moshi/MoshiEncoder.java +++ b/moshi/src/main/java/feign/moshi/MoshiEncoder.java @@ -17,6 +17,7 @@ import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.Moshi; +import feign.Request; import feign.RequestTemplate; import feign.codec.Encoder; import feign.codec.JsonEncoder; @@ -41,6 +42,6 @@ public MoshiEncoder(Iterable> adapters) { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { JsonAdapter jsonAdapter = moshi.adapter(bodyType).indent(" "); - template.body(jsonAdapter.toJson(object)); + template.body(Request.Body.of(jsonAdapter.toJson(object))); } } diff --git a/moshi/src/test/java/feign/moshi/MoshiDecoderTest.java b/moshi/src/test/java/feign/moshi/MoshiDecoderTest.java index 885a57b6df..7aabefc708 100644 --- a/moshi/src/test/java/feign/moshi/MoshiDecoderTest.java +++ b/moshi/src/test/java/feign/moshi/MoshiDecoderTest.java @@ -22,7 +22,6 @@ import com.squareup.moshi.Moshi; import feign.Request; import feign.Response; -import feign.Util; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; @@ -60,8 +59,7 @@ class Zone extends LinkedHashMap { .reason("OK") .headers(Collections.emptyMap()) .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(zonesJson, UTF_8) .build(); @@ -106,8 +104,7 @@ void nullBodyDecodesToNull() throws Exception { .reason("OK") .headers(Collections.emptyMap()) .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .build(); assertThat(new MoshiDecoder().decode(response, String.class)).isNull(); } @@ -120,8 +117,7 @@ void emptyBodyDecodesToNull() throws Exception { .reason("OK") .headers(Collections.emptyMap()) .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); assertThat(new MoshiDecoder().decode(response, String.class)).isNull(); @@ -136,8 +132,7 @@ void notFoundDecodesToEmpty() throws Exception { .reason("NOT FOUND") .headers(Collections.emptyMap()) .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .build(); assertThat((byte[]) new MoshiDecoder().decode(response, byte[].class)).isEmpty(); } @@ -158,8 +153,7 @@ void customDecoder() throws Exception { .reason("OK") .headers(Collections.emptyMap()) .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(zonesJson, UTF_8) .build(); @@ -181,8 +175,7 @@ void customObjectDecoder() throws Exception { .reason("OK") .headers(Collections.emptyMap()) .request( - Request.create( - Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .body(videoGamesJson, UTF_8) .build(); diff --git a/okhttp/src/main/java/feign/okhttp/OkHttpClient.java b/okhttp/src/main/java/feign/okhttp/OkHttpClient.java index 25a8b7f1b1..ee582ad7a4 100644 --- a/okhttp/src/main/java/feign/okhttp/OkHttpClient.java +++ b/okhttp/src/main/java/feign/okhttp/OkHttpClient.java @@ -29,7 +29,15 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import okhttp3.*; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.Headers; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.BufferedSink; /** * This module directs Feign's http requests to @@ -67,9 +75,6 @@ static Request toOkHttpRequest(feign.Request input) { requestBuilder.addHeader(field, value); if (field.equalsIgnoreCase("Content-Type")) { mediaType = MediaType.parse(value); - if (input.charset() != null) { - mediaType.charset(input.charset()); - } } } } @@ -78,21 +83,42 @@ static Request toOkHttpRequest(feign.Request input) { requestBuilder.addHeader("Accept", "*/*"); } - byte[] inputBody = input.body(); - if (input.httpMethod().isWithBody()) { - requestBuilder.removeHeader("Content-Type"); - if (inputBody == null) { - // write an empty BODY to conform with okhttp 2.4.0+ - // http://johnfeng.github.io/blog/2015/06/30/okhttp-updates-post-wouldnt-be-allowed-to-have-null-body/ - inputBody = new byte[0]; - } - } - - RequestBody body = inputBody != null ? RequestBody.create(mediaType, inputBody) : null; + RequestBody body = input.httpMethod().isWithBody() ? toRequestBody(input, mediaType) : null; requestBuilder.method(input.httpMethod().name(), body); return requestBuilder.build(); } + static RequestBody toRequestBody(feign.Request request, MediaType mediaType) { + return request + .body() + .map(body -> toRequestBody(body, mediaType)) + .orElseGet(() -> RequestBody.create(new byte[0], mediaType)); + } + + static RequestBody toRequestBody(feign.Request.Body body, MediaType mediaType) { + return new RequestBody() { + @Override + public MediaType contentType() { + return mediaType; + } + + @Override + public long contentLength() { + return body.contentLength(); + } + + @Override + public boolean isOneShot() { + return !body.isRepeatable(); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + body.writeTo(sink.outputStream()); + } + }; + } + private static feign.Response toFeignResponse(Response response, feign.Request request) throws IOException { return feign.Response.builder() diff --git a/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java b/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java index 79150b86b9..c03eb1ef4b 100644 --- a/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java +++ b/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java @@ -16,7 +16,6 @@ package feign.okhttp; import static feign.assertj.MockWebServerAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; @@ -528,7 +527,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (final FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + assertThat(e.contentUTF8()).isEmpty(); return; } fail(""); @@ -565,7 +564,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) .body(new byte[0]) .build(); @@ -769,7 +768,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(new HashMap<>()) .build(); } @@ -1027,9 +1026,9 @@ static final class TestInterfaceAsyncBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(new Gson().toJson(object)); + template.body(Request.Body.of(new Gson().toJson(object))); } else { - template.body(object.toString()); + template.body(Request.Body.of(object.toString())); } }); diff --git a/pom.xml b/pom.xml index 3b613d5f81..afcb4317da 100644 --- a/pom.xml +++ b/pom.xml @@ -983,6 +983,14 @@ @feign.Experimental feign.graphql + + feign.Request + + feign.RequestTemplate + + feign.mock.RequestKey + + feign.vertx.VertxHttpClient public diff --git a/ribbon/src/main/java/feign/ribbon/LBClient.java b/ribbon/src/main/java/feign/ribbon/LBClient.java index 1062abb173..260b57df9e 100644 --- a/ribbon/src/main/java/feign/ribbon/LBClient.java +++ b/ribbon/src/main/java/feign/ribbon/LBClient.java @@ -122,15 +122,18 @@ static class RibbonRequest extends ClientRequest implements Cloneable { @SuppressWarnings("deprecation") Request toRequest() { - // add header "Content-Length" according to the request body - final byte[] body = request.body(); - final int bodyLength = body != null ? body.length : 0; // create a new Map to avoid side effect, not to change the old headers Map> headers = new LinkedHashMap>(); headers.putAll(request.headers()); - headers.put(Util.CONTENT_LENGTH, Collections.singletonList(String.valueOf(bodyLength))); + String contentLength = + request.body().map(body -> String.valueOf(body.contentLength())).orElse("0"); + headers.put(Util.CONTENT_LENGTH, Collections.singletonList(contentLength)); return Request.create( - request.httpMethod(), getUri().toASCIIString(), headers, body, request.charset()); + request.httpMethod(), + getUri().toASCIIString(), + headers, + request.body().orElse(null), + null); } Client client() { diff --git a/ribbon/src/test/java/feign/ribbon/LBClientTest.java b/ribbon/src/test/java/feign/ribbon/LBClientTest.java index ad29059cbe..b2086c6744 100644 --- a/ribbon/src/test/java/feign/ribbon/LBClientTest.java +++ b/ribbon/src/test/java/feign/ribbon/LBClientTest.java @@ -22,7 +22,6 @@ import feign.ribbon.LBClient.RibbonRequest; import java.net.URI; import java.net.URISyntaxException; -import java.nio.charset.Charset; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; @@ -48,8 +47,7 @@ void ribbonRequest() throws URISyntaxException { URI uri = new URI(urlWithEncodedJson); Map> headers = new LinkedHashMap<>(); // create a Request for recreating another Request by toRequest() - Request requestOrigin = - Request.create(method, uri.toASCIIString(), headers, null, Charset.forName("utf-8")); + Request requestOrigin = Request.create(method, uri.toASCIIString(), headers, null, null); RibbonRequest ribbonRequest = new RibbonRequest(null, requestOrigin, uri); // use toRequest() recreate a Request diff --git a/sax/src/test/java/feign/sax/SAXDecoderTest.java b/sax/src/test/java/feign/sax/SAXDecoderTest.java index 21fdc29890..5b23f6eb1e 100644 --- a/sax/src/test/java/feign/sax/SAXDecoderTest.java +++ b/sax/src/test/java/feign/sax/SAXDecoderTest.java @@ -22,7 +22,6 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; -import feign.Util; import feign.codec.Decoder; import java.io.IOException; import java.text.ParseException; @@ -77,7 +76,7 @@ private Response statusFailedResponse() { return Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body(statusFailed, UTF_8) .build(); @@ -89,8 +88,7 @@ void nullBodyDecodesToEmpty() throws Exception { Response.builder() .status(204) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .build(); assertThat((byte[]) decoder.decode(response, byte[].class)).isEmpty(); @@ -103,8 +101,7 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .build(); assertThat((byte[]) decoder.decode(response, byte[].class)).isEmpty(); diff --git a/sax/src/test/java/feign/sax/examples/AWSSignatureVersion4.java b/sax/src/test/java/feign/sax/examples/AWSSignatureVersion4.java index aac5a2ede5..bfb107a583 100644 --- a/sax/src/test/java/feign/sax/examples/AWSSignatureVersion4.java +++ b/sax/src/test/java/feign/sax/examples/AWSSignatureVersion4.java @@ -16,10 +16,12 @@ package feign.sax.examples; import static feign.Util.UTF_8; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.Request; import feign.RequestTemplate; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.time.Clock; import javax.crypto.Mac; @@ -72,8 +74,7 @@ private static String canonicalString(RequestTemplate input, String host) { canonicalRequest.append("host").append('\n'); // HexEncode(Hash(Payload)) - byte[] data = input.body(); - String bodyText = (data != null) ? new String(data, input.requestCharset()) : null; + String bodyText = input.requestBody().map(AWSSignatureVersion4::bodyAsUtf8String).orElse(null); if (bodyText != null) { canonicalRequest.append(hex(sha256(bodyText))); } else { @@ -82,6 +83,10 @@ private static String canonicalString(RequestTemplate input, String host) { return canonicalRequest.toString(); } + private static String bodyAsUtf8String(Request.Body body) { + return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); + } + private static String toSign(String timestamp, String credentialScope, String canonicalRequest) { StringBuilder toSign = new StringBuilder(); // Algorithm + '\n' + @@ -116,7 +121,7 @@ public Request apply(RequestTemplate input) { if (!input.headers().isEmpty()) { throw new UnsupportedOperationException("headers not supported"); } - if (input.body() != null) { + if (input.requestBody().isPresent()) { throw new UnsupportedOperationException("body not supported"); } diff --git a/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java b/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java index c4eaf5bfd5..12973ff4e9 100644 --- a/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java +++ b/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java @@ -21,7 +21,6 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; -import feign.Util; import java.util.Collection; import java.util.Collections; import org.junit.jupiter.api.Test; @@ -42,7 +41,7 @@ public class Slf4jLoggerTest { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body(new byte[0]) .build(); diff --git a/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java b/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java index 709b7f2a13..31bc768304 100644 --- a/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java +++ b/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java @@ -15,6 +15,7 @@ */ package feign.soap; +import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -32,7 +33,11 @@ import java.nio.charset.StandardCharsets; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.*; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; @@ -131,7 +136,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) { } else { soapMessage.writeTo(bos); } - template.body(bos.toString()); + template.body(Request.Body.of(bos.toByteArray())); } catch (SOAPException | JAXBException | ParserConfigurationException diff --git a/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java b/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java index 0cbb94be42..8634ff9815 100644 --- a/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java +++ b/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java @@ -17,14 +17,13 @@ import static feign.Util.UTF_8; import static feign.assertj.FeignAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; import feign.Request; import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; -import feign.Util; import feign.codec.Encoder; import feign.jaxb.JAXBContextFactory; import jakarta.xml.bind.annotation.XmlAccessType; @@ -254,8 +253,7 @@ void decodesSoap() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -290,8 +288,7 @@ void decodesSoapWithSchemaOnEnvelope() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -328,8 +325,7 @@ void decodesSoap1_2Protocol() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -353,8 +349,7 @@ class ParameterizedHolder { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body( """ @@ -404,10 +399,9 @@ void decodeAnnotatedParameterizedTypes() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) - .body(template.body()) + .body(template.requestBody().map(this::bodyAsBytes).orElse(null)) .build(); new SOAPDecoder(new JAXBContextFactory.Builder().build()).decode(response, Box.class); @@ -420,8 +414,7 @@ void notFoundDecodesToNull() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat( @@ -466,6 +459,10 @@ void changeSoapProtocolAndSetHeader() { assertThat(template).hasBody(soapEnvelop); } + private byte[] bodyAsBytes(Request.Body body) { + return assertDoesNotThrow(body::writeToByteArray); + } + @XmlRootElement static class Box { diff --git a/soap-jakarta/src/test/java/feign/soap/SOAPFaultDecoderTest.java b/soap-jakarta/src/test/java/feign/soap/SOAPFaultDecoderTest.java index c94f83b16a..85cd3979a5 100644 --- a/soap-jakarta/src/test/java/feign/soap/SOAPFaultDecoderTest.java +++ b/soap-jakarta/src/test/java/feign/soap/SOAPFaultDecoderTest.java @@ -23,7 +23,6 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; -import feign.Util; import feign.jaxb.JAXBContextFactory; import jakarta.xml.soap.SOAPConstants; import jakarta.xml.ws.soap.SOAPFaultException; @@ -50,8 +49,7 @@ void soapDecoderThrowsSOAPFaultException() throws IOException { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(getResourceBytes("/samples/SOAP_1_2_FAULT.xml")) .build(); @@ -73,8 +71,7 @@ void errorDecoderReturnsSOAPFaultException() throws IOException { Response.builder() .status(400) .reason("BAD REQUEST") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(getResourceBytes("/samples/SOAP_1_1_FAULT.xml")) .build(); @@ -91,8 +88,7 @@ void errorDecoderReturnsFeignExceptionOn503Status() throws IOException { Response.builder() .status(503) .reason("Service Unavailable") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body("Service Unavailable", UTF_8) .build(); @@ -123,8 +119,7 @@ void errorDecoderReturnsFeignExceptionOnEmptyFault() throws IOException { Response.builder() .status(500) .reason("Internal Server Error") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(responseBody, UTF_8) .build(); diff --git a/soap/src/main/java/feign/soap/SOAPEncoder.java b/soap/src/main/java/feign/soap/SOAPEncoder.java index 24f10da917..711c44171f 100644 --- a/soap/src/main/java/feign/soap/SOAPEncoder.java +++ b/soap/src/main/java/feign/soap/SOAPEncoder.java @@ -15,6 +15,7 @@ */ package feign.soap; +import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -135,7 +136,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) { } else { soapMessage.writeTo(bos); } - template.body(new String(bos.toByteArray())); + template.body(Request.Body.of(bos.toByteArray())); } catch (SOAPException | JAXBException | ParserConfigurationException diff --git a/soap/src/test/java/feign/soap/SOAPCodecTest.java b/soap/src/test/java/feign/soap/SOAPCodecTest.java index 002a0e33b6..59d38432da 100644 --- a/soap/src/test/java/feign/soap/SOAPCodecTest.java +++ b/soap/src/test/java/feign/soap/SOAPCodecTest.java @@ -17,14 +17,13 @@ import static feign.Util.UTF_8; import static feign.assertj.FeignAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; import feign.Request; import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; -import feign.Util; import feign.codec.Encoder; import feign.jaxb.JAXBContextFactory; import java.lang.reflect.Type; @@ -254,8 +253,7 @@ void decodesSoap() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -290,8 +288,7 @@ void decodesSoapWithSchemaOnEnvelope() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -328,8 +325,7 @@ void decodesSoap1_2Protocol() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -353,8 +349,7 @@ class ParameterizedHolder { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body( """ @@ -414,10 +409,9 @@ void decodeAnnotatedParameterizedTypes() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) - .body(template.body()) + .body(template.requestBody().map(this::bodyAsBytes).orElse(null)) .build(); new SOAPDecoder(new JAXBContextFactory.Builder().build()).decode(response, Box.class); @@ -430,8 +424,7 @@ void notFoundDecodesToNull() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .build(); assertThat( @@ -476,6 +469,10 @@ void changeSoapProtocolAndSetHeader() { assertThat(template).hasBody(soapEnvelop); } + private byte[] bodyAsBytes(Request.Body body) { + return assertDoesNotThrow(body::writeToByteArray); + } + static class ChangedProtocolAndHeaderSOAPEncoder extends SOAPEncoder { public ChangedProtocolAndHeaderSOAPEncoder(JAXBContextFactory jaxbContextFactory) { diff --git a/soap/src/test/java/feign/soap/SOAPFaultDecoderTest.java b/soap/src/test/java/feign/soap/SOAPFaultDecoderTest.java index 15d3f76696..810f173f11 100644 --- a/soap/src/test/java/feign/soap/SOAPFaultDecoderTest.java +++ b/soap/src/test/java/feign/soap/SOAPFaultDecoderTest.java @@ -23,7 +23,6 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; -import feign.Util; import feign.jaxb.JAXBContextFactory; import java.io.DataInputStream; import java.io.IOException; @@ -43,8 +42,7 @@ void soapDecoderThrowsSOAPFaultException() throws IOException { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(getResourceBytes("/samples/SOAP_1_2_FAULT.xml")) .build(); @@ -65,8 +63,7 @@ void errorDecoderReturnsSOAPFaultException() throws IOException { Response.builder() .status(400) .reason("BAD REQUEST") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(getResourceBytes("/samples/SOAP_1_1_FAULT.xml")) .build(); @@ -83,8 +80,7 @@ void errorDecoderReturnsFeignExceptionOn503Status() throws IOException { Response.builder() .status(503) .reason("Service Unavailable") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body("Service Unavailable", UTF_8) .build(); @@ -115,8 +111,7 @@ void errorDecoderReturnsFeignExceptionOnEmptyFault() throws IOException { Response.builder() .status(500) .reason("Internal Server Error") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.emptyMap()) .body(responseBody, UTF_8) .build(); diff --git a/spring/src/test/java/feign/spring/SpringContractTest.java b/spring/src/test/java/feign/spring/SpringContractTest.java index 4f0277d70e..7788815757 100755 --- a/spring/src/test/java/feign/spring/SpringContractTest.java +++ b/spring/src/test/java/feign/spring/SpringContractTest.java @@ -16,6 +16,7 @@ package feign.spring; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; import feign.Feign; @@ -181,7 +182,8 @@ void nonRequiredRequestBodyIsNull() { resource.checkWithNonRequiredRequestBody(null); Request request = mockClient.verifyOne(HttpMethod.POST, "/health/withNonRequiredRequestBody"); - assertThat(request.requestTemplate().body()).asString().isEqualTo("null"); + assertThat(request.requestTemplate().requestBody().map(this::bodyAsUtf8String)) + .contains("null"); } @Test @@ -191,7 +193,8 @@ void nonRequiredRequestBodyIsObject() { resource.checkWithNonRequiredRequestBody(object); Request request = mockClient.verifyOne(HttpMethod.POST, "/health/withNonRequiredRequestBody"); - assertThat(request.requestTemplate().body()).asString().contains("\"name\" : \"hello\""); + assertThat(request.requestTemplate().requestBody().map(this::bodyAsUtf8String).orElse(null)) + .contains("\"name\" : \"hello\""); } @Test @@ -281,6 +284,10 @@ void consumeAndProduce() { assertThat(request.headers()).containsEntry("Accept", Arrays.asList("text/plain")); } + private String bodyAsUtf8String(Request.Body body) { + return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); + } + interface GenericResource { @RequestMapping(value = "generic", method = RequestMethod.GET) diff --git a/vertx/feign-vertx/src/main/java/feign/VertxFeign.java b/vertx/feign-vertx/src/main/java/feign/VertxFeign.java index 09a6264ebe..24a24cef59 100644 --- a/vertx/feign-vertx/src/main/java/feign/VertxFeign.java +++ b/vertx/feign-vertx/src/main/java/feign/VertxFeign.java @@ -28,6 +28,7 @@ import feign.querymap.FieldQueryMapEncoder; import feign.vertx.VertxDelegatingContract; import feign.vertx.VertxHttpClient; +import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.client.HttpRequest; import io.vertx.ext.web.client.WebClient; @@ -94,6 +95,7 @@ public T newInstance(final Target target) { /** VertxFeign builder. */ public static final class Builder extends Feign.Builder { + private Vertx vertx; private WebClient webClient; private final List requestInterceptors = new ArrayList<>(); private Logger.Level logLevel = Logger.Level.NONE; @@ -122,6 +124,11 @@ public Builder invocationHandlerFactory( throw new UnsupportedOperationException(); } + public Builder vertx(final Vertx vertx) { + this.vertx = vertx; + return this; + } + /** * Sets a vertx WebClient. * @@ -370,10 +377,12 @@ public Feign.Builder options(final Request.Options options) { @Override public VertxFeign internalBuild() { + checkNotNull(this.vertx, "Vertx instance wasn't provided in VertxFeign builder"); checkNotNull( this.webClient, "Vertx WebClient instance wasn't provided in VertxFeign builder"); - final VertxHttpClient client = new VertxHttpClient(webClient, timeout, requestPreProcessor); + final VertxHttpClient client = + new VertxHttpClient(vertx, webClient, timeout, requestPreProcessor); final VertxMethodHandler.Factory methodHandlerFactory = new VertxMethodHandler.Factory( client, retryer, requestInterceptors, logger, logLevel, decode404); diff --git a/vertx/feign-vertx/src/main/java/feign/vertx/OutputToReadStream.java b/vertx/feign-vertx/src/main/java/feign/vertx/OutputToReadStream.java new file mode 100644 index 0000000000..e124976ad7 --- /dev/null +++ b/vertx/feign-vertx/src/main/java/feign/vertx/OutputToReadStream.java @@ -0,0 +1,308 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.vertx; + +import io.vertx.core.AsyncResult; +import io.vertx.core.Context; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.Promise; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.streams.ReadStream; +import io.vertx.core.streams.WriteStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +/** + * A conversion utility to help move data from a Java classic blocking IO to a Vert.x asynchronous + * stream. + * + *

Adapted from {@code io.cloudonix.vertx.javaio.OutputToReadStream} in {@code + * io.cloudonix:vertx-java.io:5.0.8} (MIT License), with local changes for Feign. + * + *

This class is copied here to keep compatibility with both Vert.x 4 and Vert.x 5. + * + *

Main compatibility change: {@link #pipeFromInput(InputStream, WriteStream)} uses {@code + * Future.onComplete(...)} rather than {@code Future.andThen(...)} to avoid a runtime linkage to + * {@code io.vertx.core.Completable}, which does not exist in Vert.x 4. + * + *

Use this class to create an {@link OutputStream} that pushes data written to it to a {@link + * ReadStream} API. + * + *

The ReadStream handlers are called on a Vert.x context, and {@link #close()} must be called + * for the ReadStream end handler to be triggered. + * + *

It is recommended to use this class in a blocking try-with-resources block, to ensure that + * streams are closed properly. For example: + * + *

{@code try (final OutputToReadStream os = new OutputToReadStream(vertx); final InputStream is + * = getInput()) { os.pipeTo(someWriteStream); is.transferTo(os); } } + * + * @author guss77 + */ +public class OutputToReadStream extends OutputStream implements ReadStream { + + private AtomicReference paused = new AtomicReference<>(new CountDownLatch(0)); + private boolean closed; + private AtomicLong demand = new AtomicLong(0); + private Handler endHandler = v -> {}; + private Handler dataHandler = d -> {}; + private Handler errorHandler = t -> {}; + private Context context; + + public OutputToReadStream(Vertx vertx) { + context = vertx.getOrCreateContext(); + } + + /** + * Helper utility to pipe a Java {@link InputStream} to a {@link WriteStream}. + * + *

This method is non-blocking and Vert.x context safe. It uses the common ForkJoinPool to + * perform the Java blocking IO and will try to propagate IO failures to the returned {@link + * Future}. + * + *

Compatibility note: this implementation intentionally uses {@code + * onComplete} (not {@code andThen}) so it works on Vert.x 4 and Vert.x 5. + * + *

This method uses {@link InputStream#transferTo(OutputStream)} to copy all the data, and will + * then attempt to close both streams asynchronously. Some Java compilers might not detect that + * the streams will be safely closed and will issue leak warnings. + * + * @param source InputStream to drain + * @param sink WriteStream to pipe data to + * @return a Future that will succeed when all the data have been written and the streams closed, + * or fail if an {@link IOException} has occurred + */ + public Future pipeFromInput(InputStream source, WriteStream sink) { + Promise promise = Promise.promise(); + pipeTo(sink) + .onComplete( + ar -> { + if (ar.succeeded()) { + promise.complete(ar.result()); + } else { + promise.fail(ar.cause()); + } + }); + ForkJoinPool.commonPool() + .submit( + () -> { + try (final InputStream is = source; + final OutputStream os = this) { + source.transferTo(this); + } catch (IOException e) { + promise.tryFail(e); + } + }); + return promise.future(); + } + + /** + * Helper utility to pipe a Java {@link InputStream} to a {@link WriteStream}. + * + *

This method is non-blocking and Vert.x context safe. It uses the common ForkJoinPool to + * perform the Java blocking IO and will try to propagate IO failures to the returned {@link + * Future} + * + *

This method uses {@link InputStream#transferTo(OutputStream)} to copy all the data, and will + * then attempt to close both streams asynchronously. Some Java compilers might not detect that + * the streams will be safely closed and will issue leak warnings. + * + * @param source InputStream to drain + * @param sink WriteStream to pipe data to + * @param handler a handler that will be called when all the data have been written and the + * streams closed, or if an {@link IOException} has occurred. + */ + public void pipeFromInput( + InputStream source, WriteStream sink, Handler> handler) { + pipeFromInput(source, sink).onComplete(handler); + } + + /** + * Propagate an out-of-band error (likely generated or handled by the code that feeds the output + * stream) to the end of the read stream to let them know that the result is not going to be good. + * + * @param t error to be propagated down the stream + */ + public void sendError(Throwable t) { + context.executeBlocking( + () -> { + errorHandler.handle(t); + return null; + }); + } + + /* ReadStream stuff */ + + /** + * {@inheritDoc} + * + * @param handler {@inheritDoc} + * @return {@inheritDoc} + */ + @Override + public OutputToReadStream exceptionHandler(Handler handler) { + // we are usually not propagating exceptions as OutputStream has no mechanism for propagating + // exceptions down, + // except when wrapping an input stream, in which case we can forward InputStream read errors to + // the error handler. + errorHandler = Objects.requireNonNullElse(handler, t -> {}); + return this; + } + + /** + * {@inheritDoc} + * + * @param handler {@inheritDoc} + * @return {@inheritDoc} + */ + @Override + public OutputToReadStream handler(Handler handler) { + this.dataHandler = Objects.requireNonNullElse(handler, d -> {}); + return this; + } + + /** + * {@inheritDoc} + * + * @return {@inheritDoc} + */ + @Override + public OutputToReadStream pause() { + paused.getAndSet(new CountDownLatch(1)).countDown(); + return this; + } + + /** + * {@inheritDoc} + * + * @return {@inheritDoc} + */ + @Override + public OutputToReadStream resume() { + paused.getAndSet(new CountDownLatch(0)).countDown(); + return this; + } + + /** + * {@inheritDoc} + * + * @param amount {@inheritDoc} + * @return {@inheritDoc} + */ + @Override + public OutputToReadStream fetch(long amount) { + resume(); + demand.addAndGet(amount); + return null; + } + + /** + * {@inheritDoc} + * + * @param endHandler {@inheritDoc} + * @return {@inheritDoc} + */ + @Override + public OutputToReadStream endHandler(Handler endHandler) { + this.endHandler = Objects.requireNonNullElse(endHandler, v -> {}); + return this; + } + + /* OutputStream stuff */ + + /** + * {@inheritDoc} + * + * @param b {@inheritDoc} + * @throws IOException {@inheritDoc} + */ + @Override + public synchronized void write(int b) throws IOException { + if (closed) throw new IOException("OutputStream is closed"); + try { + paused.get().await(); + } catch (InterruptedException e) { + throw new IOException("Interrupted a wait for stream to resume", e); + } + push(Buffer.buffer(1).appendByte((byte) (b & 0xFF))); + } + + /** + * {@inheritDoc} + * + * @param b {@inheritDoc} + * @param off {@inheritDoc} + * @param len {@inheritDoc} + * @throws IOException {@inheritDoc} + */ + @Override + public synchronized void write(byte[] b, int off, int len) throws IOException { + if (closed) throw new IOException("OutputStream is closed"); + try { + paused.get().await(); + } catch (InterruptedException e) { + throw new IOException("Interrupted a wait for stream to resume", e); + } + push(Buffer.buffer(len - off).appendBytes(b, off, len)); + } + + /** + * {@inheritDoc} + * + * @throws IOException {@inheritDoc} + */ + @Override + public synchronized void close() throws IOException { + if (closed) return; + closed = true; + try { + paused.get().await(); + } catch (InterruptedException e) { + throw new IOException("Interrupted a wait for stream to resume", e); + } + push(null); + } + + /* Internal implementation */ + + private void push(Buffer data) { + var awaiter = new CountDownLatch(1); + context.runOnContext( + v -> { + try { + if (data == null) // end of stream + endHandler.handle(null); + else dataHandler.handle(data); + } catch (Throwable t) { + errorHandler.handle(t); + } finally { + awaiter.countDown(); + } + }); + try { + awaiter.await(); + } catch (InterruptedException e) { + } + } +} diff --git a/vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java b/vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java index 0b196b6ffb..0a00bd2adb 100644 --- a/vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java +++ b/vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java @@ -44,6 +44,7 @@ */ @SuppressWarnings("unused") public final class VertxHttpClient { + private final Vertx vertx; private final WebClient webClient; private final long timeout; private final UnaryOperator> requestPreProcessor; @@ -56,12 +57,15 @@ public final class VertxHttpClient { * @param requestPreProcessor request pre-processor */ public VertxHttpClient( + final Vertx vertx, final WebClient webClient, final long timeout, final UnaryOperator> requestPreProcessor) { + checkNotNull(vertx, "Argument vertx must not be null"); checkNotNull(webClient, "Argument webClient must not be null"); checkNotNull(requestPreProcessor, "Argument requestPreProcessor must be not null"); + this.vertx = vertx; this.webClient = webClient; this.timeout = timeout; this.requestPreProcessor = requestPreProcessor; @@ -85,9 +89,25 @@ public Future execute(final Request request) { } final Future> responseFuture = - request.body() != null - ? httpClientRequest.sendBuffer(Buffer.buffer(request.body())) - : httpClientRequest.send(); + request + .body() + .map( + body -> { + OutputToReadStream stream = new OutputToReadStream(vertx); + Future> sendStreamFuture = + httpClientRequest.sendStream(stream); + Future writeFuture = + vertx.executeBlocking( + () -> { + try (stream) { + body.writeTo(stream); + } + return null; + }); + return Future.all(sendStreamFuture, writeFuture) + .map(composite -> sendStreamFuture.result()); + }) + .orElseGet(httpClientRequest::send); return responseFuture.compose( response -> { diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java b/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java index 5931c7acb4..dd7f496b6b 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java @@ -81,6 +81,7 @@ void http11NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { HelloServiceAPI client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) @@ -108,6 +109,7 @@ void http2NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { HelloServiceAPI client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java index fae9a70e9d..88dab3713b 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java @@ -38,6 +38,7 @@ protected void createClient(final Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java index 39a43a8adb..69e3d5dfd8 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java @@ -55,6 +55,7 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .queryMapEncoder(new CustomQueryMapEncoder()) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java index 48f46b4b49..e816622474 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java @@ -45,6 +45,7 @@ class RawContractTest extends AbstractFeignVertxTest { static void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(WebClient.create(vertx)) .encoder(new JacksonEncoder(TestUtils.MAPPER)) .decoder(new JacksonDecoder(TestUtils.MAPPER)) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java index 87850cb9e3..2d88afa6c9 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java @@ -47,6 +47,7 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .requestPreProcessor(req -> req.addQueryParam("version", "v1")) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java index b294d99363..89691c9d5a 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java @@ -48,6 +48,7 @@ class RetryingTest extends AbstractFeignVertxTest { static void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(WebClient.create(vertx)) .decoder(new JacksonDecoder(MAPPER)) .retryer(new DefaultRetryer(100, SECONDS.toMillis(1), 5)) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java index 29e7efa6e1..5bd97dd4a5 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java @@ -48,6 +48,7 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .timeout(1000) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java index eca7765385..005568436b 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java @@ -65,6 +65,7 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) @@ -217,6 +218,7 @@ class WhenMakePostRequest { void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(WebClient.create(vertx)) .encoder(new JacksonEncoder(TestUtils.MAPPER)) .decoder(new JacksonDecoder(TestUtils.MAPPER)) @@ -304,6 +306,23 @@ void whenVertxMissing() { ThrowableAssert.ThrowingCallable instantiateContractForgottenVertx = () -> VertxFeign.builder().target(IcecreamServiceApi.class, wireMock.baseUrl()); + /* Then */ + assertThatCode(instantiateContractForgottenVertx) + .isInstanceOf(NullPointerException.class) + .hasMessage("Vertx instance wasn't provided in VertxFeign builder"); + } + + @Test + @DisplayName("when Vertx WebClient is not provided") + void whenVertxWebClientMissing(Vertx vertx) { + + /* Given */ + ThrowableAssert.ThrowingCallable instantiateContractForgottenVertx = + () -> + VertxFeign.builder() + .vertx(vertx) + .target(IcecreamServiceApi.class, wireMock.baseUrl()); + /* Then */ assertThatCode(instantiateContractForgottenVertx) .isInstanceOf(NullPointerException.class) @@ -318,6 +337,7 @@ void whenTryToInstantiateBrokenContract(Vertx vertx) { ThrowableAssert.ThrowingCallable instantiateBrokenContract = () -> VertxFeign.builder() + .vertx(vertx) .webClient(WebClient.create(vertx)) .target(IcecreamServiceApiBroken.class, wireMock.baseUrl()); diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java index 626376a347..21eefbe9ca 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java @@ -65,6 +65,7 @@ void httpClientOptions(Vertx vertx, VertxTestContext testContext) { IcecreamServiceApi client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) @@ -86,6 +87,7 @@ void requestOptions(Vertx vertx, VertxTestContext testContext) { IcecreamServiceApi client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java index b76b751ed0..4dcde50338 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java @@ -84,6 +84,7 @@ void http11NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { HelloServiceAPI client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) @@ -111,6 +112,7 @@ void http2NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { HelloServiceAPI client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java index 207ae8a89e..bb6edaf4a8 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java @@ -36,6 +36,7 @@ protected void createClient(final Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java index 39a43a8adb..69e3d5dfd8 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java @@ -55,6 +55,7 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .queryMapEncoder(new CustomQueryMapEncoder()) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java index 48f46b4b49..e816622474 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java @@ -45,6 +45,7 @@ class RawContractTest extends AbstractFeignVertxTest { static void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(WebClient.create(vertx)) .encoder(new JacksonEncoder(TestUtils.MAPPER)) .decoder(new JacksonDecoder(TestUtils.MAPPER)) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java index 87850cb9e3..2d88afa6c9 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java @@ -47,6 +47,7 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .requestPreProcessor(req -> req.addQueryParam("version", "v1")) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java index b294d99363..89691c9d5a 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java @@ -48,6 +48,7 @@ class RetryingTest extends AbstractFeignVertxTest { static void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(WebClient.create(vertx)) .decoder(new JacksonDecoder(MAPPER)) .retryer(new DefaultRetryer(100, SECONDS.toMillis(1), 5)) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java index 29e7efa6e1..5bd97dd4a5 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java @@ -48,6 +48,7 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .timeout(1000) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java index eca7765385..005568436b 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java @@ -65,6 +65,7 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) @@ -217,6 +218,7 @@ class WhenMakePostRequest { void createClient(Vertx vertx) { client = VertxFeign.builder() + .vertx(vertx) .webClient(WebClient.create(vertx)) .encoder(new JacksonEncoder(TestUtils.MAPPER)) .decoder(new JacksonDecoder(TestUtils.MAPPER)) @@ -304,6 +306,23 @@ void whenVertxMissing() { ThrowableAssert.ThrowingCallable instantiateContractForgottenVertx = () -> VertxFeign.builder().target(IcecreamServiceApi.class, wireMock.baseUrl()); + /* Then */ + assertThatCode(instantiateContractForgottenVertx) + .isInstanceOf(NullPointerException.class) + .hasMessage("Vertx instance wasn't provided in VertxFeign builder"); + } + + @Test + @DisplayName("when Vertx WebClient is not provided") + void whenVertxWebClientMissing(Vertx vertx) { + + /* Given */ + ThrowableAssert.ThrowingCallable instantiateContractForgottenVertx = + () -> + VertxFeign.builder() + .vertx(vertx) + .target(IcecreamServiceApi.class, wireMock.baseUrl()); + /* Then */ assertThatCode(instantiateContractForgottenVertx) .isInstanceOf(NullPointerException.class) @@ -318,6 +337,7 @@ void whenTryToInstantiateBrokenContract(Vertx vertx) { ThrowableAssert.ThrowingCallable instantiateBrokenContract = () -> VertxFeign.builder() + .vertx(vertx) .webClient(WebClient.create(vertx)) .target(IcecreamServiceApiBroken.class, wireMock.baseUrl()); diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java index 0e83d3ea62..2ca7a54cb6 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java @@ -64,6 +64,7 @@ void httpClientOptions(Vertx vertx, VertxTestContext testContext) { IcecreamServiceApi client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) @@ -85,6 +86,7 @@ void requestOptions(Vertx vertx, VertxTestContext testContext) { IcecreamServiceApi client = VertxFeign.builder() + .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) From 21cd9f3320dccf18c07ffb7e1cd9b9c774f13296 Mon Sep 17 00:00:00 2001 From: Oussama Ben Ghorbel Date: Mon, 8 Jun 2026 13:16:08 +0200 Subject: [PATCH 555/615] [issue #2998] Expose uriTemplate in RequestTemplate (#3393) * Expose uriTemplate in RequestTemplate * fix formatting --------- Co-authored-by: obenghorbel --- core/src/main/java/feign/RequestTemplate.java | 16 +++++++++ .../test/java/feign/RequestTemplateTest.java | 33 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/core/src/main/java/feign/RequestTemplate.java b/core/src/main/java/feign/RequestTemplate.java index 2f767d067f..b4868481fb 100644 --- a/core/src/main/java/feign/RequestTemplate.java +++ b/core/src/main/java/feign/RequestTemplate.java @@ -576,6 +576,22 @@ public String path() { return path.toString(); } + /** + * The Uri Template (relative path) without the host and port. This is the templated path with + * parameter placeholders but without the scheme://host:port prefix. + * + *

For example, given a target of {@code https://api.example.com:8443} and a uri of {@code + * /v1/api/resource/{id}}, this method will return {@code /v1/api/resource/{id}}. + * + * @return the uri template path without host/port, or "/" if no path is set + */ + public String requestUriTemplate() { + if (this.uriTemplate != null) { + return this.uriTemplate.toString(); + } + return "/"; + } + /** * List all of the template variable expressions for this template. * diff --git a/core/src/test/java/feign/RequestTemplateTest.java b/core/src/test/java/feign/RequestTemplateTest.java index 183aaca0d4..16106c9277 100644 --- a/core/src/test/java/feign/RequestTemplateTest.java +++ b/core/src/test/java/feign/RequestTemplateTest.java @@ -600,4 +600,37 @@ void nullValuesOfHeaderShouldBeHandled() { String name = ""; template.header(name, values); } + + @Test + void requestUriTemplateReturnsPathWithoutHost() { + RequestTemplate template = new RequestTemplate(); + template.target("https://api.example.com:8443"); + template.uri("/v1/api/resource/{id}"); + assertThat(template.requestUriTemplate()).isEqualTo("/v1/api/resource/{id}"); + } + + @Test + void requestUriTemplateWithMultiplePathSegments() { + RequestTemplate template = new RequestTemplate(); + template.target("https://api.example.com:8443"); + template.uri("/api/v1/users/{userId}/posts/{postId}"); + assertThat(template.requestUriTemplate()).isEqualTo("/api/v1/users/{userId}/posts/{postId}"); + } + + @Test + void requestUriTemplateReturnsRootPathWhenNotSet() { + RequestTemplate template = new RequestTemplate(); + assertThat(template.requestUriTemplate()).isEqualTo("/"); + } + + @Test + void requestUriTemplateDoesNotIncludeQueries() { + RequestTemplate template = new RequestTemplate(); + template.uri("/resource?filter={filter}&sort={sort}"); + assertThat(template.requestUriTemplate()).isEqualTo("/resource"); + assertThat(template) + .hasQueries( + entry("filter", Collections.singletonList("{filter}")), + entry("sort", Collections.singletonList("{sort}"))); + } } From 16cf31218184b978bb5b9115098d77c1357e1d33 Mon Sep 17 00:00:00 2001 From: seonwoojung Date: Thu, 11 Jun 2026 20:17:14 +0900 Subject: [PATCH 556/615] Open observation scope and stop observation on non-FeignException errors (#3407) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `MicrometerObservationCapability` started an `Observation` but never opened its `Scope`, so the new observation was not the current one while the call ran. Downstream `ObservationHandler`s — most importantly, tracing handlers that copy trace/span ids into the MDC — saw the parent observation instead of the Feign one, so log lines for the outgoing call were tagged with the wrong span id. The capability also caught only `FeignException`. Underlying clients (JDK `HttpURLConnection`, Apache HC5, OkHttp, …) throw client-specific exceptions — `SocketTimeoutException`, `HttpHostConnectException`, `IOException` — directly, never wrapped as `FeignException`. Those slipped past the `catch`, so the observation was never stopped: the error was not recorded, the timer was never committed, and the observation leaked. Both calls now open the observation as a `Scope` while the underlying client runs, catch any `Throwable` to record the error and stop the observation, and unwrap `CompletionException` on the async path so the recorded error is the cause rather than the wrapper. Fixes #2406 Fixes #2566 --- .../MicrometerObservationCapability.java | 39 ++- .../MicrometerObservationCapabilityTest.java | 302 ++++++++++++++++++ 2 files changed, 325 insertions(+), 16 deletions(-) create mode 100644 micrometer/src/test/java/feign/micrometer/MicrometerObservationCapabilityTest.java diff --git a/micrometer/src/main/java/feign/micrometer/MicrometerObservationCapability.java b/micrometer/src/main/java/feign/micrometer/MicrometerObservationCapability.java index e49f43d40e..dfa5eaabd3 100644 --- a/micrometer/src/main/java/feign/micrometer/MicrometerObservationCapability.java +++ b/micrometer/src/main/java/feign/micrometer/MicrometerObservationCapability.java @@ -18,10 +18,10 @@ import feign.AsyncClient; import feign.Capability; import feign.Client; -import feign.FeignException; import feign.Response; import io.micrometer.observation.Observation; import io.micrometer.observation.ObservationRegistry; +import java.util.concurrent.CompletionException; /** Wrap feign {@link Client} with metrics. */ public class MicrometerObservationCapability implements Capability { @@ -55,13 +55,15 @@ public Client enrich(Client client) { this.observationRegistry) .start(); - try { + try (Observation.Scope scope = observation.openScope()) { Response response = client.execute(request, options); - finalizeObservation(feignContext, observation, null, response); + feignContext.setResponse(response); return response; - } catch (FeignException ex) { - finalizeObservation(feignContext, observation, ex, null); + } catch (Throwable ex) { + observation.error(ex); throw ex; + } finally { + observation.stop(); } }; } @@ -80,24 +82,29 @@ public AsyncClient enrich(AsyncClient client) { this.observationRegistry) .start(); - try { + try (Observation.Scope scope = observation.openScope()) { return client .execute(feignContext.getCarrier(), options, context) - .whenComplete((r, ex) -> finalizeObservation(feignContext, observation, ex, r)); - } catch (FeignException ex) { - finalizeObservation(feignContext, observation, ex, null); - + .whenComplete( + (response, ex) -> { + feignContext.setResponse(response); + if (ex != null) { + observation.error(unwrap(ex)); + } + observation.stop(); + }); + } catch (Throwable ex) { + observation.error(ex); + observation.stop(); throw ex; } }; } - private void finalizeObservation( - FeignContext feignContext, Observation observation, Throwable ex, Response response) { - feignContext.setResponse(response); - if (ex != null) { - observation.error(ex); + private static Throwable unwrap(Throwable ex) { + if (ex instanceof CompletionException && ex.getCause() != null) { + return ex.getCause(); } - observation.stop(); + return ex; } } diff --git a/micrometer/src/test/java/feign/micrometer/MicrometerObservationCapabilityTest.java b/micrometer/src/test/java/feign/micrometer/MicrometerObservationCapabilityTest.java new file mode 100644 index 0000000000..b2f75d09ef --- /dev/null +++ b/micrometer/src/test/java/feign/micrometer/MicrometerObservationCapabilityTest.java @@ -0,0 +1,302 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.micrometer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import feign.AsyncClient; +import feign.AsyncFeign; +import feign.Client; +import feign.Feign; +import feign.RequestLine; +import feign.Retryer; +import feign.Target.HardCodedTarget; +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationHandler; +import io.micrometer.observation.tck.TestObservationRegistry; +import io.micrometer.observation.tck.TestObservationRegistryAssert; +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Behavioural tests for {@link MicrometerObservationCapability} focusing on the cases that the + * existing capability did not cover: + * + *
    + *
  • The observation is current (via {@code Observation.Scope}) while the client executes, so + * downstream handlers — most notably tracing handlers that propagate trace/span ids into the + * MDC — see the Feign-scoped observation rather than the parent. + *
  • Exceptions thrown by the underlying client that are not {@code FeignException} — + * {@code IOException}, {@code SocketTimeoutException}, runtime exceptions thrown by a custom + * {@code ErrorDecoder}, and so on — still close the observation and record the error. + *
+ */ +class MicrometerObservationCapabilityTest { + + interface TestClient { + @RequestLine("GET /") + String get(); + } + + interface AsyncTestClient { + @RequestLine("GET /") + CompletableFuture get(); + } + + private TestObservationRegistry observationRegistry; + + @BeforeEach + void setUp() { + this.observationRegistry = TestObservationRegistry.create(); + } + + @Test + void scopeIsOpenDuringClientExecution() { + AtomicReference observedDuringExecute = new AtomicReference<>(); + Client client = + (request, options) -> { + observedDuringExecute.set(observationRegistry.getCurrentObservation()); + return feign.Response.builder() + .status(200) + .reason("OK") + .request(request) + .headers(java.util.Collections.emptyMap()) + .build(); + }; + + TestClient feignClient = + Feign.builder() + .client(client) + .addCapability(new MicrometerObservationCapability(observationRegistry)) + .target(new HardCodedTarget<>(TestClient.class, "http://localhost")); + + feignClient.get(); + + assertThat(observedDuringExecute.get()) + .as("observation must be active (scoped) while the underlying client executes") + .isNotNull(); + assertThat(observationRegistry.getCurrentObservation()) + .as("observation must no longer be current after the call returns") + .isNull(); + } + + @Test + void recordsNonFeignExceptionThrownByClient() { + // Feign's SynchronousMethodHandler wraps IOExceptions, so callers don't see the original + // throwable. The observation captured by the capability sits below that wrapping, and is the + // only place the underlying error is recorded against the trace. + SocketTimeoutException underlying = new SocketTimeoutException("connect timed out"); + + Client client = + (request, options) -> { + throw underlying; + }; + + TestClient feignClient = + Feign.builder() + .client(client) + .retryer(Retryer.NEVER_RETRY) + .addCapability(new MicrometerObservationCapability(observationRegistry)) + .target(new HardCodedTarget<>(TestClient.class, "http://localhost")); + + assertThatThrownBy(feignClient::get).isInstanceOf(Exception.class); + + TestObservationRegistryAssert.assertThat(observationRegistry) + .hasSingleObservationThat() + .hasBeenStopped() + .hasError(underlying); + } + + @Test + void recordsRuntimeExceptionThrownByClient() { + RuntimeException underlying = new RuntimeException("boom"); + + Client client = + (request, options) -> { + throw underlying; + }; + + TestClient feignClient = + Feign.builder() + .client(client) + .retryer(Retryer.NEVER_RETRY) + .addCapability(new MicrometerObservationCapability(observationRegistry)) + .target(new HardCodedTarget<>(TestClient.class, "http://localhost")); + + assertThatThrownBy(feignClient::get).isInstanceOf(Exception.class); + + TestObservationRegistryAssert.assertThat(observationRegistry) + .hasSingleObservationThat() + .hasBeenStopped() + .hasError(underlying); + } + + @Test + void asyncScopeIsOpenDuringClientExecution() { + AtomicReference observedDuringExecute = new AtomicReference<>(); + AsyncClient client = + (request, options, context) -> { + observedDuringExecute.set(observationRegistry.getCurrentObservation()); + return CompletableFuture.completedFuture( + feign.Response.builder() + .status(200) + .reason("OK") + .request(request) + .headers(java.util.Collections.emptyMap()) + .build()); + }; + + AsyncTestClient feignClient = + AsyncFeign.builder() + .client(client) + .addCapability(new MicrometerObservationCapability(observationRegistry)) + .target(new HardCodedTarget<>(AsyncTestClient.class, "http://localhost")); + + feignClient.get().join(); + + assertThat(observedDuringExecute.get()) + .as("observation must be active while the async client kicks off the request") + .isNotNull(); + } + + @Test + void asyncRecordsNonFeignExceptionFromFailedFuture() { + IOException underlying = new IOException("connection reset"); + + AsyncClient client = + (request, options, context) -> { + CompletableFuture failed = new CompletableFuture<>(); + failed.completeExceptionally(underlying); + return failed; + }; + + AsyncTestClient feignClient = + AsyncFeign.builder() + .client(client) + .retryer(Retryer.NEVER_RETRY) + .addCapability(new MicrometerObservationCapability(observationRegistry)) + .target(new HardCodedTarget<>(AsyncTestClient.class, "http://localhost")); + + assertThatThrownBy(() -> feignClient.get().join()).isInstanceOf(CompletionException.class); + + TestObservationRegistryAssert.assertThat(observationRegistry) + .hasSingleObservationThat() + .hasBeenStopped() + .hasError(underlying); + } + + @Test + void asyncRecordsSynchronousExceptionFromClient() { + RuntimeException underlying = new RuntimeException("immediate failure"); + + AsyncClient client = + (request, options, context) -> { + throw underlying; + }; + + AsyncTestClient feignClient = + AsyncFeign.builder() + .client(client) + .retryer(Retryer.NEVER_RETRY) + .addCapability(new MicrometerObservationCapability(observationRegistry)) + .target(new HardCodedTarget<>(AsyncTestClient.class, "http://localhost")); + + assertThatThrownBy(feignClient::get).isInstanceOf(RuntimeException.class); + + TestObservationRegistryAssert.assertThat(observationRegistry) + .hasSingleObservationThat() + .hasBeenStopped() + .hasError(underlying); + } + + @Test + void parentObservationIsRestoredAfterCall() { + Observation parent = Observation.start("parent", observationRegistry); + try (Observation.Scope ignored = parent.openScope()) { + + Client client = + (request, options) -> + feign.Response.builder() + .status(200) + .reason("OK") + .request(request) + .headers(java.util.Collections.emptyMap()) + .build(); + + TestClient feignClient = + Feign.builder() + .client(client) + .addCapability(new MicrometerObservationCapability(observationRegistry)) + .target(new HardCodedTarget<>(TestClient.class, "http://localhost")); + + feignClient.get(); + + assertThat(observationRegistry.getCurrentObservation()) + .as("parent observation must still be current after the Feign call completes") + .isSameAs(parent); + } finally { + parent.stop(); + } + } + + @Test + @SuppressWarnings("unchecked") + void scopeReceivesObservationCarryingFeignContext() { + AtomicReference seenContext = new AtomicReference<>(); + + observationRegistry + .observationConfig() + .observationHandler( + new ObservationHandler() { + @Override + public void onScopeOpened(Observation.Context context) { + seenContext.set(context); + } + + @Override + public boolean supportsContext(Observation.Context context) { + return true; + } + }); + + Client client = + (request, options) -> + feign.Response.builder() + .status(200) + .reason("OK") + .request(request) + .headers(java.util.Collections.emptyMap()) + .build(); + + TestClient feignClient = + Feign.builder() + .client(client) + .addCapability(new MicrometerObservationCapability(observationRegistry)) + .target(new HardCodedTarget<>(TestClient.class, "http://localhost")); + + feignClient.get(); + + assertThat(seenContext.get()) + .as("scope must propagate the FeignContext to ObservationHandler#onScopeOpened") + .isInstanceOf(FeignContext.class); + } +} From e6e3a7beca9c84fbcf23f7fec67b298806c34017 Mon Sep 17 00:00:00 2001 From: seonwoojung Date: Thu, 11 Jun 2026 20:17:26 +0900 Subject: [PATCH 557/615] Avoid ClassLoader leak from static default async executor (#3178) (#3394) * Avoid ClassLoader leak from static default async executor AsyncFeign held its default ExecutorService in a static singleton (LazyInitializedExecutorService) that was never shut down. Inside a servlet container, the daemon thread pool retained a strong reference to the initial application's ContextClassLoader, so each redeployment leaked the previous application's ClassLoader and threads, eventually causing a Metaspace OutOfMemoryError. Replace the static singleton with an instance-scoped default executor created per built client, so it (and its threads) become eligible for GC once the client is discarded. Also add AsyncBuilder.executorService(...) so callers can supply and own a managed, shut-downable executor. Fixes #3178 Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com> * Exclude async executor from capability enrichment --------- Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) --- core/src/main/java/feign/AsyncFeign.java | 52 +++++++++++++++----- core/src/main/java/feign/BaseBuilder.java | 2 + core/src/test/java/feign/AsyncFeignTest.java | 37 ++++++++++++++ 3 files changed, 79 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/feign/AsyncFeign.java b/core/src/main/java/feign/AsyncFeign.java index 08cfcc96c6..38830b4234 100644 --- a/core/src/main/java/feign/AsyncFeign.java +++ b/core/src/main/java/feign/AsyncFeign.java @@ -56,23 +56,28 @@ public static AsyncBuilder asyncBuilder() { return builder(); } - private static class LazyInitializedExecutorService { - - private static final ExecutorService instance = - Executors.newCachedThreadPool( - r -> { - final Thread result = new Thread(r); - result.setDaemon(true); - return result; - }); + /** + * Creates the default {@link ExecutorService} used when neither a custom {@link AsyncClient} nor + * a custom executor is provided. The executor is created per built client (instance scoped) + * rather than being held in a static singleton, so that it - together with its daemon threads - + * becomes eligible for garbage collection once the owning client is discarded. This avoids the + * {@code ClassLoader} leak that a static singleton causes on application redeployments inside + * servlet containers (see gh-3178). + */ + private static ExecutorService defaultExecutorService() { + return Executors.newCachedThreadPool( + r -> { + final Thread result = new Thread(r); + result.setDaemon(true); + return result; + }); } public static class AsyncBuilder extends BaseBuilder, AsyncFeign> { private AsyncContextSupplier defaultContextSupplier = () -> null; - private AsyncClient client = - new DefaultAsyncClient<>( - new DefaultClient(null, null), LazyInitializedExecutorService.instance); + private AsyncClient client; + private ExecutorService executorService; private MethodInfoResolver methodInfoResolver = MethodInfo::new; @Deprecated @@ -86,6 +91,28 @@ public AsyncBuilder client(AsyncClient client) { return this; } + /** + * Sets the {@link ExecutorService} used by the default {@link AsyncClient} to run the + * (blocking) underlying client calls. When provided, the caller owns the executor's lifecycle + * and is responsible for shutting it down. This is the recommended way to avoid the {@code + * ClassLoader} leak described in gh-3178: supply a managed, shut-downable executor instead of + * relying on the built-in default. Ignored when a custom {@link #client(AsyncClient)} is + * supplied. + */ + public AsyncBuilder executorService(ExecutorService executorService) { + this.executorService = executorService; + return this; + } + + private AsyncClient resolveClient() { + if (client != null) { + return client; + } + final ExecutorService executor = + executorService != null ? executorService : defaultExecutorService(); + return new DefaultAsyncClient<>(new DefaultClient(null, null), executor); + } + public AsyncBuilder methodInfoResolver(MethodInfoResolver methodInfoResolver) { this.methodInfoResolver = methodInfoResolver; return this; @@ -206,6 +233,7 @@ public AsyncBuilder invocationHandlerFactory( @Override public AsyncFeign internalBuild() { + final AsyncClient client = resolveClient(); AsyncResponseHandler responseHandler = (AsyncResponseHandler) Capability.enrich( diff --git a/core/src/main/java/feign/BaseBuilder.java b/core/src/main/java/feign/BaseBuilder.java index 05608dc2ed..d279ed764a 100644 --- a/core/src/main/java/feign/BaseBuilder.java +++ b/core/src/main/java/feign/BaseBuilder.java @@ -362,6 +362,8 @@ List getFieldsToEnrich() { .filter(field -> !Objects.equals(field.getName(), "requestInterceptors")) .filter(field -> !Objects.equals(field.getName(), "responseInterceptors")) .filter(field -> !Objects.equals(field.getName(), "methodInterceptors")) + // caller-owned lifecycle resources are not capability-enriched + .filter(field -> !Objects.equals(field.getName(), "executorService")) // skip primitive types .filter(field -> !field.getType().isPrimitive()) // skip enumerations diff --git a/core/src/test/java/feign/AsyncFeignTest.java b/core/src/test/java/feign/AsyncFeignTest.java index 08c70f19c4..2e683de5f8 100644 --- a/core/src/test/java/feign/AsyncFeignTest.java +++ b/core/src/test/java/feign/AsyncFeignTest.java @@ -23,6 +23,10 @@ import static org.assertj.core.data.MapEntry.entry; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -103,6 +107,39 @@ void postTemplateParamsResolve() throws Exception { + " \"password\"}"); } + @Test + void usesProvidedExecutorService() throws Exception { + server.enqueue(new MockResponse().setBody("foo")); + + ExecutorService executorService = spy(Executors.newCachedThreadPool()); + try { + TestInterfaceAsync api = + AsyncFeign.builder() + .decoder(new DefaultDecoder()) + .executorService(executorService) + .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); + + String result = api.post().join(); + + assertThat(result).isEqualTo("foo"); + verify(executorService, atLeastOnce()).submit(any(Runnable.class)); + } finally { + executorService.shutdownNow(); + } + } + + @Test + void defaultExecutorServiceStillExecutesRequests() throws Exception { + server.enqueue(new MockResponse().setBody("foo")); + + TestInterfaceAsync api = + AsyncFeign.builder() + .decoder(new DefaultDecoder()) + .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort()); + + assertThat(api.post().join()).isEqualTo("foo"); + } + @Test void postFormParams() throws Exception { server.enqueue(new MockResponse().setBody("foo")); From 18fe77168bc4a3c7309e631b565f1cc455728b4a Mon Sep 17 00:00:00 2001 From: seonwoojung Date: Thu, 11 Jun 2026 21:43:58 +0900 Subject: [PATCH 558/615] Fix feign-core test compilation broken by removed Request.create overload (#3406) * fix: adapt logger tests to the Request.create(Body, RequestTemplate) signature JavaLoggerTest and LoggerRebufferTest still called the Request.create(..., byte[], Charset) overload removed in f9159cfa, breaking test compilation of feign-core on master. Use the (Body, RequestTemplate) signature with null arguments, matching the existing usage in RetryableExceptionTest. * fix: adapt Slf4jLoggerTest to the Request.create(Body, RequestTemplate) signature Slf4jLoggerTest had the same problem as the feign-core logger tests: it called the removed Request.create(..., byte[], Charset) overload and also referenced feign.Util without an import, breaking feign-slf4j test compilation once feign-core compiles again. * fix: adapt validation tests to the RequestTemplate#body(Request.Body) signature Both BeanValidationMethodInterceptorTest variants still used the RequestTemplate#body(String) overload removed in f9159cfa. * test: make Http2ClientTest hermetic, dropping the live nghttp2.org dependency that hangs CI Signed-off-by: Marvin Froeder --------- Signed-off-by: Marvin Froeder Co-authored-by: Marvin Froeder Co-authored-by: Marvin --- core/src/test/java/feign/JavaLoggerTest.java | 9 +- .../test/java/feign/LoggerRebufferTest.java | 19 ++-- .../http2client/test/Http2ClientTest.java | 100 +++++++++++++++--- .../java/feign/slf4j/Slf4jLoggerTest.java | 10 +- .../BeanValidationMethodInterceptorTest.java | 4 +- .../BeanValidationMethodInterceptorTest.java | 4 +- 6 files changed, 103 insertions(+), 43 deletions(-) diff --git a/core/src/test/java/feign/JavaLoggerTest.java b/core/src/test/java/feign/JavaLoggerTest.java index f05d839e15..3799d79b4b 100644 --- a/core/src/test/java/feign/JavaLoggerTest.java +++ b/core/src/test/java/feign/JavaLoggerTest.java @@ -43,8 +43,7 @@ void rebuffersResponseBodyWhenJulLevelIsInfo() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body("{\"error\":\"test\"}", Util.UTF_8) .build(); @@ -69,8 +68,7 @@ void rebuffersResponseBodyWhenJulLevelIsWarning() throws Exception { Response.builder() .status(500) .reason("Internal Server Error") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body("{\"message\":\"error details\"}", Util.UTF_8) .build(); @@ -95,8 +93,7 @@ void responseBodyReadableMultipleTimesForErrorDecoder() throws Exception { .status(400) .reason("Bad Request") .request( - Request.create( - HttpMethod.POST, "/api/submit", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(HttpMethod.POST, "/api/submit", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); diff --git a/core/src/test/java/feign/LoggerRebufferTest.java b/core/src/test/java/feign/LoggerRebufferTest.java index 5928a8f255..ab1e1f2309 100644 --- a/core/src/test/java/feign/LoggerRebufferTest.java +++ b/core/src/test/java/feign/LoggerRebufferTest.java @@ -43,8 +43,7 @@ void headersLevelRebuffersResponseBody() throws Exception { .status(404) .reason("Not Found") .request( - Request.create( - HttpMethod.GET, "/api/resource", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(HttpMethod.GET, "/api/resource", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); @@ -70,8 +69,7 @@ void basicLevelDoesNotRebufferResponseBody() throws Exception { .status(200) .reason("OK") .request( - Request.create( - HttpMethod.GET, "/api/resource", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(HttpMethod.GET, "/api/resource", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); @@ -94,8 +92,7 @@ void fullLevelRebuffersResponseBody() throws Exception { .status(200) .reason("OK") .request( - Request.create( - HttpMethod.POST, "/api/create", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(HttpMethod.POST, "/api/create", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); @@ -122,8 +119,7 @@ void noneLevelDoesNotRebufferResponseBody() throws Exception { .status(200) .reason("OK") .request( - Request.create( - HttpMethod.GET, "/api/status", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(HttpMethod.GET, "/api/status", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); @@ -146,7 +142,7 @@ void http204DoesNotRebufferEvenAtHeadersLevel() throws Exception { .reason("No Content") .request( Request.create( - HttpMethod.DELETE, "/api/resource/1", Collections.emptyMap(), null, Util.UTF_8)) + HttpMethod.DELETE, "/api/resource/1", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body("should be ignored", Util.UTF_8) .build(); @@ -168,8 +164,7 @@ void http205DoesNotRebufferEvenAtHeadersLevel() throws Exception { .status(205) .reason("Reset Content") .request( - Request.create( - HttpMethod.POST, "/api/form", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(HttpMethod.POST, "/api/form", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body("should be ignored", Util.UTF_8) .build(); @@ -192,7 +187,7 @@ void nullBodyHandledCorrectlyAtHeadersLevel() throws Exception { .reason("OK") .request( Request.create( - HttpMethod.HEAD, "/api/resource", Collections.emptyMap(), null, Util.UTF_8)) + HttpMethod.HEAD, "/api/resource", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body((byte[]) null) .build(); diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientTest.java index a769bda6b2..4f3602322b 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientTest.java @@ -26,16 +26,20 @@ import feign.http2client.Http2Client; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; import java.net.http.HttpTimeoutException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.RecordedRequest; -import org.json.JSONException; import org.junit.jupiter.api.Test; -import org.skyscreamer.jsonassert.JSONAssert; /** Tests client-specific behavior, such as ensuring Content-Length is sent when specified. */ public class Http2ClientTest extends AbstractClientTest { @@ -83,17 +87,39 @@ public interface TestInterface { @Override @Test public void patch() throws Exception { + server.enqueue(new MockResponse().setBody("foo")); + final TestInterface api = - newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); - assertThat(api.patch("")).contains("https://nghttp2.org/httpbin/patch"); + newBuilder().target(TestInterface.class, "http://localhost:" + server.getPort()); + + assertThat(api.patch("some text")).isEqualTo("foo"); + + MockWebServerAssertions.assertThat(server.takeRequest()) + .hasMethod("PATCH") + .hasPath("/patch") + .hasBody("some text"); } @Override @Test public void noResponseBodyForPatch() { + server.enqueue(new MockResponse()); + final TestInterface api = - newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); - assertThat(api.patch()).contains("https://nghttp2.org/httpbin/patch"); + newBuilder().target(TestInterface.class, "http://localhost:" + server.getPort()); + + assertThat(api.patch()).isEmpty(); + + MockWebServerAssertions.assertThat(takeRequest()).hasMethod("PATCH").hasPath("/patch"); + } + + private RecordedRequest takeRequest() { + try { + return server.takeRequest(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(e); + } } @Override @@ -150,21 +176,61 @@ void timeoutTest() { } @Test - void getWithRequestBody() throws JSONException { - final TestInterface api = - newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); - String result = api.getWithBody(); - String expected = "{ \"data\":\"some request body\" }"; - JSONAssert.assertEquals(expected, result, false); + void getWithRequestBody() throws Exception { + // MockWebServer rejects GET requests carrying a body ("Request must not have a body"), + // so this test runs against a minimal local socket server instead. + try (ServerSocket httpServer = new ServerSocket(0, 1, InetAddress.getLoopbackAddress())) { + final AtomicReference receivedRequest = new AtomicReference<>(); + final Thread serverThread = + new Thread( + () -> { + try (Socket socket = httpServer.accept()) { + socket.setSoTimeout(5000); + final InputStream in = socket.getInputStream(); + final StringBuilder request = new StringBuilder(); + final byte[] buffer = new byte[8192]; + while (!request.toString().contains("some request body")) { + final int read = in.read(buffer); + if (read == -1) { + break; + } + request.append(new String(buffer, 0, read, UTF_8)); + } + receivedRequest.set(request.toString()); + socket + .getOutputStream() + .write("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo".getBytes(UTF_8)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + serverThread.start(); + + final TestInterface api = + newBuilder().target(TestInterface.class, "http://localhost:" + httpServer.getLocalPort()); + + assertThat(api.getWithBody()).isEqualTo("foo"); + + serverThread.join(5000); + assertThat(receivedRequest.get()) + .startsWith("GET /anything HTTP/1.1") + .contains("some request body"); + } } @Test - void deleteWithRequestBody() throws JSONException { + void deleteWithRequestBody() throws Exception { + server.enqueue(new MockResponse().setBody("foo")); + final TestInterface api = - newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); - String result = api.deleteWithBody(); - String expected = "{ \"data\":\"some request body\" }"; - JSONAssert.assertEquals(expected, result, false); + newBuilder().target(TestInterface.class, "http://localhost:" + server.getPort()); + + assertThat(api.deleteWithBody()).isEqualTo("foo"); + + MockWebServerAssertions.assertThat(server.takeRequest()) + .hasMethod("DELETE") + .hasPath("/anything") + .hasBody("some request body"); } @Override diff --git a/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java b/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java index 12973ff4e9..6df54f9ef7 100644 --- a/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java +++ b/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java @@ -21,6 +21,7 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; +import feign.Util; import java.util.Collection; import java.util.Collections; import org.junit.jupiter.api.Test; @@ -124,8 +125,7 @@ void rebuffersResponseBodyWhenLogLevelIsInfo() throws Exception { Response.builder() .status(200) .reason("OK") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body("{\"error\":\"test\"}", Util.UTF_8) .build(); @@ -150,8 +150,7 @@ void rebuffersResponseBodyWhenLogLevelIsFull() throws Exception { Response.builder() .status(500) .reason("Internal Server Error") - .request( - Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body("{\"message\":\"error details\"}", Util.UTF_8) .build(); @@ -177,8 +176,7 @@ void responseBodyReadableMultipleTimes() throws Exception { .status(400) .reason("Bad Request") .request( - Request.create( - HttpMethod.POST, "/api/submit", Collections.emptyMap(), null, Util.UTF_8)) + Request.create(HttpMethod.POST, "/api/submit", Collections.emptyMap(), null, null)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); diff --git a/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java b/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java index b2c977a242..36748ac295 100644 --- a/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java +++ b/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java @@ -20,6 +20,7 @@ import feign.Feign; import feign.Param; +import feign.Request; import feign.RequestLine; import jakarta.validation.ConstraintViolationException; import jakarta.validation.Valid; @@ -76,7 +77,8 @@ interface Api { private Api api() { return Feign.builder() - .encoder((object, bodyType, template) -> template.body(String.valueOf(object))) + .encoder( + (object, bodyType, template) -> template.body(Request.Body.of(String.valueOf(object)))) .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory()) .target(Api.class, "http://localhost:" + server.getPort()); } diff --git a/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java b/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java index 11c19dd111..a25b393a38 100644 --- a/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java +++ b/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java @@ -20,6 +20,7 @@ import feign.Feign; import feign.Param; +import feign.Request; import feign.RequestLine; import javax.validation.ConstraintViolationException; import javax.validation.Valid; @@ -76,7 +77,8 @@ interface Api { private Api api() { return Feign.builder() - .encoder((object, bodyType, template) -> template.body(String.valueOf(object))) + .encoder( + (object, bodyType, template) -> template.body(Request.Body.of(String.valueOf(object)))) .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory()) .target(Api.class, "http://localhost:" + server.getPort()); } From 216dbf7349dd3544cb794188314a6cbbaa85b034 Mon Sep 17 00:00:00 2001 From: Marvin Date: Thu, 11 Jun 2026 11:44:14 -0300 Subject: [PATCH 559/615] revert: move Request.Body streaming breaking changes off master, they belong to 14.x (#3409) Signed-off-by: Marvin Froeder --- MIGRATION-v14.md | 421 ------------- .../java/feign/error/ExceptionGenerator.java | 4 +- .../AbstractAnnotationErrorDecoderTest.java | 4 +- ...ErrorDecoderExceptionConstructorsTest.java | 7 +- .../benchmark/DecoderIteratorsBenchmark.java | 2 +- core/src/main/java/feign/DefaultClient.java | 9 +- core/src/main/java/feign/DefaultContract.java | 2 +- core/src/main/java/feign/FeignException.java | 6 +- core/src/main/java/feign/Logger.java | 22 +- core/src/main/java/feign/Request.java | 573 +++++++++--------- core/src/main/java/feign/RequestTemplate.java | 60 +- .../main/java/feign/codec/DefaultEncoder.java | 5 +- .../feign/AlwaysEncodeBodyContractTest.java | 15 +- core/src/test/java/feign/AsyncFeignTest.java | 11 +- core/src/test/java/feign/ClientTest.java | 6 +- .../test/java/feign/DefaultContractTest.java | 31 +- .../src/test/java/feign/FeignBuilderTest.java | 3 +- .../test/java/feign/FeignExceptionTest.java | 39 +- core/src/test/java/feign/FeignTest.java | 11 +- .../test/java/feign/FeignUnderAsyncTest.java | 11 +- core/src/test/java/feign/JavaLoggerTest.java | 9 +- .../test/java/feign/LoggerMethodsTest.java | 2 +- .../test/java/feign/LoggerRebufferTest.java | 19 +- .../test/java/feign/RequestTemplateTest.java | 13 +- core/src/test/java/feign/ResponseTest.java | 23 +- .../java/feign/RetryableExceptionTest.java | 6 +- core/src/test/java/feign/RetryerTest.java | 2 +- core/src/test/java/feign/TargetTest.java | 4 +- .../feign/assertj/RequestTemplateAssert.java | 26 +- .../java/feign/codec/DefaultDecoderTest.java | 5 +- .../java/feign/codec/DefaultEncoderTest.java | 17 +- .../DefaultErrorDecoderHttpErrorTest.java | 6 +- .../feign/codec/DefaultErrorDecoderTest.java | 19 +- .../java/feign/stream/StreamDecoderTest.java | 4 +- .../java/feign/metrics4/MeteredEncoder.java | 18 +- .../java/feign/metrics5/MeteredEncoder.java | 18 +- .../feign/fastjson2/Fastjson2Encoder.java | 4 +- .../feign/fastjson2/FastJsonCodecTest.java | 16 +- .../form/MultipartFormContentProcessor.java | 3 +- .../form/UrlencodedFormContentProcessor.java | 3 +- .../feign/form/multipart/DelegateWriter.java | 16 +- .../googlehttpclient/GoogleHttpClient.java | 60 +- .../java/feign/graphql/GraphqlDecoder.java | 11 +- .../graphql/GraphqlRequestInterceptor.java | 2 +- .../feign/graphql/GraphqlDecoderTest.java | 6 +- .../feign/graphql/GraphqlEncoderTest.java | 33 +- .../src/main/java/feign/gson/GsonEncoder.java | 3 +- .../test/java/feign/gson/GsonCodecTest.java | 19 +- .../java/feign/hc5/ApacheHttp5Client.java | 22 +- .../feign/hc5/AsyncApacheHttp5Client.java | 125 +--- .../main/java/feign/hc5/FeignBodyEntity.java | 97 --- .../feign/hc5/AsyncApacheHttp5ClientTest.java | 11 +- .../feign/httpclient/ApacheHttpClient.java | 64 +- .../jackson/jaxb/JacksonJaxbJsonEncoder.java | 4 +- .../jackson/jaxb/JacksonJaxbCodecTest.java | 7 +- .../feign/jackson/jr/JacksonJrEncoder.java | 5 +- .../feign/jackson/jr/JacksonCodecTest.java | 32 +- .../java/feign/jackson/JacksonEncoder.java | 4 +- .../java/feign/jackson/JacksonCodecTest.java | 31 +- .../feign/jackson/JacksonIteratorTest.java | 10 +- .../java/feign/jackson3/Jackson3Encoder.java | 4 +- .../feign/jackson3/Jackson3CodecTest.java | 31 +- .../java/feign/http2client/Http2Client.java | 110 +--- .../test/Http2ClientAsyncTest.java | 11 +- .../src/main/java/feign/jaxb/JAXBEncoder.java | 3 +- .../test/java/feign/jaxb/JAXBCodecTest.java | 27 +- .../jaxb/examples/AWSSignatureVersion4.java | 11 +- .../src/main/java/feign/jaxb/JAXBEncoder.java | 3 +- .../test/java/feign/jaxb/JAXBCodecTest.java | 27 +- .../jaxb/examples/AWSSignatureVersion4.java | 11 +- .../main/java/feign/jaxrs2/JAXRSClient.java | 29 +- .../src/main/java/feign/json/JsonEncoder.java | 3 +- .../test/java/feign/json/JsonCodecTest.java | 7 +- .../test/java/feign/json/JsonDecoderTest.java | 4 +- .../test/java/feign/json/JsonEncoderTest.java | 18 +- .../kotlin/feign/kotlin/CoroutineFeignTest.kt | 5 +- .../java/feign/micrometer/MeteredEncoder.java | 16 +- mock/src/main/java/feign/mock/RequestKey.java | 47 +- .../test/java/feign/mock/MockClientTest.java | 41 +- .../test/java/feign/mock/RequestKeyTest.java | 35 +- .../main/java/feign/moshi/MoshiEncoder.java | 3 +- .../java/feign/moshi/MoshiDecoderTest.java | 19 +- .../main/java/feign/okhttp/OkHttpClient.java | 56 +- .../feign/okhttp/OkHttpClientAsyncTest.java | 11 +- pom.xml | 8 - .../src/main/java/feign/ribbon/LBClient.java | 13 +- .../test/java/feign/ribbon/LBClientTest.java | 4 +- .../test/java/feign/sax/SAXDecoderTest.java | 9 +- .../sax/examples/AWSSignatureVersion4.java | 11 +- .../java/feign/slf4j/Slf4jLoggerTest.java | 11 +- .../src/main/java/feign/soap/SOAPEncoder.java | 9 +- .../test/java/feign/soap/SOAPCodecTest.java | 27 +- .../java/feign/soap/SOAPFaultDecoderTest.java | 13 +- .../src/main/java/feign/soap/SOAPEncoder.java | 3 +- .../test/java/feign/soap/SOAPCodecTest.java | 27 +- .../java/feign/soap/SOAPFaultDecoderTest.java | 13 +- .../java/feign/spring/SpringContractTest.java | 11 +- .../BeanValidationMethodInterceptorTest.java | 4 +- .../BeanValidationMethodInterceptorTest.java | 4 +- .../src/main/java/feign/VertxFeign.java | 11 +- .../java/feign/vertx/OutputToReadStream.java | 308 ---------- .../java/feign/vertx/VertxHttpClient.java | 26 +- .../feign/vertx/ConnectionsLeakTests.java | 2 - .../vertx/Http11ClientReconnectTest.java | 1 - .../java/feign/vertx/QueryMapEncoderTest.java | 1 - .../java/feign/vertx/RawContractTest.java | 1 - .../feign/vertx/RequestPreProcessorTest.java | 1 - .../test/java/feign/vertx/RetryingTest.java | 1 - .../java/feign/vertx/TimeoutHandlingTest.java | 1 - .../java/feign/vertx/VertxHttpClientTest.java | 20 - .../feign/vertx/VertxHttpOptionsTest.java | 2 - .../feign/vertx/ConnectionsLeakTests.java | 2 - .../vertx/Http11ClientReconnectTest.java | 1 - .../java/feign/vertx/QueryMapEncoderTest.java | 1 - .../java/feign/vertx/RawContractTest.java | 1 - .../feign/vertx/RequestPreProcessorTest.java | 1 - .../test/java/feign/vertx/RetryingTest.java | 1 - .../java/feign/vertx/TimeoutHandlingTest.java | 1 - .../java/feign/vertx/VertxHttpClientTest.java | 20 - .../feign/vertx/VertxHttpOptionsTest.java | 2 - 120 files changed, 1037 insertions(+), 2088 deletions(-) delete mode 100644 MIGRATION-v14.md delete mode 100644 hc5/src/main/java/feign/hc5/FeignBodyEntity.java delete mode 100644 vertx/feign-vertx/src/main/java/feign/vertx/OutputToReadStream.java diff --git a/MIGRATION-v14.md b/MIGRATION-v14.md deleted file mode 100644 index e489aa707a..0000000000 --- a/MIGRATION-v14.md +++ /dev/null @@ -1,421 +0,0 @@ -# Migration Guide — Feign v14 (Request Body Streaming) - -This guide covers the breaking changes introduced in #3360 and explains how to update your code. - -> **Target release:** `v14.rc.1` - ---- - -## Overview - -`feign.Request.Body` has been redesigned from a `byte[]`-backed concrete class into a **streaming-ready interface**. -Request bodies are no longer eagerly buffered in memory unless you explicitly use the `byte[]`/`String` factory methods. - -For most users, regular Feign usage via interface annotations and `Feign.builder().target(...)` is unchanged. -The **breaking changes** primarily affect code that interacts directly with request body internals, including: - -- Custom `Encoder` implementations -- Custom `Client` implementations -- Any code that directly reads `Request.body()`, `Request.length()`, `Request.charset()`, or `RequestTemplate.body()`/ - `RequestTemplate.requestBody()` - ---- - -## Breaking Changes - -### 1. `Request.Body` is now an interface - -**Before:** - -```java -// Body was a concrete class with public fields/methods -Request.Body body = Request.Body.create("hello", StandardCharsets.UTF_8); -byte[] bytes = body.asBytes(); -String str = body.asString(); -int len = body.length(); -Optional charset = body.getEncoding(); -boolean binary = body.isBinary(); -``` - -**After:** - -```java -// Body is now an interface — use the factory methods -Request.Body body = Request.Body.of("hello", StandardCharsets.UTF_8); - -// To read content, write it to a stream (note: these methods throw checked IOException): -byte[] bytes = body.writeToByteArray(); -String str = body.writeToString(StandardCharsets.UTF_8); -long len = body.contentLength(); // -1 if unknown/streaming -boolean repeatable = body.isRepeatable(); -``` - -**Removed methods on `Request.Body`:** - -| Removed | Replacement | -|---------------------------------|---------------------------------------------------------------------------------------| -| `Body.create(String)` | `Body.of(String)` | -| `Body.create(String, Charset)` | `Body.of(String, Charset)` | -| `Body.create(byte[])` | `Body.of(byte[])` | -| `Body.create(byte[], Charset)` | `Body.of(byte[], Charset)` | -| `Body.encoded(byte[], Charset)` | `Body.of(byte[], Charset)` | -| `Body.empty()` | Pass `null` for no body | -| `body.asBytes()` | `body.writeToByteArray()` | -| `body.asString()` | `body.writeToString(charset)` | -| `body.length()` → `int` | `body.contentLength()` → `long` (returns `-1` if unknown) | -| `body.getEncoding()` | Read charset from `Content-Type` header | -| `body.isBinary()` | No direct replacement; `body.isRepeatable()` may be useful depending on your use case | - ---- - -### 2. `Request.body()` now returns `Optional` - -**Before:** - -```java -byte[] body = request.body(); // nullable byte[] -if (body != null) { - out.write(body); -} -``` - -**After:** - -```java -// writeTo(OutputStream) throws checked IOException, so a plain Consumer lambda -// (as used in Optional.ifPresent) cannot propagate it. Use an explicit if-block instead. -Optional body = request.body(); -if (body.isPresent()) { - body.get().writeTo(out); -} -``` - ---- - -### 3. `Request.length()` removed - -**Before:** - -```java -int length = request.length(); -``` - -**After:** - -```java -// contentLength() does not throw, so Optional.map is safe here. -long length = request.body() - .map(Request.Body::contentLength) - .orElse(0L); -``` - ---- - -### 4. `Request.charset()` removed - -**Before:** - -```java -Charset charset = request.charset(); -``` - -**After:** Read the charset from the `Content-Type` request header. There is no longer a charset field on `Request` -itself. - ---- - -### 5. `Request.isBinary()` removed - -**Before:** - -```java -boolean binary = request.isBinary(); -``` - -**After:** - -```java -// There is no direct replacement for request.isBinary(). -// Depending on why you were checking it, request body repeatability may be useful: -boolean repeatable = request.body() - .map(Request.Body::isRepeatable) - .orElse(false); -``` - ---- - -### 6. `Request.create(...)` overloads removed - -The `byte[]` + `Charset`-based `Request.create(...)` overloads have been removed. - -**Before:** - -```java -Request.create(HttpMethod.GET, url, headers, bodyBytes, charset); -Request.create(HttpMethod.GET, url, headers, bodyBytes, charset, requestTemplate); -// Deprecated String-based variant: -Request.create("GET", url, headers, bodyBytes, charset); -``` - -**After:** - -```java -// With a body: -Request.create(HttpMethod.GET, url, headers, Request.Body.of(bodyBytes), requestTemplate); - -// Without a body: -Request.create(HttpMethod.GET, url, headers, null, null); -``` - ---- - -### 7. `RequestTemplate` API changes - -#### `RequestTemplate.body(String)` removed - -**Before:** - -```java -template.body("hello world"); -``` - -**After:** - -```java -template.body(Request.Body.of("hello world")); -``` - -#### `RequestTemplate.body(byte[], Charset)` deprecated - -**Before:** - -```java -template.body(bytes, StandardCharsets.UTF_8); -``` - -**After:** - -```java -template.body(Request.Body.of(bytes, StandardCharsets.UTF_8)); -// or, if charset is irrelevant for your use case: -template.body(Request.Body.of(bytes)); -``` - -#### `RequestTemplate.body()` (returns `byte[]`) removed - -**Before:** - -```java -byte[] body = template.body(); -``` - -**After:** - -```java -// writeToByteArray() throws checked IOException, so a plain Function lambda -// (as used in Optional.map) cannot propagate it. Use an explicit if-block instead. -byte[] body = null; -Optional requestBody = template.requestBody(); -if (requestBody.isPresent()) { - body = requestBody.get().writeToByteArray(); -} -``` - -#### `RequestTemplate.requestBody()` is no longer `@Deprecated` - -The method now returns `Optional` and is the primary accessor. - -#### `RequestTemplate.requestCharset()` removed - -**Before:** - -```java -Charset charset = template.requestCharset(); -``` - -**After:** Read charset from the `Content-Type` header. There is no longer a charset tracked on the template itself. - ---- - -### 8. Custom `Encoder` implementations - -If you implement a custom `Encoder`, update calls to `template.body(...)`: - -**Before:** - -```java -template.body(serialized.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); -// or -template.body(serialized); -``` - -**After:** - -```java -template.body(Request.Body.of(serialized, StandardCharsets.UTF_8)); -// or, for UTF-8 strings: -template.body(Request.Body.of(serialized)); -``` - ---- - -### 9. Custom `Client` implementations - -If you implement a custom `Client`, update how you write the request body: - -**Before:** - -```java -byte[] body = request.body(); -if (body != null) { - outputStream.write(body); -} -``` - -**After:** - -```java -// writeTo(OutputStream) throws checked IOException, so a plain Consumer lambda -// (as used in Optional.ifPresent) cannot propagate it. Use an explicit if-block instead. -Optional body = request.body(); -if (body.isPresent()) { - body.get().writeTo(outputStream); -} -``` - -For retry-capable clients, check `body.isRepeatable()` before attempting a retry — non-repeatable (streaming) bodies -cannot be re-sent. - ---- - -### 10. `FeignException.errorReading(...)` — request body no longer captured - -`FeignException` no longer captures the request body when a read error occurs, because the body may be a non-repeatable -stream. Code asserting `exception.contentUTF8()` returns the request body must be updated: - -**Before:** - -```java -assertThat(exception.contentUTF8()).isEqualTo("Request body"); -``` - -**After:** - -```java -assertThat(exception.contentUTF8()).isEmpty(); -``` - ---- - -### 11. `mock` module — `RequestKey` no longer stores `Charset` - -**Before:** - -```java -RequestKey.builder(...).charset(StandardCharsets.UTF_8).build(); -``` - -**After:** The `charset(Charset)` method has been removed from `RequestKey.Builder`. Remove it from your mock setup -code. - ---- - -### 12. `Request.Body` no longer implements `Serializable` - -`feign.Request.Body` previously implemented `java.io.Serializable`. This has been removed. -If you were serializing `Request.Body` objects (e.g., for caching or distributed tracing), you will need an alternative -serialization strategy. - ---- - -### 13. Vert.x integration — `VertxFeign.Builder` now requires `.vertx(Vertx)` - -**Before:** - -```java -VertxFeign.builder() - .webClient(webClient) - .target(MyApi.class, url); -``` - -**After:** - -```java -VertxFeign.builder() - .vertx(vertx) // required — NPE with descriptive message if missing - .webClient(webClient) - .target(MyApi.class, url); -``` - ---- - -## Implementing a Custom Streaming Body - -If you want to stream a body (e.g., from a file or `InputStream`), implement `Request.Body` directly. Because -`writeTo(OutputStream)` itself declares `throws IOException`, the lambda **can** propagate it freely — the restriction -only applies to standard functional interfaces (`Consumer`, `Function`, etc.) that don't -declare checked exceptions. - -```java -// One-shot InputStream — non-repeatable (isRepeatable() defaults to false) -Request.Body streamingBody = outputStream -> { - try (InputStream in = Files.newInputStream(path)) { - byte[] buffer = new byte[8192]; - int read; - while ((read = in.read(buffer)) != -1) { - outputStream.write(buffer, 0, read); - } - // or, with Java 9+: - // in.transferTo(outputStream); - } - // IOException propagates naturally — no try-catch needed here -}; -template.body(streamingBody); -``` - -For a repeatable streaming body (e.g., backed by a file that can be re-read): - -```java -public class FileBody implements Request.Body { - private final Path path; - - public FileBody(Path path) { - this.path = path; - } - - @Override - public void writeTo(OutputStream out) throws IOException { - try (InputStream in = Files.newInputStream(path)) { - byte[] buffer = new byte[8192]; - int read; - while ((read = in.read(buffer)) != -1) { - out.write(buffer, 0, read); - } - // or, with Java 9+: - // in.transferTo(out); - } - } - - @Override - public boolean isRepeatable() { - return true; - } - - @Override - public long contentLength() { - try { - return Files.size(path); - } catch (IOException e) { - return super.contentLength(); // returns -1 - } - } -} -``` - ---- - -## Spring Cloud OpenFeign Compatibility - -`RequestTemplate#body(byte[], Charset)` is kept `@Deprecated` for backward compatibility with -`spring-cloud-openfeign-core`. Spring Cloud OpenFeign users are not required to make any changes immediately, but should -migrate to `body(Request.Body)` once the Spring team provides an updated release. diff --git a/annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java b/annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java index 23d5f317b4..2d2c0fe74b 100644 --- a/annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java +++ b/annotation-error-decoder/src/main/java/feign/error/ExceptionGenerator.java @@ -45,7 +45,9 @@ class ExceptionGenerator { .status(500) .body((Response.Body) null) .headers(testHeaders) - .request(Request.create(Request.HttpMethod.GET, "http://test", testHeaders, null, null)) + .request( + Request.create( + Request.HttpMethod.GET, "http://test", testHeaders, Request.Body.empty(), null)) .build(); } diff --git a/annotation-error-decoder/src/test/java/feign/error/AbstractAnnotationErrorDecoderTest.java b/annotation-error-decoder/src/test/java/feign/error/AbstractAnnotationErrorDecoderTest.java index 1d7375b30e..e66a25a9f4 100644 --- a/annotation-error-decoder/src/test/java/feign/error/AbstractAnnotationErrorDecoderTest.java +++ b/annotation-error-decoder/src/test/java/feign/error/AbstractAnnotationErrorDecoderTest.java @@ -45,7 +45,9 @@ Response testResponse(int status, String body, Map> h .status(status) .body(body, StandardCharsets.UTF_8) .headers(headers) - .request(Request.create(Request.HttpMethod.GET, "http://test", headers, null, null)) + .request( + Request.create( + Request.HttpMethod.GET, "http://test", headers, Request.Body.empty(), null)) .build(); } } diff --git a/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java b/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java index 82f0d9231c..9728a46f5e 100644 --- a/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java +++ b/annotation-error-decoder/src/test/java/feign/error/AnnotationErrorDecoderExceptionConstructorsTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import feign.Request; import feign.codec.DefaultDecoder; import feign.error.AnnotationErrorDecoderExceptionConstructorsTest.TestClientInterfaceWithDifferentExceptionConstructors; import feign.error.AnnotationErrorDecoderExceptionConstructorsTest.TestClientInterfaceWithDifferentExceptionConstructors.DeclaredDefaultConstructorException; @@ -55,7 +56,11 @@ public class AnnotationErrorDecoderExceptionConstructorsTest private static final String NON_NULL_BODY = "A GIVEN BODY"; private static final feign.Request REQUEST = feign.Request.create( - feign.Request.HttpMethod.GET, "http://test", Collections.emptyMap(), null, null); + feign.Request.HttpMethod.GET, + "http://test", + Collections.emptyMap(), + Request.Body.empty(), + null); private static final feign.Request NO_REQUEST = null; private static final Map> NON_NULL_HEADERS = new HashMap<>(); private static final Map> NO_HEADERS = null; diff --git a/benchmark/src/main/java/feign/benchmark/DecoderIteratorsBenchmark.java b/benchmark/src/main/java/feign/benchmark/DecoderIteratorsBenchmark.java index ebe9ad7188..76fbc1e1b3 100644 --- a/benchmark/src/main/java/feign/benchmark/DecoderIteratorsBenchmark.java +++ b/benchmark/src/main/java/feign/benchmark/DecoderIteratorsBenchmark.java @@ -82,7 +82,7 @@ public void buildResponse() { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(carsJson(Integer.parseInt(size)), Util.UTF_8) .build(); diff --git a/core/src/main/java/feign/DefaultClient.java b/core/src/main/java/feign/DefaultClient.java index ec0df4644b..d8e02fb4ad 100644 --- a/core/src/main/java/feign/DefaultClient.java +++ b/core/src/main/java/feign/DefaultClient.java @@ -32,7 +32,6 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.TreeMap; import java.util.zip.DeflaterOutputStream; import java.util.zip.GZIPInputStream; @@ -188,9 +187,9 @@ else if (field.equals(ACCEPT_ENCODING)) { connection.addRequestProperty("Accept", "*/*"); } - Optional body = request.body(); + byte[] body = request.body(); - if (body.isPresent()) { + if (body != null) { /* * Ignore disableRequestBuffering flag if the empty body was set, to ensure that internal * retry logic applies to such requests. @@ -210,7 +209,7 @@ else if (field.equals(ACCEPT_ENCODING)) { out = new DeflaterOutputStream(out); } try { - body.get().writeTo(out); + out.write(body); } finally { try { out.close(); @@ -219,7 +218,7 @@ else if (field.equals(ACCEPT_ENCODING)) { } } - if (!body.isPresent() && request.httpMethod().isWithBody()) { + if (body == null && request.httpMethod().isWithBody()) { // To use this Header, set 'sun.net.http.allowRestrictedHeaders' property true. connection.addRequestProperty("Content-Length", "0"); } diff --git a/core/src/main/java/feign/DefaultContract.java b/core/src/main/java/feign/DefaultContract.java index a59b1183c9..79edadde82 100644 --- a/core/src/main/java/feign/DefaultContract.java +++ b/core/src/main/java/feign/DefaultContract.java @@ -76,7 +76,7 @@ public DefaultContract() { "Body annotation was empty on method %s.", data.configKey()); if (body.indexOf('{') == -1) { - data.template().body(Request.Body.of(body)); + data.template().body(body); } else { data.template().bodyTemplate(body); } diff --git a/core/src/main/java/feign/FeignException.java b/core/src/main/java/feign/FeignException.java index f053591c96..b7ea794cae 100644 --- a/core/src/main/java/feign/FeignException.java +++ b/core/src/main/java/feign/FeignException.java @@ -15,9 +15,7 @@ */ package feign; -import static feign.Util.UTF_8; -import static feign.Util.caseInsensitiveCopyOf; -import static feign.Util.checkNotNull; +import static feign.Util.*; import static java.lang.String.format; import static java.util.regex.Pattern.CASE_INSENSITIVE; @@ -184,7 +182,7 @@ static FeignException errorReading(Request request, Response response, IOExcepti format("%s reading %s %s", cause.getMessage(), request.httpMethod(), request.url()), request, cause, - null, + request.body(), request.headers()); } diff --git a/core/src/main/java/feign/Logger.java b/core/src/main/java/feign/Logger.java index ae297d3861..a460251a6a 100644 --- a/core/src/main/java/feign/Logger.java +++ b/core/src/main/java/feign/Logger.java @@ -78,18 +78,16 @@ protected void logRequest(String configKey, Level logLevel, Request request) { } } - long bodyLength = - request - .body() - .map( - body -> { - if (logLevel.ordinal() >= Level.FULL.ordinal()) { - log(configKey, ""); // CRLF - log(configKey, "%s", body.toString()); - } - return body.contentLength(); - }) - .orElse(0L); + int bodyLength = 0; + if (request.body() != null) { + bodyLength = request.length(); + if (logLevel.ordinal() >= Level.FULL.ordinal()) { + String bodyText = + request.charset() != null ? new String(request.body(), request.charset()) : null; + log(configKey, ""); // CRLF + log(configKey, "%s", bodyText != null ? bodyText : "Binary data"); + } + } log(configKey, "---> END HTTP (%s-byte body)", bodyLength); } } diff --git a/core/src/main/java/feign/Request.java b/core/src/main/java/feign/Request.java index 00ff8ad039..a3627a164d 100644 --- a/core/src/main/java/feign/Request.java +++ b/core/src/main/java/feign/Request.java @@ -19,30 +19,150 @@ import static feign.Util.getThreadIdentifier; import static feign.Util.valuesOrEmpty; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; import java.io.Serializable; import java.net.HttpURLConnection; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; /** An immutable request to an http server. */ public final class Request implements Serializable { + + public enum HttpMethod { + GET, + HEAD, + POST(true), + PUT(true), + DELETE, + CONNECT, + OPTIONS, + TRACE, + PATCH(true); + + private final boolean withBody; + + HttpMethod() { + this(false); + } + + HttpMethod(boolean withBody) { + this.withBody = withBody; + } + + public boolean isWithBody() { + return this.withBody; + } + } + + public enum ProtocolVersion { + HTTP_1_0("HTTP/1.0"), + HTTP_1_1("HTTP/1.1"), + HTTP_2("HTTP/2.0"), + MOCK; + + final String protocolVersion; + + ProtocolVersion() { + protocolVersion = name(); + } + + ProtocolVersion(String protocolVersion) { + this.protocolVersion = protocolVersion; + } + + @Override + public String toString() { + return protocolVersion; + } + } + + /** + * No parameters can be null except {@code body} and {@code charset}. All parameters must be + * effectively immutable, via safe copies, not mutating or otherwise. + * + * @deprecated {@link #create(HttpMethod, String, Map, byte[], Charset)} + */ + @Deprecated + public static Request create( + String method, + String url, + Map> headers, + byte[] body, + Charset charset) { + checkNotNull(method, "httpMethod of %s", method); + final HttpMethod httpMethod = HttpMethod.valueOf(method.toUpperCase()); + return create(httpMethod, url, headers, body, charset, null); + } + + /** + * Builds a Request. All parameters must be effectively immutable, via safe copies. + * + * @param httpMethod for the request. + * @param url for the request. + * @param headers to include. + * @param body of the request, can be {@literal null} + * @param charset of the request, can be {@literal null} + * @return a Request + */ + @Deprecated + public static Request create( + HttpMethod httpMethod, + String url, + Map> headers, + byte[] body, + Charset charset) { + return create(httpMethod, url, headers, Body.create(body, charset), null); + } + + /** + * Builds a Request. All parameters must be effectively immutable, via safe copies. + * + * @param httpMethod for the request. + * @param url for the request. + * @param headers to include. + * @param body of the request, can be {@literal null} + * @param charset of the request, can be {@literal null} + * @return a Request + */ + public static Request create( + HttpMethod httpMethod, + String url, + Map> headers, + byte[] body, + Charset charset, + RequestTemplate requestTemplate) { + return create(httpMethod, url, headers, Body.create(body, charset), requestTemplate); + } + + /** + * Builds a Request. All parameters must be effectively immutable, via safe copies. + * + * @param httpMethod for the request. + * @param url for the request. + * @param headers to include. + * @param body of the request, can be {@literal null} + * @return a Request + */ + public static Request create( + HttpMethod httpMethod, + String url, + Map> headers, + Body body, + RequestTemplate requestTemplate) { + return new Request(httpMethod, url, headers, body, requestTemplate); + } + private final HttpMethod httpMethod; private final String url; private final Map> headers; - private final transient Body body; + private final Body body; private final RequestTemplate requestTemplate; private final ProtocolVersion protocolVersion; @@ -70,40 +190,41 @@ public final class Request implements Serializable { } /** - * Builds a Request. All parameters must be effectively immutable, via safe copies. + * Http Method for this request. * - * @param httpMethod for the request. - * @param url for the request. - * @param headers to include. - * @param body of the request, can be {@literal null} - * @return a Request + * @return the HttpMethod string + * @deprecated @see {@link #httpMethod()} */ - public static Request create( - HttpMethod httpMethod, - String url, - Map> headers, - Body body, - RequestTemplate requestTemplate) { - return new Request(httpMethod, url, headers, body, requestTemplate); + @Deprecated + public String method() { + return httpMethod.name(); } /** - * Returns the body of the request, if any. + * Http Method for the request. * - * @return the body of the request, if any + * @return the HttpMethod. */ - public Optional body() { - return Optional.ofNullable(body); + public HttpMethod httpMethod() { + return this.httpMethod; } /** - * Add new entries to request Headers. It overrides existing entries + * URL for the request. * - * @param key - * @param values + * @return URL as a String. */ - public void header(String key, Collection values) { - headers.put(key, values); + public String url() { + return url; + } + + /** + * Request Headers. + * + * @return the request headers. + */ + public Map> headers() { + return Collections.unmodifiableMap(headers); } /** @@ -117,44 +238,54 @@ public void header(String key, String value) { } /** - * Request Headers. + * Add new entries to request Headers. It overrides existing entries * - * @return the request headers. + * @param key + * @param values */ - public Map> headers() { - return Collections.unmodifiableMap(headers); + public void header(String key, Collection values) { + headers.put(key, values); } /** - * Http Method for the request. + * Charset of the request. * - * @return the HttpMethod. + * @return the current character set for the request, may be {@literal null} for binary data. */ - public HttpMethod httpMethod() { - return this.httpMethod; + public Charset charset() { + return body.encoding; } /** - * Request HTTP protocol version + * If present, this is the replayable body to send to the server. In some cases, this may be + * interpretable as text. * - * @return HTTP protocol version + * @see #charset() */ - public ProtocolVersion protocolVersion() { - return protocolVersion; + public byte[] body() { + return body.data; } - @Experimental - public RequestTemplate requestTemplate() { - return this.requestTemplate; + public boolean isBinary() { + return body.isBinary(); } /** - * URL for the request. + * Request Length. * - * @return URL as a String. + * @return size of the request body. */ - public String url() { - return url; + public int length() { + return this.body.length(); + } + + /** + * Request HTTP protocol version + * + * @return HTTP protocol version + */ + public ProtocolVersion protocolVersion() { + return protocolVersion; } /** @@ -178,185 +309,51 @@ public String toString() { } } if (body != null) { - builder.append('\n').append(body); + builder.append('\n').append(body.asString()); } return builder.toString(); } - public enum HttpMethod { - GET, - HEAD, - POST(true), - PUT(true), - DELETE, - CONNECT, - OPTIONS, - TRACE, - PATCH(true); - - private final boolean withBody; - - HttpMethod() { - this(false); - } - - HttpMethod(boolean withBody) { - this.withBody = withBody; - } - - public boolean isWithBody() { - return this.withBody; - } - } - - public enum ProtocolVersion { - HTTP_1_0("HTTP/1.0"), - HTTP_1_1("HTTP/1.1"), - HTTP_2("HTTP/2.0"), - MOCK; - - final String protocolVersion; - - ProtocolVersion() { - protocolVersion = name(); - } - - ProtocolVersion(String protocolVersion) { - this.protocolVersion = protocolVersion; - } - - @Override - public String toString() { - return protocolVersion; - } - } - /** - * Request Body - * - *

Considered experimental, will most likely be made internal going forward. + * Controls the per-request settings currently required to be implemented by all {@link Client + * clients} */ - @Experimental - @FunctionalInterface - public interface Body { - /** - * Creates a new {@link Body} instance from the provided string content. - * - * @param content the string content to be used as the body of the request - * @return a new {@link Body} instance containing the provided string content - * @apiNote It's assumed that the content was constructed using {@link StandardCharsets#UTF_8} - * charset. - */ - static Body of(String content) { - return of(content, StandardCharsets.UTF_8); - } - - /** - * Creates a new {@link Body} instance from the provided byte array. - * - * @param content the byte array representing the body content - * @return a new {@link Body} instance - * @apiNote It's assumed that the byte array can be converted to a string using {@link - * StandardCharsets#UTF_8} charset. - */ - static Body of(byte[] content) { - return of(content, StandardCharsets.UTF_8); - } - - /** - * Creates a new {@link Body} instance from the provided string content, using the specified - * charset. - * - * @param content the string content to be used as the body content - * @param charset the content charset - * @return a new {@link Body} instance containing the provided content - */ - static Body of(String content, Charset charset) { - Objects.requireNonNull(content, "content is required"); - Objects.requireNonNull(charset, "charset is required"); - - return of(content.getBytes(charset), charset); - } - - /** - * Creates a new {@link Body} instance from the provided byte array, using the specified - * charset. - * - * @param content the byte array representing the body content - * @param charset the content charset - * @return a new {@link Body} instance - */ - static Body of(byte[] content, Charset charset) { - return new Request.BodyImpl(content, charset); - } - - /** - * Writes the body content to the provided {@link OutputStream}. - * - * @param outputStream the output stream to which the body content should be written - * @throws IOException if an I/O error occurs while writing the body content - */ - void writeTo(OutputStream outputStream) throws IOException; - - /** - * Writes the body content to a byte array. - * - * @return a byte array containing the body content - * @throws IOException if an I/O error occurs while writing the body content to a byte array - */ - default byte[] writeToByteArray() throws IOException { - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - writeTo(outputStream); - return outputStream.toByteArray(); - } - } + public static class Options { - /** - * Writes the body content to a string using the specified charset for decoding. - * - * @param charset the charset to be used for decoding the body content - * @return a string representation of the body content - * @throws IOException if an I/O error occurs while writing the body content to a string - */ - default String writeToString(Charset charset) throws IOException { - Objects.requireNonNull(charset, "charset is required"); - return new String(writeToByteArray(), charset); - } + private final long connectTimeout; + private final TimeUnit connectTimeoutUnit; + private final long readTimeout; + private final TimeUnit readTimeoutUnit; + private final boolean followRedirects; + private final Map> threadToMethodOptions; /** - * Returns the content length of the body, or {@code -1} if unknown. This can be used by clients - * to set the {@code Content-Length} header. Defaults to {@code -1}. + * Get an Options by methodName * - * @return the content length, or {@code -1} if unknown + * @param methodName it's your FeignInterface method name. + * @return method Options */ - default long contentLength() { - return -1; + @Experimental + public Options getMethodOptions(String methodName) { + Map methodOptions = + threadToMethodOptions.getOrDefault(getThreadIdentifier(), new HashMap<>()); + return methodOptions.getOrDefault(methodName, this); } /** - * Indicates whether the body can be written multiple times. This is important for clients that - * may need to retry requests, as non-repeatable bodies (e.g., streaming data) cannot be - * re-sent. Defaults to {@code false}. + * Set methodOptions by methodKey and options * - * @return {@code true} if the body can be written multiple times, {@code false} otherwise + * @param methodName it's your FeignInterface method name. + * @param options it's the Options for this method. */ - default boolean isRepeatable() { - return false; + @Experimental + public void setMethodOptions(String methodName, Options options) { + String threadIdentifier = getThreadIdentifier(); + Map methodOptions = + threadToMethodOptions.getOrDefault(threadIdentifier, new HashMap<>()); + threadToMethodOptions.put(threadIdentifier, methodOptions); + methodOptions.put(methodName, options); } - } - - /** - * Controls the per-request settings currently required to be implemented by all {@link Client - * clients} - */ - public static class Options { - - private final long connectTimeout; - private final TimeUnit connectTimeoutUnit; - private final long readTimeout; - private final TimeUnit readTimeoutUnit; - private final boolean followRedirects; - private final Map> threadToMethodOptions; /** * Creates a new Options instance. @@ -441,15 +438,6 @@ public Options() { this(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true); } - /** - * Connect Timeout Value. - * - * @return current timeout value. - */ - public long connectTimeout() { - return connectTimeout; - } - /** * Defaults to 10 seconds. {@code 0} implies no timeout. * @@ -460,52 +448,48 @@ public int connectTimeoutMillis() { } /** - * TimeUnit for the Connection Timeout value. + * Defaults to 60 seconds. {@code 0} implies no timeout. * - * @return TimeUnit + * @see java.net.HttpURLConnection#getReadTimeout() */ - public TimeUnit connectTimeoutUnit() { - return connectTimeoutUnit; + public int readTimeoutMillis() { + return (int) readTimeoutUnit.toMillis(readTimeout); } /** - * Get an Options by methodName + * Defaults to true. {@code false} tells the client to not follow the redirections. * - * @param methodName it's your FeignInterface method name. - * @return method Options + * @see HttpURLConnection#getFollowRedirects() */ - @Experimental - public Options getMethodOptions(String methodName) { - Map methodOptions = - threadToMethodOptions.getOrDefault(getThreadIdentifier(), new HashMap<>()); - return methodOptions.getOrDefault(methodName, this); + public boolean isFollowRedirects() { + return followRedirects; } /** - * Defaults to true. {@code false} tells the client to not follow the redirections. + * Connect Timeout Value. * - * @see HttpURLConnection#getFollowRedirects() + * @return current timeout value. */ - public boolean isFollowRedirects() { - return followRedirects; + public long connectTimeout() { + return connectTimeout; } /** - * Read Timeout value. + * TimeUnit for the Connection Timeout value. * - * @return current read timeout value. + * @return TimeUnit */ - public long readTimeout() { - return readTimeout; + public TimeUnit connectTimeoutUnit() { + return connectTimeoutUnit; } /** - * Defaults to 60 seconds. {@code 0} implies no timeout. + * Read Timeout value. * - * @see java.net.HttpURLConnection#getReadTimeout() + * @return current read timeout value. */ - public int readTimeoutMillis() { - return (int) readTimeoutUnit.toMillis(readTimeout); + public long readTimeout() { + return readTimeout; } /** @@ -516,50 +500,91 @@ public int readTimeoutMillis() { public TimeUnit readTimeoutUnit() { return readTimeoutUnit; } + } - /** - * Set methodOptions by methodKey and options - * - * @param methodName it's your FeignInterface method name. - * @param options it's the Options for this method. - */ - @Experimental - public void setMethodOptions(String methodName, Options options) { - String threadIdentifier = getThreadIdentifier(); - Map methodOptions = - threadToMethodOptions.getOrDefault(threadIdentifier, new HashMap<>()); - threadToMethodOptions.put(threadIdentifier, methodOptions); - methodOptions.put(methodName, options); - } + @Experimental + public RequestTemplate requestTemplate() { + return this.requestTemplate; } - private static class BodyImpl implements Body { - private final byte[] content; - private final Charset charset; + /** + * Request Body + * + *

Considered experimental, will most likely be made internal going forward. + */ + @Experimental + public static class Body implements Serializable { + + private transient Charset encoding; + + private byte[] data; - private BodyImpl(byte[] content, Charset charset) { - this.content = Objects.requireNonNull(content, "content must not be null"); - this.charset = Objects.requireNonNull(charset, "charset must not be null"); + private Body() { + super(); } - @Override - public void writeTo(OutputStream outputStream) throws IOException { - Objects.requireNonNull(outputStream, "outputStream is required").write(content); + private Body(byte[] data) { + this.data = data; } - @Override - public long contentLength() { - return content.length; + private Body(byte[] data, Charset encoding) { + this.data = data; + this.encoding = encoding; } - @Override - public boolean isRepeatable() { - return true; + public Optional getEncoding() { + return Optional.ofNullable(this.encoding); } - @Override - public String toString() { - return new String(content, charset); + public int length() { + /* calculate the content length based on the data provided */ + return data != null ? data.length : 0; + } + + public byte[] asBytes() { + return data; + } + + public String asString() { + return !isBinary() ? new String(data, encoding) : "Binary data"; + } + + public boolean isBinary() { + return encoding == null || data == null; + } + + public static Body create(String data) { + return new Body(data.getBytes()); + } + + public static Body create(String data, Charset charset) { + return new Body(data.getBytes(charset), charset); + } + + public static Body create(byte[] data) { + return new Body(data); + } + + public static Body create(byte[] data, Charset charset) { + return new Body(data, charset); + } + + /** + * Creates a new Request Body with charset encoded data. + * + * @param data to be encoded. + * @param charset to encode the data with. if {@literal null}, then data will be considered + * binary and will not be encoded. + * @return a new Request.Body instance with the encoded data. + * @deprecated please use {@link Request.Body#create(byte[], Charset)} + */ + @Deprecated + public static Body encoded(byte[] data, Charset charset) { + return create(data, charset); + } + + public static Body empty() { + return new Body(); } } } diff --git a/core/src/main/java/feign/RequestTemplate.java b/core/src/main/java/feign/RequestTemplate.java index b4868481fb..6f376c4ae1 100644 --- a/core/src/main/java/feign/RequestTemplate.java +++ b/core/src/main/java/feign/RequestTemplate.java @@ -38,7 +38,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Optional; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -63,7 +62,7 @@ public final class RequestTemplate implements Serializable { private BodyTemplate bodyTemplate; private HttpMethod method; private transient Charset charset = Util.UTF_8; - private transient Request.Body body; + private Request.Body body = Request.Body.empty(); private boolean decodeSlash = true; private CollectionFormat collectionFormat = CollectionFormat.EXPLODED; private MethodMetadata methodMetadata; @@ -254,7 +253,7 @@ public RequestTemplate resolve(Map variables) { } if (this.bodyTemplate != null) { - resolved.body(Request.Body.of(this.bodyTemplate.expand(variables))); + resolved.body(this.bodyTemplate.expand(variables)); } /* mark the new template resolved */ @@ -882,14 +881,22 @@ public Map> headers() { * Sets the Body and Charset for this request. * * @param data to send, can be null. - * @param ignoredCharset of the encoded data. + * @param charset of the encoded data. * @return a RequestTemplate for chaining. - * @deprecated this method is kept to maintain compatibility with {@code - * spring-cloud-openfeign-core}. Please use {@link #body(Request.Body)} instead. */ - @Deprecated - public RequestTemplate body(byte[] data, Charset ignoredCharset) { - this.body(Request.Body.of(data)); + public RequestTemplate body(byte[] data, Charset charset) { + this.body(Request.Body.create(data, charset)); + return this; + } + + /** + * Set the Body for this request. Charset is assumed to be UTF_8. Data must be encoded. + * + * @param bodyText to send. + * @return a RequestTemplate for chaining. + */ + public RequestTemplate body(String bodyText) { + this.body(Request.Body.create(bodyText.getBytes(this.charset), this.charset)); return this; } @@ -898,30 +905,53 @@ public RequestTemplate body(byte[] data, Charset ignoredCharset) { * * @param body to send. * @return a RequestTemplate for chaining. + * @deprecated use {@link #body(byte[], Charset)} instead. */ + @Deprecated public RequestTemplate body(Request.Body body) { this.body = body; /* body template must be cleared to prevent double processing */ this.bodyTemplate = null; - /* reset any prior Content-Length so it cannot be duplicated or left stale */ - this.header(CONTENT_LENGTH, Collections.emptyList()); - if (body.contentLength() >= 0) { - this.header(CONTENT_LENGTH, String.valueOf(body.contentLength())); + header(CONTENT_LENGTH, Collections.emptyList()); + if (body.length() > 0) { + header(CONTENT_LENGTH, String.valueOf(body.length())); } return this; } + /** + * Charset of the Request Body, if known. + * + * @return the currently applied Charset. + */ + public Charset requestCharset() { + if (this.body != null) { + return this.body.getEncoding().orElse(this.charset); + } + return this.charset; + } + + /** + * The Request Body. + * + * @return the request body. + */ + public byte[] body() { + return body.asBytes(); + } + /** * The Request.Body internal object. * * @return the internal Request.Body. * @deprecated this abstraction is leaky and will be removed in later releases. */ - public Optional requestBody() { - return Optional.ofNullable(this.body); + @Deprecated + public Request.Body requestBody() { + return this.body; } /** diff --git a/core/src/main/java/feign/codec/DefaultEncoder.java b/core/src/main/java/feign/codec/DefaultEncoder.java index a32cf2065a..39a0f8daba 100644 --- a/core/src/main/java/feign/codec/DefaultEncoder.java +++ b/core/src/main/java/feign/codec/DefaultEncoder.java @@ -17,7 +17,6 @@ import static java.lang.String.format; -import feign.Request; import feign.RequestTemplate; import java.lang.reflect.Type; @@ -26,9 +25,9 @@ public class DefaultEncoder implements Encoder { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { if (bodyType == String.class) { - template.body(Request.Body.of(object.toString())); + template.body(object.toString()); } else if (bodyType == byte[].class) { - template.body(Request.Body.of((byte[]) object)); + template.body((byte[]) object, null); } else if (object != null) { throw new EncodeException( format("%s is not a type supported by this encoder.", object.getClass())); diff --git a/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java b/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java index a3100d882d..7a626d6ef0 100644 --- a/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java +++ b/core/src/test/java/feign/AlwaysEncodeBodyContractTest.java @@ -17,7 +17,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -66,7 +65,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) Object[] methodParameters = (Object[]) object; String body = Arrays.stream(methodParameters).map(String::valueOf).collect(Collectors.joining()); - template.body(Request.Body.of(body)); + template.body(body); } } @@ -74,22 +73,14 @@ private static class BodyParameterSampleEncoder implements Encoder { @Override public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { - template.body(Request.Body.of(String.valueOf(object))); + template.body(String.valueOf(object)); } } private static class SampleClient implements Client { @Override public Response execute(Request request, Request.Options options) throws IOException { - return Response.builder() - .status(200) - .request(request) - .body(request.body().map(this::bodyAsBytes).orElse(null)) - .build(); - } - - private byte[] bodyAsBytes(Request.Body body) { - return assertDoesNotThrow(body::writeToByteArray); + return Response.builder().status(200).request(request).body(request.body()).build(); } } diff --git a/core/src/test/java/feign/AsyncFeignTest.java b/core/src/test/java/feign/AsyncFeignTest.java index 2e683de5f8..300385be64 100644 --- a/core/src/test/java/feign/AsyncFeignTest.java +++ b/core/src/test/java/feign/AsyncFeignTest.java @@ -18,6 +18,7 @@ import static feign.ExceptionPropagationPolicy.UNWRAP; import static feign.Util.UTF_8; import static feign.assertj.MockWebServerAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; @@ -620,7 +621,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (FeignException e) { assertThat(e.getMessage()) .contains("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEmpty(); + assertThat(e.contentUTF8()).isEqualTo("Request body"); return; } fail(""); @@ -735,7 +736,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); @@ -1006,7 +1007,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(new HashMap<>()) .build(); } @@ -1263,9 +1264,9 @@ static final class TestInterfaceAsyncBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(Request.Body.of(new Gson().toJson(object))); + template.body(new Gson().toJson(object)); } else { - template.body(Request.Body.of(object.toString())); + template.body(object.toString()); } }); diff --git a/core/src/test/java/feign/ClientTest.java b/core/src/test/java/feign/ClientTest.java index c094cadabf..cdfe54d292 100644 --- a/core/src/test/java/feign/ClientTest.java +++ b/core/src/test/java/feign/ClientTest.java @@ -61,12 +61,13 @@ void testConvertAndSendWithAcceptEncoding() throws IOException { headers.put(Util.ACCEPT_ENCODING, acceptEncoding); RequestTemplate requestTemplate = mock(RequestTemplate.class); + Request.Body body = mock(Request.Body.class); Request.Options options = mock(Request.Options.class); Client client = mock(Client.class); Request request = Request.create( - Request.HttpMethod.GET, "http://example.com", headers, null, requestTemplate); + Request.HttpMethod.GET, "http://example.com", headers, body, requestTemplate); DefaultClient defaultClient = new DefaultClient(null, null); HttpURLConnection urlConnection = defaultClient.convertAndSend(request, options); Map> requestProperties = urlConnection.getRequestProperties(); @@ -81,12 +82,13 @@ void testConvertAndSendWithContentLength() throws IOException { headers.put(Util.CONTENT_LENGTH, Collections.singletonList("100")); RequestTemplate requestTemplate = mock(RequestTemplate.class); + Request.Body body = mock(Request.Body.class); Request.Options options = mock(Request.Options.class); Client client = mock(Client.class); Request request = Request.create( - Request.HttpMethod.GET, "http://example.com", headers, null, requestTemplate); + Request.HttpMethod.GET, "http://example.com", headers, body, requestTemplate); DefaultClient defaultClient = new DefaultClient(null, null); HttpURLConnection urlConnection = defaultClient.convertAndSend(request, options); Map> requestProperties = urlConnection.getRequestProperties(); diff --git a/core/src/test/java/feign/DefaultContractTest.java b/core/src/test/java/feign/DefaultContractTest.java index 0ecf46f4ae..6b26d1ed0e 100644 --- a/core/src/test/java/feign/DefaultContractTest.java +++ b/core/src/test/java/feign/DefaultContractTest.java @@ -17,6 +17,7 @@ import static feign.assertj.FeignAssertions.assertThat; import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.MapEntry.entry; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -144,15 +145,7 @@ void headersOnMethodAddsContentTypeHeader() throws Exception { assertThat(md.template()) .hasHeaders( entry("Content-Type", asList("application/xml")), - entry( - "Content-Length", - asList( - md.template() - .requestBody() - .map(Request.Body::contentLength) - .filter(contentLength -> contentLength >= 0) - .map(String::valueOf) - .orElse("0")))); + entry("Content-Length", asList(String.valueOf(md.template().body().length)))); } @Test @@ -162,15 +155,7 @@ void headersOnTypeAddsContentTypeHeader() throws Exception { assertThat(md.template()) .hasHeaders( entry("Content-Type", asList("application/xml")), - entry( - "Content-Length", - asList( - md.template() - .requestBody() - .map(Request.Body::contentLength) - .filter(contentLength -> contentLength >= 0) - .map(String::valueOf) - .orElse("0")))); + entry("Content-Length", asList(String.valueOf(md.template().body().length)))); } @Test @@ -180,15 +165,7 @@ void headersContainsWhitespaces() throws Exception { assertThat(md.template()) .hasHeaders( entry("Content-Type", Collections.singletonList("application/xml")), - entry( - "Content-Length", - asList( - md.template() - .requestBody() - .map(Request.Body::contentLength) - .filter(contentLength -> contentLength >= 0) - .map(String::valueOf) - .orElse("0")))); + entry("Content-Length", asList(String.valueOf(md.template().body().length)))); } @Test diff --git a/core/src/test/java/feign/FeignBuilderTest.java b/core/src/test/java/feign/FeignBuilderTest.java index d9ff04604d..2db2fd9df5 100644 --- a/core/src/test/java/feign/FeignBuilderTest.java +++ b/core/src/test/java/feign/FeignBuilderTest.java @@ -16,6 +16,7 @@ package feign; import static feign.assertj.MockWebServerAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; @@ -209,7 +210,7 @@ void overrideEncoder() throws Exception { server.enqueue(new MockResponse().setBody("response data")); String url = "http://localhost:" + server.getPort(); - Encoder encoder = (object, _, template) -> template.body(Request.Body.of(object.toString())); + Encoder encoder = (object, _, template) -> template.body(object.toString()); TestInterface api = Feign.builder().encoder(encoder).target(TestInterface.class, url); api.encodedPost(Arrays.asList("This", "is", "my", "request")); diff --git a/core/src/test/java/feign/FeignExceptionTest.java b/core/src/test/java/feign/FeignExceptionTest.java index 660af75fcf..f86d35fe19 100644 --- a/core/src/test/java/feign/FeignExceptionTest.java +++ b/core/src/test/java/feign/FeignExceptionTest.java @@ -39,7 +39,8 @@ void canCreateWithRequestAndResponse() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - Request.Body.of("data".getBytes(StandardCharsets.UTF_8)), + "data".getBytes(StandardCharsets.UTF_8), + StandardCharsets.UTF_8, null); Response response = @@ -51,7 +52,7 @@ void canCreateWithRequestAndResponse() { FeignException exception = FeignException.errorReading(request, response, new IOException("socket closed")); - assertThat(exception.responseBody()).isEmpty(); + assertThat(exception.responseBody()).isNotEmpty(); assertThat(exception.hasRequest()).isTrue(); assertThat(exception.request()).isNotNull(); } @@ -63,12 +64,14 @@ void canCreateWithRequestOnly() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - Request.Body.of("data".getBytes(StandardCharsets.UTF_8)), + "data".getBytes(StandardCharsets.UTF_8), + StandardCharsets.UTF_8, null); FeignException exception = FeignException.errorExecuting(request, new IOException("connection timeout")); assertThat(exception.responseBody()).isEmpty(); + assertThat(exception.content()).isNullOrEmpty(); assertThat(exception.hasRequest()).isTrue(); assertThat(exception.request()).isNotNull(); } @@ -87,7 +90,8 @@ void createFeignExceptionWithCorrectCharsetResponse() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - Request.Body.of("data".getBytes(StandardCharsets.UTF_16BE)), + "data".getBytes(StandardCharsets.UTF_16BE), + StandardCharsets.UTF_16BE, null); Response response = @@ -123,7 +127,8 @@ void createFeignExceptionWithCorrectCharsetResponseButDifferentContentTypeFormat Request.HttpMethod.GET, "/home", Collections.emptyMap(), - Request.Body.of("data".getBytes(StandardCharsets.UTF_16BE)), + "data".getBytes(StandardCharsets.UTF_16BE), + StandardCharsets.UTF_16BE, null); Response response = @@ -153,7 +158,8 @@ void createFeignExceptionWithErrorCharsetResponse() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - Request.Body.of("data".getBytes(StandardCharsets.UTF_16BE)), + "data".getBytes(StandardCharsets.UTF_16BE), + StandardCharsets.UTF_16BE, null); Response response = @@ -176,7 +182,8 @@ void canGetResponseHeadersFromException() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - Request.Body.of("data".getBytes(StandardCharsets.UTF_8)), + "data".getBytes(StandardCharsets.UTF_8), + StandardCharsets.UTF_8, null); Map> responseHeaders = new HashMap<>(); @@ -234,7 +241,8 @@ void lengthOfBodyExceptionTest() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - Request.Body.of("data".getBytes(StandardCharsets.UTF_8)), + "data".getBytes(StandardCharsets.UTF_8), + StandardCharsets.UTF_8, null); Response response = @@ -265,12 +273,7 @@ void nullRequestShouldThrowNPEwThrowableAndBytes() { NullPointerException.class, () -> new Derived( - 404, - "message", - null, - new Throwable(), - "content".getBytes(StandardCharsets.UTF_8), - Collections.emptyMap())); + 404, "message", null, new Throwable(), new byte[1], Collections.emptyMap())); } @Test @@ -282,13 +285,7 @@ void nullRequestShouldThrowNPE() { void nullRequestShouldThrowNPEwBytes() { assertThrows( NullPointerException.class, - () -> - new Derived( - 404, - "message", - null, - "content".getBytes(StandardCharsets.UTF_8), - Collections.emptyMap())); + () -> new Derived(404, "message", null, new byte[1], Collections.emptyMap())); } static class Derived extends FeignException { diff --git a/core/src/test/java/feign/FeignTest.java b/core/src/test/java/feign/FeignTest.java index 41b3e0e331..47a348bfaf 100755 --- a/core/src/test/java/feign/FeignTest.java +++ b/core/src/test/java/feign/FeignTest.java @@ -19,6 +19,7 @@ import static feign.Util.UTF_8; import static feign.assertj.MockWebServerAssertions.assertThat; import static java.util.Collections.emptyList; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; @@ -606,7 +607,7 @@ void throwsFeignExceptionIncludingBody() { } catch (FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEmpty(); + assertThat(e.contentUTF8()).isEqualTo("Request body"); } } @@ -771,7 +772,7 @@ void whenReturnTypeIsResponseNoErrorHandling() { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); @@ -961,7 +962,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(new HashMap<>()) .build(); } @@ -1491,9 +1492,9 @@ static final class TestInterfaceBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(Request.Body.of(new Gson().toJson(object))); + template.body(new Gson().toJson(object)); } else { - template.body(Request.Body.of(object.toString())); + template.body(object.toString()); } }); diff --git a/core/src/test/java/feign/FeignUnderAsyncTest.java b/core/src/test/java/feign/FeignUnderAsyncTest.java index 0440fad8a6..f18fd5d747 100644 --- a/core/src/test/java/feign/FeignUnderAsyncTest.java +++ b/core/src/test/java/feign/FeignUnderAsyncTest.java @@ -17,6 +17,7 @@ import static feign.Util.UTF_8; import static feign.assertj.MockWebServerAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -492,7 +493,7 @@ void throwsFeignExceptionIncludingBody() { } catch (FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEmpty(); + assertThat(e.contentUTF8()).isEqualTo("Request body"); } } @@ -526,7 +527,7 @@ void whenReturnTypeIsResponseNoErrorHandling() { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); @@ -721,7 +722,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(new HashMap<>()) .build(); } @@ -963,9 +964,9 @@ static final class TestInterfaceBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(Request.Body.of(new Gson().toJson(object))); + template.body(new Gson().toJson(object)); } else { - template.body(Request.Body.of(object.toString())); + template.body(object.toString()); } }); diff --git a/core/src/test/java/feign/JavaLoggerTest.java b/core/src/test/java/feign/JavaLoggerTest.java index 3799d79b4b..f05d839e15 100644 --- a/core/src/test/java/feign/JavaLoggerTest.java +++ b/core/src/test/java/feign/JavaLoggerTest.java @@ -43,7 +43,8 @@ void rebuffersResponseBodyWhenJulLevelIsInfo() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body("{\"error\":\"test\"}", Util.UTF_8) .build(); @@ -68,7 +69,8 @@ void rebuffersResponseBodyWhenJulLevelIsWarning() throws Exception { Response.builder() .status(500) .reason("Internal Server Error") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body("{\"message\":\"error details\"}", Util.UTF_8) .build(); @@ -93,7 +95,8 @@ void responseBodyReadableMultipleTimesForErrorDecoder() throws Exception { .status(400) .reason("Bad Request") .request( - Request.create(HttpMethod.POST, "/api/submit", Collections.emptyMap(), null, null)) + Request.create( + HttpMethod.POST, "/api/submit", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); diff --git a/core/src/test/java/feign/LoggerMethodsTest.java b/core/src/test/java/feign/LoggerMethodsTest.java index 36c8c6a913..bee76be63b 100644 --- a/core/src/test/java/feign/LoggerMethodsTest.java +++ b/core/src/test/java/feign/LoggerMethodsTest.java @@ -36,7 +36,7 @@ protected void log(String configKey, String format, Object... args) {} @Test void responseIsClosedAfterRebuffer() throws IOException { Request request = - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null); + Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, UTF_8, null); Response response = Response.builder() .status(200) diff --git a/core/src/test/java/feign/LoggerRebufferTest.java b/core/src/test/java/feign/LoggerRebufferTest.java index ab1e1f2309..5928a8f255 100644 --- a/core/src/test/java/feign/LoggerRebufferTest.java +++ b/core/src/test/java/feign/LoggerRebufferTest.java @@ -43,7 +43,8 @@ void headersLevelRebuffersResponseBody() throws Exception { .status(404) .reason("Not Found") .request( - Request.create(HttpMethod.GET, "/api/resource", Collections.emptyMap(), null, null)) + Request.create( + HttpMethod.GET, "/api/resource", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); @@ -69,7 +70,8 @@ void basicLevelDoesNotRebufferResponseBody() throws Exception { .status(200) .reason("OK") .request( - Request.create(HttpMethod.GET, "/api/resource", Collections.emptyMap(), null, null)) + Request.create( + HttpMethod.GET, "/api/resource", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); @@ -92,7 +94,8 @@ void fullLevelRebuffersResponseBody() throws Exception { .status(200) .reason("OK") .request( - Request.create(HttpMethod.POST, "/api/create", Collections.emptyMap(), null, null)) + Request.create( + HttpMethod.POST, "/api/create", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); @@ -119,7 +122,8 @@ void noneLevelDoesNotRebufferResponseBody() throws Exception { .status(200) .reason("OK") .request( - Request.create(HttpMethod.GET, "/api/status", Collections.emptyMap(), null, null)) + Request.create( + HttpMethod.GET, "/api/status", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); @@ -142,7 +146,7 @@ void http204DoesNotRebufferEvenAtHeadersLevel() throws Exception { .reason("No Content") .request( Request.create( - HttpMethod.DELETE, "/api/resource/1", Collections.emptyMap(), null, null)) + HttpMethod.DELETE, "/api/resource/1", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body("should be ignored", Util.UTF_8) .build(); @@ -164,7 +168,8 @@ void http205DoesNotRebufferEvenAtHeadersLevel() throws Exception { .status(205) .reason("Reset Content") .request( - Request.create(HttpMethod.POST, "/api/form", Collections.emptyMap(), null, null)) + Request.create( + HttpMethod.POST, "/api/form", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body("should be ignored", Util.UTF_8) .build(); @@ -187,7 +192,7 @@ void nullBodyHandledCorrectlyAtHeadersLevel() throws Exception { .reason("OK") .request( Request.create( - HttpMethod.HEAD, "/api/resource", Collections.emptyMap(), null, null)) + HttpMethod.HEAD, "/api/resource", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body((byte[]) null) .build(); diff --git a/core/src/test/java/feign/RequestTemplateTest.java b/core/src/test/java/feign/RequestTemplateTest.java index 16106c9277..d66b8db289 100644 --- a/core/src/test/java/feign/RequestTemplateTest.java +++ b/core/src/test/java/feign/RequestTemplateTest.java @@ -17,6 +17,7 @@ import static feign.assertj.FeignAssertions.assertThat; import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.MapEntry.entry; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -91,9 +92,11 @@ void resolveTemplateWithParameterizedPathSkipsEncodingSlash() { @Test void resolveTemplateWithBinaryBody() { - byte[] body = new byte[] {7, 3, -3, -7}; RequestTemplate template = - new RequestTemplate().method(HttpMethod.GET).uri("{zoneId}").body(Request.Body.of(body)); + new RequestTemplate() + .method(HttpMethod.GET) + .uri("{zoneId}") + .body(new byte[] {7, 3, -3, -7}, null); template = template.resolve(mapOf("zoneId", "/hostedzone/Z1PA6795UKMFR9")); assertThat(template).hasUrl("/hostedzone/Z1PA6795UKMFR9"); @@ -342,11 +345,7 @@ void resolveTemplateWithBodyTemplateSetsBodyAndContentLength() { .hasHeaders( entry( "Content-Length", - Collections.singletonList( - template - .requestBody() - .map(body -> String.valueOf(body.contentLength())) - .orElse("0")))); + Collections.singletonList(String.valueOf(template.body().length)))); } @Test diff --git a/core/src/test/java/feign/ResponseTest.java b/core/src/test/java/feign/ResponseTest.java index 5a7020f0ff..9af1ceb887 100644 --- a/core/src/test/java/feign/ResponseTest.java +++ b/core/src/test/java/feign/ResponseTest.java @@ -36,7 +36,8 @@ void reasonPhraseIsOptional() { Response.builder() .status(200) .headers(Collections.>emptyMap()) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); @@ -53,7 +54,8 @@ void canAccessHeadersCaseInsensitively() { Response.builder() .status(200) .headers(headersMap) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); assertThat(response.headers()) @@ -78,7 +80,8 @@ void charsetSupportsMediaTypesWithQuotedCharset() { Response.builder() .status(200) .headers(headersMap) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); assertThat(response.charset()).isEqualTo(Util.UTF_8); @@ -94,7 +97,8 @@ void headerValuesWithSameNameOnlyVaryingInCaseAreMerged() { Response.builder() .status(200) .headers(headersMap) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); @@ -111,7 +115,8 @@ void headersAreOptional() { Response response = Response.builder() .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); assertThat(response.headers()).isNotNull().isEmpty(); @@ -122,7 +127,8 @@ void support1xxStatusCodes() { Response response = Response.builder() .status(103) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body((Response.Body) null) .build(); @@ -139,7 +145,7 @@ void statusCodesOfAnyValueAreAllowed() { .status(statusCode) .request( Request.create( - HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body((Response.Body) null) .build(); @@ -152,7 +158,8 @@ void protocolVersionDefaultsToHttp1_1() { Response response = Response.builder() .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .protocolVersion(null) .body(new byte[0]) .build(); diff --git a/core/src/test/java/feign/RetryableExceptionTest.java b/core/src/test/java/feign/RetryableExceptionTest.java index 90fc028eb9..0bd9a73127 100644 --- a/core/src/test/java/feign/RetryableExceptionTest.java +++ b/core/src/test/java/feign/RetryableExceptionTest.java @@ -33,7 +33,7 @@ void createRetryableExceptionWithResponseAndResponseHeader() { // given Long retryAfter = 5000L; Request request = - Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, null); + Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8); byte[] response = "response".getBytes(StandardCharsets.UTF_8); Map> responseHeader = new HashMap<>(); responseHeader.put("TEST_HEADER", Arrays.asList("TEST_CONTENT")); @@ -56,7 +56,7 @@ void createRetryableExceptionWithMethodKey() { Long retryAfter = 5000L; String methodKey = "TestClient#testMethod()"; Request request = - Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, null); + Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8); Throwable cause = new RuntimeException("test cause"); // when @@ -81,7 +81,7 @@ void createRetryableExceptionWithMethodKey() { void methodKeyIsNullWhenNotProvided() { // given Request request = - Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, null); + Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8); // when RetryableException retryableException = diff --git a/core/src/test/java/feign/RetryerTest.java b/core/src/test/java/feign/RetryerTest.java index d2656b8686..74ed8e832b 100644 --- a/core/src/test/java/feign/RetryerTest.java +++ b/core/src/test/java/feign/RetryerTest.java @@ -26,7 +26,7 @@ class RetryerTest { private static final Request REQUEST = - Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, null); + Request.create(Request.HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8); @Test void only5TriesAllowedAndExponentialBackoff() { diff --git a/core/src/test/java/feign/TargetTest.java b/core/src/test/java/feign/TargetTest.java index 73e9fb5e92..024a9514f5 100644 --- a/core/src/test/java/feign/TargetTest.java +++ b/core/src/test/java/feign/TargetTest.java @@ -66,8 +66,8 @@ public Request apply(RequestTemplate input) { urlEncoded.httpMethod(), urlEncoded.url().replace("%2F", "/"), urlEncoded.headers(), - urlEncoded.body().orElse(null), - null); + urlEncoded.body(), + urlEncoded.charset()); } }; diff --git a/core/src/test/java/feign/assertj/RequestTemplateAssert.java b/core/src/test/java/feign/assertj/RequestTemplateAssert.java index d3ccb7a7b9..0a571ebb36 100644 --- a/core/src/test/java/feign/assertj/RequestTemplateAssert.java +++ b/core/src/test/java/feign/assertj/RequestTemplateAssert.java @@ -15,11 +15,9 @@ */ package feign.assertj; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static feign.Util.UTF_8; -import feign.Request; import feign.RequestTemplate; -import java.nio.charset.StandardCharsets; import org.assertj.core.api.AbstractAssert; import org.assertj.core.data.MapEntry; import org.assertj.core.internal.ByteArrays; @@ -60,8 +58,7 @@ public RequestTemplateAssert hasBody(String utf8Expected) { if (actual.bodyTemplate() != null) { failWithMessage("\nExpecting bodyTemplate to be null, but was:<%s>", actual.bodyTemplate()); } - objects.assertEqual( - info, actual.requestBody().map(this::bodyAsUtf8String).orElse(null), utf8Expected); + objects.assertEqual(info, new String(actual.body(), UTF_8), utf8Expected); return this; } @@ -70,13 +67,13 @@ public RequestTemplateAssert hasBody(byte[] expected) { if (actual.bodyTemplate() != null) { failWithMessage("\nExpecting bodyTemplate to be null, but was:<%s>", actual.bodyTemplate()); } - arrays.assertContains(info, actual.requestBody().map(this::bodyAsBytes).orElse(null), expected); + arrays.assertContains(info, actual.body(), expected); return this; } public RequestTemplateAssert hasBodyTemplate(String expected) { isNotNull(); - if (actual.requestBody().isPresent()) { + if (actual.body() != null) { failWithMessage("\nExpecting body to be null, but was:<%s>", actual.bodyTemplate()); } objects.assertEqual(info, actual.bodyTemplate(), expected); @@ -102,24 +99,17 @@ public RequestTemplateAssert hasNoHeader(final String encoded) { public RequestTemplateAssert noRequestBody() { isNotNull(); - if (actual.requestBody().isPresent()) { + if (actual.body() != null) { if (actual.bodyTemplate() != null) { failWithMessage( "\nExpecting requestBody.bodyTemplate to be null, but was:<%s>", actual.bodyTemplate()); } - if (actual.requestBody().isPresent()) { + if (actual.body() != null) { failWithMessage( - "\nExpecting requestBody.data to be null, but was:<%s>", actual.requestBody().get()); + "\nExpecting requestBody.data to be null, but was:<%s>", + new String(actual.body(), actual.requestCharset())); } } return this; } - - private String bodyAsUtf8String(Request.Body body) { - return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); - } - - private byte[] bodyAsBytes(Request.Body body) { - return assertDoesNotThrow(body::writeToByteArray); - } } diff --git a/core/src/test/java/feign/codec/DefaultDecoderTest.java b/core/src/test/java/feign/codec/DefaultDecoderTest.java index f1856c2946..23ba1d4d06 100644 --- a/core/src/test/java/feign/codec/DefaultDecoderTest.java +++ b/core/src/test/java/feign/codec/DefaultDecoderTest.java @@ -22,6 +22,7 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; +import feign.Util; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Collection; @@ -73,7 +74,7 @@ private Response knownResponse() { .status(200) .reason("OK") .headers(headers) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(inputStream, content.length()) .build(); } @@ -83,7 +84,7 @@ private Response nullBodyResponse() { .status(200) .reason("OK") .headers(Collections.>emptyMap()) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .build(); } } diff --git a/core/src/test/java/feign/codec/DefaultEncoderTest.java b/core/src/test/java/feign/codec/DefaultEncoderTest.java index 94f5183229..9aecbb9059 100644 --- a/core/src/test/java/feign/codec/DefaultEncoderTest.java +++ b/core/src/test/java/feign/codec/DefaultEncoderTest.java @@ -15,15 +15,13 @@ */ package feign.codec; +import static feign.Util.UTF_8; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; -import feign.Request; import feign.RequestTemplate; -import java.nio.charset.StandardCharsets; import java.time.Clock; -import java.util.Optional; +import java.util.Arrays; import org.junit.jupiter.api.Test; class DefaultEncoderTest { @@ -35,11 +33,7 @@ void encodesStrings() throws Exception { String content = "This is my content"; RequestTemplate template = new RequestTemplate(); encoder.encode(content, String.class, template); - Optional optionalBody = template.requestBody(); - assertThat(optionalBody).isPresent(); - String body = - assertDoesNotThrow(() -> optionalBody.get().writeToString(StandardCharsets.UTF_8)); - assertThat(body).contains(content); + assertThat(new String(template.body(), UTF_8)).isEqualTo(content); } @Test @@ -47,10 +41,7 @@ void encodesByteArray() throws Exception { byte[] content = {12, 34, 56}; RequestTemplate template = new RequestTemplate(); encoder.encode(content, byte[].class, template); - Optional optionalBody = template.requestBody(); - assertThat(optionalBody).isPresent(); - byte[] body = assertDoesNotThrow(() -> optionalBody.get().writeToByteArray()); - assertThat(body).isEqualTo(content); + assertThat(Arrays.equals(content, template.body())).isTrue(); } @Test diff --git a/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java b/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java index 0d546b1cd7..c9dae156bd 100644 --- a/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java +++ b/core/src/test/java/feign/codec/DefaultErrorDecoderHttpErrorTest.java @@ -141,7 +141,11 @@ void exceptionIsHttpSpecific(int httpStatus, Class expectedExceptionClass, Strin .reason("anything") .request( Request.create( - HttpMethod.GET, "http://example.com/api", Collections.emptyMap(), null, null)) + HttpMethod.GET, + "http://example.com/api", + Collections.emptyMap(), + null, + Util.UTF_8)) .headers(headers) .body("response body", Util.UTF_8) .build(); diff --git a/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java b/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java index 6088ea54b1..1967e77632 100644 --- a/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java +++ b/core/src/test/java/feign/codec/DefaultErrorDecoderTest.java @@ -26,7 +26,6 @@ import feign.Util; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -48,7 +47,8 @@ void throwsFeignException() throws Throwable { Response.builder() .status(500) .reason("Internal server error") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(headers) .build(); @@ -63,7 +63,8 @@ void throwsFeignExceptionIncludingBody() throws Throwable { Response.builder() .status(500) .reason("Internal server error") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(headers) .body("hello world", UTF_8) .build(); @@ -85,7 +86,8 @@ void throwsFeignExceptionIncludingLongBody() throws Throwable { Response.builder() .status(500) .reason("Internal server error") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(headers) .body(actualBody, UTF_8) .build(); @@ -117,7 +119,8 @@ void feignExceptionIncludesStatus() { Response.builder() .status(400) .reason("Bad request") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(headers) .build(); @@ -135,7 +138,8 @@ void retryAfterHeaderThrowsRetryableException() throws Throwable { Response.builder() .status(503) .reason("Service Unavailable") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(headers) .build(); @@ -190,7 +194,8 @@ private Response bigBodyResponse() { Request.HttpMethod.GET, "/home", Collections.emptyMap(), - Request.Body.of("data".getBytes(StandardCharsets.UTF_8)), + "data".getBytes(Util.UTF_8), + Util.UTF_8, null)) .body(content, Util.UTF_8) .build(); diff --git a/core/src/test/java/feign/stream/StreamDecoderTest.java b/core/src/test/java/feign/stream/StreamDecoderTest.java index 86a6d8509e..d514dcc6b7 100644 --- a/core/src/test/java/feign/stream/StreamDecoderTest.java +++ b/core/src/test/java/feign/stream/StreamDecoderTest.java @@ -24,6 +24,7 @@ import feign.Request.HttpMethod; import feign.RequestLine; import feign.Response; +import feign.Util; import java.io.BufferedReader; import java.io.Closeable; import java.io.IOException; @@ -137,7 +138,8 @@ void shouldCloseIteratorWhenStreamClosed() throws IOException { .status(200) .reason("OK") .headers(Collections.emptyMap()) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body("", UTF_8) .build(); diff --git a/dropwizard-metrics4/src/main/java/feign/metrics4/MeteredEncoder.java b/dropwizard-metrics4/src/main/java/feign/metrics4/MeteredEncoder.java index 4263d14d51..2a2c644c5f 100644 --- a/dropwizard-metrics4/src/main/java/feign/metrics4/MeteredEncoder.java +++ b/dropwizard-metrics4/src/main/java/feign/metrics4/MeteredEncoder.java @@ -50,15 +50,13 @@ public void encode(Object object, Type bodyType, RequestTemplate template) encoder.encode(object, bodyType, template); } - template - .requestBody() - .ifPresent( - body -> - metricRegistry - .histogram( - metricName.metricName( - template.methodMetadata(), template.feignTarget(), "request_size"), - metricSuppliers.histograms()) - .update(body.contentLength())); + if (template.body() != null) { + metricRegistry + .histogram( + metricName.metricName( + template.methodMetadata(), template.feignTarget(), "request_size"), + metricSuppliers.histograms()) + .update(template.body().length); + } } } diff --git a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java index 09f3058be4..77cc7b78cb 100644 --- a/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java +++ b/dropwizard-metrics5/src/main/java/feign/metrics5/MeteredEncoder.java @@ -62,15 +62,13 @@ public void encode(Object object, Type bodyType, RequestTemplate template) encoder.encode(object, bodyType, template); } - template - .requestBody() - .ifPresent( - body -> - metricRegistry - .histogram( - metricName.metricName( - template.methodMetadata(), template.feignTarget(), "request_size"), - metricSuppliers.histograms()) - .update(body.contentLength())); + if (template.body() != null) { + metricRegistry + .histogram( + metricName.metricName( + template.methodMetadata(), template.feignTarget(), "request_size"), + metricSuppliers.histograms()) + .update(template.body().length); + } } } diff --git a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java index 7e79af331a..06a98e8dd2 100644 --- a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java +++ b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java @@ -17,8 +17,8 @@ import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONWriter; -import feign.Request; import feign.RequestTemplate; +import feign.Util; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.JsonEncoder; @@ -42,6 +42,6 @@ public Fastjson2Encoder(JSONWriter.Feature[] features) { @Override public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { - template.body(Request.Body.of(JSON.toJSONBytes(object, features))); + template.body(JSON.toJSONBytes(object, features), Util.UTF_8); } } diff --git a/fastjson2/src/test/java/feign/fastjson2/FastJsonCodecTest.java b/fastjson2/src/test/java/feign/fastjson2/FastJsonCodecTest.java index 06c00502d5..606ccf2511 100644 --- a/fastjson2/src/test/java/feign/fastjson2/FastJsonCodecTest.java +++ b/fastjson2/src/test/java/feign/fastjson2/FastJsonCodecTest.java @@ -22,6 +22,7 @@ import feign.Request; import feign.RequestTemplate; import feign.Response; +import feign.Util; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -106,7 +107,8 @@ void decodes() throws Exception { .status(200) .reason("OK") .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -122,7 +124,8 @@ void nullBodyDecodesToNull() throws Exception { .status(204) .reason("OK") .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat(new Fastjson2Decoder().decode(response, String.class)).isNull(); @@ -135,7 +138,8 @@ void emptyBodyDecodesToNull() throws Exception { .status(204) .reason("OK") .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -154,7 +158,8 @@ void decoderCharset() throws IOException { .status(200) .reason("OK") .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(headers) .body( new String( @@ -200,7 +205,8 @@ void notFoundDecodesToEmpty() throws Exception { .status(404) .reason("NOT FOUND") .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new Fastjson2Decoder().decode(response, byte[].class)).isEmpty(); diff --git a/form/src/main/java/feign/form/MultipartFormContentProcessor.java b/form/src/main/java/feign/form/MultipartFormContentProcessor.java index d8c6e9228f..af31d36eb6 100644 --- a/form/src/main/java/feign/form/MultipartFormContentProcessor.java +++ b/form/src/main/java/feign/form/MultipartFormContentProcessor.java @@ -18,7 +18,6 @@ import static feign.form.ContentType.MULTIPART; import static lombok.AccessLevel.PRIVATE; -import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -104,7 +103,7 @@ public void process(RequestTemplate template, Charset charset, MapemptyList()); // reset header template.header(CONTENT_TYPE_HEADER, contentTypeValue); - template.body(Request.Body.of(bytes)); + template.body(bytes, charset); } @Override diff --git a/form/src/main/java/feign/form/multipart/DelegateWriter.java b/form/src/main/java/feign/form/multipart/DelegateWriter.java index 3295741e4e..7161c21a46 100644 --- a/form/src/main/java/feign/form/multipart/DelegateWriter.java +++ b/form/src/main/java/feign/form/multipart/DelegateWriter.java @@ -17,12 +17,9 @@ import static lombok.AccessLevel.PRIVATE; -import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; -import java.io.IOException; -import java.nio.charset.StandardCharsets; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import lombok.val; @@ -49,15 +46,8 @@ public boolean isApplicable(Object value) { protected void write(Output output, String key, Object value) throws EncodeException { val fake = new RequestTemplate(); delegate.encode(value, value.getClass(), fake); - fake.requestBody().ifPresent(body -> write(output, key, body)); - } - - private void write(Output output, String key, Request.Body body) { - try { - val encoded = body.writeToString(StandardCharsets.UTF_8).replaceAll("\n", ""); - parameterWriter.write(output, key, encoded); - } catch (IOException e) { - throw new EncodeException("Failed to write request body for key: " + key, e); - } + val bytes = fake.body(); + val string = new String(bytes, output.getCharset()).replaceAll("\n", ""); + parameterWriter.write(output, key, string); } } diff --git a/googlehttpclient/src/main/java/feign/googlehttpclient/GoogleHttpClient.java b/googlehttpclient/src/main/java/feign/googlehttpclient/GoogleHttpClient.java index 65aa8f1180..a57101a89c 100644 --- a/googlehttpclient/src/main/java/feign/googlehttpclient/GoogleHttpClient.java +++ b/googlehttpclient/src/main/java/feign/googlehttpclient/GoogleHttpClient.java @@ -15,6 +15,7 @@ */ package feign.googlehttpclient; +import com.google.api.client.http.ByteArrayContent; import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpContent; import com.google.api.client.http.HttpHeaders; @@ -27,7 +28,6 @@ import feign.Request; import feign.Response; import java.io.IOException; -import java.io.OutputStream; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -66,7 +66,18 @@ public final Response execute(final Request inputRequest, final Request.Options private final HttpRequest convertRequest( final Request inputRequest, final Request.Options options) throws IOException { - final HttpContent content = toHttpContent(inputRequest); + // Setup the request body + HttpContent content = null; + if (inputRequest.length() > 0) { + final Collection contentTypeValues = inputRequest.headers().get("Content-Type"); + String contentType = null; + if (contentTypeValues != null && contentTypeValues.size() > 0) { + contentType = contentTypeValues.iterator().next(); + } else { + contentType = "application/octet-stream"; + } + content = new ByteArrayContent(contentType, inputRequest.body()); + } // Build the request final HttpRequest request = @@ -97,21 +108,6 @@ private final HttpRequest convertRequest( return request; } - private HttpContent toHttpContent(final Request inputRequest) { - if (!inputRequest.httpMethod().isWithBody() || !inputRequest.body().isPresent()) { - return null; - } - - final Request.Body requestBody = inputRequest.body().get(); - final Collection contentTypeValues = inputRequest.headers().get("Content-Type"); - final String contentType = - contentTypeValues != null && !contentTypeValues.isEmpty() - ? contentTypeValues.stream().findFirst().get() - : "application/octet-stream"; - - return new FeignBodyContent(requestBody, contentType); - } - private final Response convertResponse( final Request inputRequest, final HttpResponse inputResponse) throws IOException { final HttpHeaders headers = inputResponse.getHeaders(); @@ -135,34 +131,4 @@ private final Map> toMap(final HttpHeaders headers) { } return map; } - - private static final class FeignBodyContent implements HttpContent { - private final Request.Body body; - private final String contentType; - - private FeignBodyContent(Request.Body body, String contentType) { - this.body = body; - this.contentType = contentType; - } - - @Override - public long getLength() { - return body.contentLength(); - } - - @Override - public String getType() { - return contentType; - } - - @Override - public boolean retrySupported() { - return body.isRepeatable(); - } - - @Override - public void writeTo(OutputStream outputStream) throws IOException { - body.writeTo(outputStream); - } - } } diff --git a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java index 78d8d25efe..4486a239f4 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlDecoder.java +++ b/graphql/src/main/java/feign/graphql/GraphqlDecoder.java @@ -16,7 +16,6 @@ package feign.graphql; import feign.Experimental; -import feign.Request; import feign.Response; import feign.Util; import feign.codec.Decoder; @@ -112,14 +111,14 @@ private String resolveOperationField(Map root, Response response } } - if (response.request() != null && response.request().body().isPresent()) { + if (response.request() != null && response.request().body() != null) { try { var fakeResponse = Response.builder() .status(200) .headers(Collections.emptyMap()) .request(response.request()) - .body(bodyAsByteArray(response.request())) + .body(response.request().body()) .build(); var requestBody = (Map) jsonDecoder.decode(fakeResponse, Map.class); if (requestBody != null) { @@ -136,12 +135,6 @@ private String resolveOperationField(Map root, Response response return "unknown"; } - private byte[] bodyAsByteArray(Request request) throws IOException { - var body = request.body(); - - return body.isPresent() ? body.get().writeToByteArray() : null; - } - private boolean isOptionalType(Type type) { if (type instanceof ParameterizedType pt && pt.getRawType() instanceof Class cls) { return cls == Optional.class; diff --git a/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java b/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java index 5a318958ca..252834fc3d 100644 --- a/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java +++ b/graphql/src/main/java/feign/graphql/GraphqlRequestInterceptor.java @@ -34,7 +34,7 @@ public GraphqlRequestInterceptor(Encoder delegate, GraphqlContract contract) { @Override public void apply(RequestTemplate template) { - if (template.requestBody().isPresent()) { + if (template.body() != null) { return; } diff --git a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java index 13d92f3aac..b796a68612 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlDecoderTest.java @@ -332,7 +332,11 @@ private Response buildResponse(String body) { private Request buildRequest() { return Request.create( - HttpMethod.POST, "http://localhost/graphql", Collections.emptyMap(), null, null); + HttpMethod.POST, + "http://localhost/graphql", + Collections.emptyMap(), + Request.Body.empty(), + null); } private static ParameterizedType optionalOf(Type inner) { diff --git a/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java b/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java index 21444de39a..07a22ed8a9 100644 --- a/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java +++ b/graphql/src/test/java/feign/graphql/GraphqlEncoderTest.java @@ -16,13 +16,10 @@ package feign.graphql; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import com.fasterxml.jackson.databind.ObjectMapper; -import feign.Request; import feign.RequestTemplate; import feign.jackson.JacksonEncoder; -import java.nio.charset.StandardCharsets; import java.util.Map; import org.junit.jupiter.api.Test; @@ -54,29 +51,13 @@ private RequestTemplate templateFor(Class apiClass) { return template; } - private byte[] bodyAsByteArray(Request.Body body) { - return assertDoesNotThrow(body::writeToByteArray); - } - - private String bodyAsUtf8String(Request.Body body) { - return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); - } - - private byte[] requestBodyBytes(RequestTemplate template) { - return template.requestBody().map(this::bodyAsByteArray).orElse(null); - } - - private String requestBodyString(RequestTemplate template) { - return template.requestBody().map(this::bodyAsUtf8String).orElse(null); - } - @Test void encodesBodyWithVariables() throws Exception { var template = templateFor(MutationApi.class); var body = Map.of("name", "John", "email", "john@example.com"); encoder.encode(body, Map.class, template); - var result = mapper.readTree(requestBodyBytes(template)); + var result = mapper.readTree(template.body()); assertThat(result.has("query")).isTrue(); assertThat(result.get("query").asText()).contains("createUser"); assertThat(result.has("variables")).isTrue(); @@ -88,7 +69,7 @@ void encodesBodyWithVariables() throws Exception { void delegatesToWrappedEncoderForNonGraphql() { var template = new RequestTemplate(); encoder.encode("plain body", String.class, template); - assertThat(template.requestBody()).isNotEmpty(); + assertThat(template.body()).isNotNull(); } @Test @@ -96,7 +77,7 @@ void interceptorSetsBodyForNoVariableQuery() throws Exception { var template = templateFor(NoVariableApi.class); interceptor.apply(template); - var result = mapper.readTree(requestBodyBytes(template)); + var result = mapper.readTree(template.body()); assertThat(result.get("query").asText()).contains("pending"); assertThat(result.has("variables")).isFalse(); } @@ -104,16 +85,16 @@ void interceptorSetsBodyForNoVariableQuery() throws Exception { @Test void interceptorSkipsWhenBodyAlreadySet() { var template = templateFor(MutationApi.class); - template.body(Request.Body.of("already set")); + template.body("already set"); interceptor.apply(template); - assertThat(requestBodyString(template)).isEqualTo("already set"); + assertThat(new String(template.body())).isEqualTo("already set"); } @Test void interceptorSkipsForNonGraphql() { var template = new RequestTemplate(); - template.body(Request.Body.of("some body")); + template.body("some body"); interceptor.apply(template); - assertThat(requestBodyString(template)).isEqualTo("some body"); + assertThat(new String(template.body())).isEqualTo("some body"); } } diff --git a/gson/src/main/java/feign/gson/GsonEncoder.java b/gson/src/main/java/feign/gson/GsonEncoder.java index c0c3d0eb2f..c4484bc6eb 100644 --- a/gson/src/main/java/feign/gson/GsonEncoder.java +++ b/gson/src/main/java/feign/gson/GsonEncoder.java @@ -17,7 +17,6 @@ import com.google.gson.Gson; import com.google.gson.TypeAdapter; -import feign.Request; import feign.RequestTemplate; import feign.codec.Encoder; import feign.codec.JsonEncoder; @@ -42,6 +41,6 @@ public GsonEncoder(Gson gson) { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { - template.body(Request.Body.of(gson.toJson(object, bodyType))); + template.body(gson.toJson(object, bodyType)); } } diff --git a/gson/src/test/java/feign/gson/GsonCodecTest.java b/gson/src/test/java/feign/gson/GsonCodecTest.java index f1a99670bb..1ec47b8918 100644 --- a/gson/src/test/java/feign/gson/GsonCodecTest.java +++ b/gson/src/test/java/feign/gson/GsonCodecTest.java @@ -27,6 +27,7 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; +import feign.Util; import java.io.IOException; import java.util.Arrays; import java.util.Collections; @@ -65,7 +66,8 @@ void decodesMapObjectNumericalValuesAsInteger() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body("{\"foo\": 1}", UTF_8) .build(); @@ -129,7 +131,8 @@ void decodes() throws Exception { .status(200) .reason("OK") .headers(Collections.emptyMap()) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(zonesJson, UTF_8) .build(); assertThat(new GsonDecoder().decode(response, new TypeToken>() {}.getType())) @@ -143,7 +146,8 @@ void nullBodyDecodesToNull() throws Exception { .status(204) .reason("OK") .headers(Collections.emptyMap()) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .build(); assertThat(new GsonDecoder().decode(response, String.class)).isNull(); } @@ -155,7 +159,8 @@ void emptyBodyDecodesToNull() throws Exception { .status(204) .reason("OK") .headers(Collections.emptyMap()) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); assertThat(new GsonDecoder().decode(response, String.class)).isNull(); @@ -211,7 +216,8 @@ void customDecoder() throws Exception { .status(200) .reason("OK") .headers(Collections.emptyMap()) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(zonesJson, UTF_8) .build(); assertThat(decoder.decode(response, new TypeToken>() {}.getType())).isEqualTo(zones); @@ -250,7 +256,8 @@ void notFoundDecodesToEmpty() throws Exception { .status(404) .reason("NOT FOUND") .headers(Collections.emptyMap()) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .build(); assertThat((byte[]) new GsonDecoder().decode(response, byte[].class)).isEmpty(); } diff --git a/hc5/src/main/java/feign/hc5/ApacheHttp5Client.java b/hc5/src/main/java/feign/hc5/ApacheHttp5Client.java index daaac3b77a..65edd9e71c 100644 --- a/hc5/src/main/java/feign/hc5/ApacheHttp5Client.java +++ b/hc5/src/main/java/feign/hc5/ApacheHttp5Client.java @@ -49,6 +49,7 @@ import org.apache.hc.core5.http.NameValuePair; import org.apache.hc.core5.http.io.entity.ByteArrayEntity; import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.io.support.ClassicRequestBuilder; import org.apache.hc.core5.net.URIBuilder; import org.apache.hc.core5.net.URLEncodedUtils; @@ -156,8 +157,22 @@ ClassicHttpRequest toClassicHttpRequest(Request request, Request.Options options } // request body - if (request.body().isPresent()) { - HttpEntity entity = new FeignBodyEntity(request.body().get(), getContentType(request)); + // final Body requestBody = request.requestBody(); + byte[] data = request.body(); + if (data != null) { + HttpEntity entity; + if (request.isBinary()) { + entity = new ByteArrayEntity(data, null); + } else { + final ContentType contentType = getContentType(request); + String content; + if (request.charset() != null) { + content = new String(data, request.charset()); + } else { + content = new String(data); + } + entity = new StringEntity(content, contentType); + } if (isGzip) { entity = new GzipCompressingEntity(entity); } @@ -176,6 +191,9 @@ private ContentType getContentType(Request request) { final Collection values = entry.getValue(); if (values != null && !values.isEmpty()) { contentType = ContentType.parse(values.iterator().next()); + if (contentType.getCharset() == null) { + contentType = contentType.withCharset(request.charset()); + } break; } } diff --git a/hc5/src/main/java/feign/hc5/AsyncApacheHttp5Client.java b/hc5/src/main/java/feign/hc5/AsyncApacheHttp5Client.java index 8a1adb5fd8..f51c1c2221 100644 --- a/hc5/src/main/java/feign/hc5/AsyncApacheHttp5Client.java +++ b/hc5/src/main/java/feign/hc5/AsyncApacheHttp5Client.java @@ -17,45 +17,24 @@ import static feign.Util.enumForName; -import feign.AsyncClient; -import feign.Request; +import feign.*; import feign.Request.Options; -import feign.Response; -import feign.Util; +import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; +import java.util.zip.GZIPOutputStream; +import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; -import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer; import org.apache.hc.client5.http.config.Configurable; import org.apache.hc.client5.http.config.RequestConfig; -import org.apache.hc.client5.http.entity.GzipCompressingEntity; import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.impl.async.HttpAsyncClients; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.core5.concurrent.FutureCallback; -import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.Header; -import org.apache.hc.core5.http.HttpEntity; -import org.apache.hc.core5.http.NameValuePair; -import org.apache.hc.core5.http.io.entity.ByteArrayEntity; -import org.apache.hc.core5.http.io.support.ClassicRequestBuilder; -import org.apache.hc.core5.http.nio.support.classic.ClassicToAsyncRequestProducer; import org.apache.hc.core5.io.CloseMode; -import org.apache.hc.core5.net.URIBuilder; -import org.apache.hc.core5.net.URLEncodedUtils; -import org.apache.hc.core5.util.Timeout; /** * This module directs Feign's http requests to Apache's @@ -71,34 +50,14 @@ public final class AsyncApacheHttp5Client implements AsyncClient { - Thread thread = new Thread(runnable, "feign-hc5-async-body-writer"); - thread.setDaemon(true); - return thread; - }); - private final CloseableHttpAsyncClient client; - private final Executor executor; - public AsyncApacheHttp5Client() { this(createStartedClient()); } public AsyncApacheHttp5Client(CloseableHttpAsyncClient client) { - this(client, DEFAULT_EXECUTOR); - } - - public AsyncApacheHttp5Client(CloseableHttpAsyncClient client, Executor executor) { - this.client = Objects.requireNonNull(client, "client must not be null"); - this.executor = Objects.requireNonNull(executor, "executor must not be null"); + this.client = client; } private static CloseableHttpAsyncClient createStartedClient() { @@ -110,15 +69,7 @@ private static CloseableHttpAsyncClient createStartedClient() { @Override public CompletableFuture execute( Request request, Options options, Optional requestContext) { - ClassicHttpRequest httpUriRequest; - try { - httpUriRequest = toClassicHttpRequest(request, options); - } catch (final URISyntaxException e) { - CompletableFuture failedFuture = new CompletableFuture<>(); - failedFuture.completeExceptionally( - new IOException("URL '" + request.url() + "' couldn't be parsed into a URI", e)); - return failedFuture; - } + final SimpleHttpRequest httpUriRequest = toClassicHttpRequest(request, options); final CompletableFuture result = new CompletableFuture<>(); final FutureCallback callback = @@ -139,25 +90,12 @@ public void cancelled() { result.cancel(false); } }; - final ClassicToAsyncRequestProducer requestProducer = - new ClassicToAsyncRequestProducer( - httpUriRequest, Timeout.of(options.connectTimeout(), options.connectTimeoutUnit())); client.execute( - requestProducer, - SimpleResponseConsumer.create(), + httpUriRequest, configureTimeoutsAndRedirection(options, requestContext.orElseGet(HttpClientContext::new)), callback); - executor.execute( - () -> { - try { - requestProducer.blockWaiting().execute(); - } catch (IOException | InterruptedException e) { - result.completeExceptionally(e); - } - }); - return result; } @@ -176,20 +114,9 @@ protected HttpClientContext configureTimeoutsAndRedirection( return context; } - ClassicHttpRequest toClassicHttpRequest(Request request, Request.Options options) - throws URISyntaxException { - final ClassicRequestBuilder requestBuilder = - ClassicRequestBuilder.create(request.httpMethod().name()); - - final URI uri = new URIBuilder(request.url()).build(); - - requestBuilder.setUri(uri.getScheme() + "://" + uri.getAuthority() + uri.getRawPath()); - - // request query params - final List queryParams = URLEncodedUtils.parse(uri, requestBuilder.getCharset()); - for (final NameValuePair queryParam : queryParams) { - requestBuilder.addParameter(queryParam); - } + SimpleHttpRequest toClassicHttpRequest(Request request, Request.Options options) { + final SimpleHttpRequest httpRequest = + new SimpleHttpRequest(request.httpMethod().name(), request.url()); // request headers boolean hasAcceptHeader = false; @@ -215,27 +142,34 @@ ClassicHttpRequest toClassicHttpRequest(Request request, Request.Options options "Deflate Content-Encoding is not supported by feign-hc5"); } } + for (final String headerValue : headerEntry.getValue()) { - requestBuilder.addHeader(headerName, headerValue); + httpRequest.addHeader(headerName, headerValue); } } // some servers choke on the default accept string, so we'll set it to anything if (!hasAcceptHeader) { - requestBuilder.addHeader(ACCEPT_HEADER_NAME, "*/*"); + httpRequest.addHeader(ACCEPT_HEADER_NAME, "*/*"); } // request body - if (request.body().isPresent()) { - HttpEntity entity = new FeignBodyEntity(request.body().get(), getContentType(request)); - if (isGzip) { - entity = new GzipCompressingEntity(entity); + // final Body requestBody = request.requestBody(); + byte[] data = request.body(); + if (isGzip && data != null && data.length > 0) { + // compress if needed + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream gzipOs = new GZIPOutputStream(baos, true)) { + gzipOs.write(data); + gzipOs.flush(); + data = baos.toByteArray(); + } catch (IOException suppressed) { // NOPMD } - requestBuilder.setEntity(entity); - } else { - requestBuilder.setEntity(new ByteArrayEntity(new byte[0], null)); + } + if (data != null) { + httpRequest.setBody(data, getContentType(request)); } - return requestBuilder.build(); + return httpRequest; } private ContentType getContentType(Request request) { @@ -245,6 +179,9 @@ private ContentType getContentType(Request request) { final Collection values = entry.getValue(); if (values != null && !values.isEmpty()) { contentType = ContentType.parse(values.iterator().next()); + if (contentType.getCharset() == null) { + contentType = contentType.withCharset(request.charset()); + } break; } } diff --git a/hc5/src/main/java/feign/hc5/FeignBodyEntity.java b/hc5/src/main/java/feign/hc5/FeignBodyEntity.java deleted file mode 100644 index 18504848df..0000000000 --- a/hc5/src/main/java/feign/hc5/FeignBodyEntity.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package feign.hc5; - -import feign.Request; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import org.apache.hc.core5.http.ContentType; -import org.apache.hc.core5.http.io.entity.AbstractHttpEntity; - -/** - * A wrapper for {@link Request.Body} that implements Apache HttpClient's {@link - * AbstractHttpEntity}. - */ -final class FeignBodyEntity extends AbstractHttpEntity { - private final Request.Body body; - - /** - * Creates a new {@link FeignBodyEntity} with the given body and content type. - * - * @param body the body to wrap - * @param contentType the content type of the body - */ - FeignBodyEntity(Request.Body body, ContentType contentType) { - super(contentType, null, body.contentLength() < 0); - this.body = body; - } - - /** - * {@inheritDoc} - * - * @return {@inheritDoc} - */ - @Override - public long getContentLength() { - return body.contentLength(); - } - - /** - * {@inheritDoc} - * - * @return {@inheritDoc} - */ - @Override - public InputStream getContent() { - throw new UnsupportedOperationException("Streaming request body does not expose InputStream"); - } - - /** - * {@inheritDoc} - * - * @param outStream {@inheritDoc} - * @throws {@inheritDoc} - */ - @Override - public void writeTo(OutputStream outStream) throws IOException { - body.writeTo(outStream); - } - - /** - * {@inheritDoc} - * - * @return {@inheritDoc} - */ - @Override - public boolean isRepeatable() { - return body.isRepeatable(); - } - - /** - * {@inheritDoc} - * - * @return {@inheritDoc} - */ - @Override - public boolean isStreaming() { - return !isRepeatable(); - } - - /** Does nothing. The caller is responsible for closing the output stream. */ - @Override - public void close() {} -} diff --git a/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java b/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java index cb33e46dae..6d5902d9c0 100644 --- a/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java +++ b/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java @@ -17,6 +17,7 @@ import static feign.assertj.MockWebServerAssertions.assertThat; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; @@ -534,7 +535,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (final FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEmpty(); + assertThat(e.contentUTF8()).isEqualTo("Request body"); return; } fail(""); @@ -571,7 +572,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); @@ -772,7 +773,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(new HashMap<>()) .build(); } @@ -1083,9 +1084,9 @@ static final class TestInterfaceAsyncBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(Request.Body.of(new Gson().toJson(object))); + template.body(new Gson().toJson(object)); } else { - template.body(Request.Body.of(object.toString())); + template.body(object.toString()); } }); diff --git a/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java b/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java index 45e627bf27..010c229cb7 100644 --- a/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java +++ b/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java @@ -24,7 +24,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.OutputStream; import java.io.Reader; import java.net.URI; import java.net.URISyntaxException; @@ -41,15 +40,12 @@ import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.Configurable; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.client.methods.*; import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.entity.AbstractHttpEntity; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; @@ -138,51 +134,24 @@ HttpUriRequest toHttpUriRequest(Request request, Request.Options options) } // request body - HttpEntity entity = - request - .body() - .map(body -> toHttpEntity(body, getContentType(request))) - .orElseGet(() -> new ByteArrayEntity(new byte[0])); + if (request.body() != null) { + HttpEntity entity = null; + if (request.charset() != null) { + ContentType contentType = getContentType(request); + String content = new String(request.body(), request.charset()); + entity = new StringEntity(content, contentType); + } else { + entity = new ByteArrayEntity(request.body()); + } - requestBuilder.setEntity(entity); + requestBuilder.setEntity(entity); + } else { + requestBuilder.setEntity(new ByteArrayEntity(new byte[0])); + } return requestBuilder.build(); } - private HttpEntity toHttpEntity(Request.Body body, ContentType contentType) { - AbstractHttpEntity httpEntity = - new AbstractHttpEntity() { - @Override - public long getContentLength() { - return body.contentLength(); - } - - @Override - public InputStream getContent() { - throw new UnsupportedOperationException( - "Streaming request body does not expose InputStream"); - } - - @Override - public void writeTo(OutputStream outStream) throws IOException { - body.writeTo(outStream); - } - - @Override - public boolean isRepeatable() { - return body.isRepeatable(); - } - - @Override - public boolean isStreaming() { - return !isRepeatable(); - } - }; - httpEntity.setContentType(contentType != null ? contentType.toString() : null); - httpEntity.setChunked(body.contentLength() < 0); - return httpEntity; - } - private ContentType getContentType(Request request) { ContentType contentType = null; for (Map.Entry> entry : request.headers().entrySet()) @@ -190,6 +159,9 @@ private ContentType getContentType(Request request) { Collection values = entry.getValue(); if (values != null && !values.isEmpty()) { contentType = ContentType.parse(values.iterator().next()); + if (contentType.getCharset() == null) { + contentType = contentType.withCharset(request.charset()); + } break; } } diff --git a/jackson-jaxb/src/main/java/feign/jackson/jaxb/JacksonJaxbJsonEncoder.java b/jackson-jaxb/src/main/java/feign/jackson/jaxb/JacksonJaxbJsonEncoder.java index 6e4caeaede..3786edb36e 100644 --- a/jackson-jaxb/src/main/java/feign/jackson/jaxb/JacksonJaxbJsonEncoder.java +++ b/jackson-jaxb/src/main/java/feign/jackson/jaxb/JacksonJaxbJsonEncoder.java @@ -20,13 +20,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; -import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.Type; +import java.nio.charset.Charset; public final class JacksonJaxbJsonEncoder implements Encoder { private final JacksonJaxbJsonProvider jacksonJaxbJsonProvider; @@ -46,7 +46,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) try { jacksonJaxbJsonProvider.writeTo( object, bodyType.getClass(), null, null, APPLICATION_JSON_TYPE, null, outputStream); - template.body(Request.Body.of(outputStream.toByteArray())); + template.body(outputStream.toByteArray(), Charset.defaultCharset()); } catch (IOException e) { throw new EncodeException(e.getMessage(), e); } diff --git a/jackson-jaxb/src/test/java/feign/jackson/jaxb/JacksonJaxbCodecTest.java b/jackson-jaxb/src/test/java/feign/jackson/jaxb/JacksonJaxbCodecTest.java index 29670826ea..8e0225d192 100644 --- a/jackson-jaxb/src/test/java/feign/jackson/jaxb/JacksonJaxbCodecTest.java +++ b/jackson-jaxb/src/test/java/feign/jackson/jaxb/JacksonJaxbCodecTest.java @@ -23,6 +23,7 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; +import feign.Util; import java.util.Collections; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; @@ -49,7 +50,8 @@ void decodeTest() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body("{\"value\":\"Test\"}", UTF_8) .build(); @@ -65,7 +67,8 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new JacksonJaxbJsonDecoder().decode(response, byte[].class)).isEmpty(); diff --git a/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrEncoder.java b/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrEncoder.java index 26fe78179c..44118eed76 100644 --- a/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrEncoder.java +++ b/jackson-jr/src/main/java/feign/jackson/jr/JacksonJrEncoder.java @@ -17,7 +17,6 @@ import com.fasterxml.jackson.jr.ob.JSON; import com.fasterxml.jackson.jr.ob.JacksonJrExtension; -import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -54,9 +53,9 @@ public JacksonJrEncoder(Iterable iterable) { public void encode(Object object, Type bodyType, RequestTemplate template) { try { if (bodyType == byte[].class) { - template.body(Request.Body.of(mapper.asBytes(object))); + template.body(mapper.asBytes(object), null); } else { - template.body(Request.Body.of(mapper.asString(object))); + template.body(mapper.asString(object)); } } catch (IOException e) { throw new EncodeException(e.getMessage(), e); diff --git a/jackson-jr/src/test/java/feign/jackson/jr/JacksonCodecTest.java b/jackson-jr/src/test/java/feign/jackson/jr/JacksonCodecTest.java index c716bc8194..c7c70bd67b 100644 --- a/jackson-jr/src/test/java/feign/jackson/jr/JacksonCodecTest.java +++ b/jackson-jr/src/test/java/feign/jackson/jr/JacksonCodecTest.java @@ -25,6 +25,7 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; +import feign.Util; import java.io.IOException; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; @@ -95,7 +96,8 @@ void decodes() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -110,7 +112,8 @@ void nullBodyDecodesToEmpty() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new JacksonJrDecoder().decode(response, byte[].class)).isEmpty(); @@ -122,7 +125,8 @@ void emptyBodyDecodesToEmpty() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -141,7 +145,8 @@ void customDecoder() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(DATES_JSON, UTF_8) .build(); @@ -162,7 +167,8 @@ void customDecoderExpressedAsMapper() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(DATES_JSON, UTF_8) .build(); @@ -195,7 +201,8 @@ void decoderCharset() throws IOException { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(headers) .body( new String( @@ -221,7 +228,8 @@ void decodesToMap() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(json, UTF_8) .build(); @@ -299,7 +307,8 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new JacksonJrDecoder().decode(response, byte[].class)).isEmpty(); @@ -339,7 +348,12 @@ static Stream decodeGenericsArguments() { Response.Builder responseBuilder = Response.builder() .request( - Request.create(HttpMethod.GET, "/v1/dummy", Collections.emptyMap(), null, null)); + Request.create( + HttpMethod.GET, + "/v1/dummy", + Collections.emptyMap(), + Request.Body.empty(), + null)); return Stream.of( Arguments.of( responseBuilder.body("{\"data\":2024}", StandardCharsets.UTF_8).build(), diff --git a/jackson/src/main/java/feign/jackson/JacksonEncoder.java b/jackson/src/main/java/feign/jackson/JacksonEncoder.java index 280cd3bb58..48b169a8d3 100644 --- a/jackson/src/main/java/feign/jackson/JacksonEncoder.java +++ b/jackson/src/main/java/feign/jackson/JacksonEncoder.java @@ -21,8 +21,8 @@ import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import feign.Request; import feign.RequestTemplate; +import feign.Util; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.JsonEncoder; @@ -53,7 +53,7 @@ public JacksonEncoder(ObjectMapper mapper) { public void encode(Object object, Type bodyType, RequestTemplate template) { try { JavaType javaType = mapper.getTypeFactory().constructType(bodyType); - template.body(Request.Body.of(mapper.writerFor(javaType).writeValueAsBytes(object))); + template.body(mapper.writerFor(javaType).writeValueAsBytes(object), Util.UTF_8); } catch (JsonProcessingException e) { throw new EncodeException(e.getMessage(), e); } diff --git a/jackson/src/test/java/feign/jackson/JacksonCodecTest.java b/jackson/src/test/java/feign/jackson/JacksonCodecTest.java index 0097e066ee..7de8ec3ad4 100644 --- a/jackson/src/test/java/feign/jackson/JacksonCodecTest.java +++ b/jackson/src/test/java/feign/jackson/JacksonCodecTest.java @@ -32,6 +32,7 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; +import feign.Util; import java.io.Closeable; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -120,7 +121,8 @@ void decodes() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -134,7 +136,8 @@ void nullBodyDecodesToNull() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat(new JacksonDecoder().decode(response, String.class)).isNull(); @@ -146,7 +149,8 @@ void emptyBodyDecodesToNull() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -167,7 +171,8 @@ void customDecoder() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -215,7 +220,8 @@ void decoderCharset() throws IOException { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(headers) .body( new String( @@ -244,7 +250,8 @@ void decodesIterator() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -270,7 +277,8 @@ void nullBodyDecodesToEmptyIterator() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) JacksonIteratorDecoder.create().decode(response, byte[].class)).isEmpty(); @@ -282,7 +290,8 @@ void emptyBodyDecodesToEmptyIterator() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -355,7 +364,8 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new JacksonDecoder().decode(response, byte[].class)).isEmpty(); @@ -368,7 +378,8 @@ void notFoundDecodesToEmptyIterator() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) JacksonIteratorDecoder.create().decode(response, byte[].class)).isEmpty(); diff --git a/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java b/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java index e935b6d0f8..48bc1be058 100644 --- a/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java +++ b/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java @@ -25,6 +25,7 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; +import feign.Util; import feign.codec.DecodeException; import feign.jackson.JacksonIteratorDecoder.JacksonIterator; import java.io.ByteArrayInputStream; @@ -122,7 +123,8 @@ public void close() throws IOException { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(inputStream, jsonBytes.length) .build(); @@ -148,7 +150,8 @@ public void close() throws IOException { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(inputStream, jsonBytes.length) .build(); @@ -178,7 +181,8 @@ JacksonIterator iterator(Class type, String json) throws IOException { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(json, UTF_8) .build(); diff --git a/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java b/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java index 273e6d8f79..90342c0162 100644 --- a/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java +++ b/jackson3/src/main/java/feign/jackson3/Jackson3Encoder.java @@ -16,8 +16,8 @@ package feign.jackson3; import com.fasterxml.jackson.annotation.JsonInclude; -import feign.Request; import feign.RequestTemplate; +import feign.Util; import feign.codec.EncodeException; import feign.codec.Encoder; import feign.codec.JsonEncoder; @@ -55,7 +55,7 @@ public Jackson3Encoder(JsonMapper mapper) { public void encode(Object object, Type bodyType, RequestTemplate template) { try { JavaType javaType = mapper.getTypeFactory().constructType(bodyType); - template.body(Request.Body.of(mapper.writerFor(javaType).writeValueAsBytes(object))); + template.body(mapper.writerFor(javaType).writeValueAsBytes(object), Util.UTF_8); } catch (JacksonException e) { throw new EncodeException(e.getMessage(), e); } diff --git a/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java b/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java index 16236b2c6d..d91683033c 100644 --- a/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java +++ b/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java @@ -23,6 +23,7 @@ import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; +import feign.Util; import java.io.Closeable; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -121,7 +122,8 @@ void decodes() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -135,7 +137,8 @@ void nullBodyDecodesToNull() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat(new Jackson3Decoder().decode(response, String.class)).isNull(); @@ -147,7 +150,8 @@ void emptyBodyDecodesToNull() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -168,7 +172,8 @@ void customDecoder() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -216,7 +221,8 @@ void decoderCharset() throws IOException { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(headers) .body( new String( @@ -245,7 +251,8 @@ void decodesIterator() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(zonesJson, UTF_8) .build(); @@ -271,7 +278,8 @@ void nullBodyDecodesToEmptyIterator() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) Jackson3IteratorDecoder.create().decode(response, byte[].class)).isEmpty(); @@ -283,7 +291,8 @@ void emptyBodyDecodesToEmptyIterator() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(new byte[0]) .build(); @@ -356,7 +365,8 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) new Jackson3Decoder().decode(response, byte[].class)).isEmpty(); @@ -369,7 +379,8 @@ void notFoundDecodesToEmptyIterator() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat((byte[]) Jackson3IteratorDecoder.create().decode(response, byte[].class)).isEmpty(); diff --git a/java11/src/main/java/feign/http2client/Http2Client.java b/java11/src/main/java/feign/http2client/Http2Client.java index f1f4bb49b8..40d4548a22 100644 --- a/java11/src/main/java/feign/http2client/Http2Client.java +++ b/java11/src/main/java/feign/http2client/Http2Client.java @@ -15,10 +15,7 @@ */ package feign.http2client; -import static feign.Util.CONTENT_ENCODING; -import static feign.Util.ENCODING_DEFLATE; -import static feign.Util.ENCODING_GZIP; -import static feign.Util.enumForName; +import static feign.Util.*; import feign.AsyncClient; import feign.Client; @@ -29,9 +26,6 @@ import feign.Util; import java.io.IOException; import java.io.InputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.UncheckedIOException; import java.lang.ref.SoftReference; import java.net.URI; import java.net.URISyntaxException; @@ -58,9 +52,6 @@ import java.util.TreeSet; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.stream.Collectors; import java.util.zip.GZIPInputStream; @@ -68,23 +59,8 @@ public class Http2Client implements Client, AsyncClient { - /** - * Dedicated default executor for the blocking body-writing bridge. Avoids starving the JVM-wide - * {@link java.util.concurrent.ForkJoinPool#commonPool()} when a thread is pinned per in-flight - * request. - */ - private static final Executor DEFAULT_EXECUTOR = - Executors.newCachedThreadPool( - runnable -> { - Thread thread = new Thread(runnable, "feign-http2-body-writer"); - thread.setDaemon(true); - return thread; - }); - private final HttpClient client; - private final Executor executor; - private final Map> clients = new ConcurrentHashMap<>(); /** @@ -107,21 +83,12 @@ public Http2Client() { .build()); } - public Http2Client(HttpClient client) { - this(client, DEFAULT_EXECUTOR); - } - public Http2Client(Options options) { - this(options, DEFAULT_EXECUTOR); + this(newClientBuilder(options).version(Version.HTTP_2).build()); } - public Http2Client(Options options, Executor executor) { - this(newClientBuilder(options).version(Version.HTTP_2).build(), executor); - } - - public Http2Client(HttpClient client, Executor executor) { + public Http2Client(HttpClient client) { this.client = Util.checkNotNull(client, "HttpClient must not be null"); - this.executor = Util.checkNotNull(executor, "Executor must not be null"); } @Override @@ -248,8 +215,13 @@ private static java.net.http.HttpClient.Builder newClientBuilder(Options options private Builder newRequestBuilder(Request request, Options options) throws URISyntaxException { URI uri = new URI(request.url()); - final BodyPublisher body = - request.body().map(this::createBodyPublisher).orElseGet(BodyPublishers::noBody); + final BodyPublisher body; + final byte[] data = request.body(); + if (data == null) { + body = BodyPublishers.noBody(); + } else { + body = BodyPublishers.ofByteArray(data); + } final Builder requestBuilder = HttpRequest.newBuilder() @@ -265,31 +237,6 @@ private Builder newRequestBuilder(Request request, Options options) throws URISy return requestBuilder.method(request.httpMethod().toString(), body); } - private BodyPublisher createBodyPublisher(Request.Body body) { - BodyPublisher publisher = - BodyPublishers.ofInputStream( - () -> { - PropagatingPipedInputStream inputStream = new PropagatingPipedInputStream(); - try { - PipedOutputStream outputStream = new PipedOutputStream(inputStream); - executor.execute( - () -> { - try (outputStream) { - body.writeTo(outputStream); - } catch (IOException e) { - inputStream.setException(e); - } - }); - return inputStream; - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }); - return body.contentLength() > 0 - ? BodyPublishers.fromPublisher(publisher, body.contentLength()) - : publisher; - } - /** * There is a bunch o headers that the http2 client do not allow to be set. * @@ -331,41 +278,4 @@ private String[] asString(Map> headers) { .flatMap(List::stream)) .toArray(String[]::new); } - - /** - * A {@link PipedInputStream} that allows a writer thread to record an {@link IOException} via - * {@link #setException(IOException)} so subsequent reader calls throw an {@link IOException} - * wrapping the original cause; used to propagate write failures from the body-writer thread to - * the HTTP client reader. - */ - private static class PropagatingPipedInputStream extends PipedInputStream { - private final AtomicReference exception = new AtomicReference<>(); - - @Override - public synchronized int read() throws IOException { - checkException(); - int result = super.read(); - checkException(); - return result; - } - - @Override - public synchronized int read(byte[] b, int off, int len) throws IOException { - checkException(); - int result = super.read(b, off, len); - checkException(); - return result; - } - - public void setException(IOException e) { - exception.set(e); - } - - private void checkException() throws IOException { - IOException e = exception.get(); - if (e != null) { - throw new IOException("Body write failed", e); - } - } - } } diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java index d205f51470..0d3cd6570b 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java @@ -16,6 +16,7 @@ package feign.http2client.test; import static feign.assertj.MockWebServerAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; @@ -528,7 +529,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (final FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEmpty(); + assertThat(e.contentUTF8()).isEqualTo("Request body"); return; } fail(""); @@ -565,7 +566,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); @@ -769,7 +770,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(new HashMap<>()) .build(); } @@ -1027,9 +1028,9 @@ static final class TestInterfaceAsyncBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(Request.Body.of(new Gson().toJson(object))); + template.body(new Gson().toJson(object)); } else { - template.body(Request.Body.of(object.toString())); + template.body(object.toString()); } }); diff --git a/jaxb-jakarta/src/main/java/feign/jaxb/JAXBEncoder.java b/jaxb-jakarta/src/main/java/feign/jaxb/JAXBEncoder.java index a25845800b..4ea3b7e998 100644 --- a/jaxb-jakarta/src/main/java/feign/jaxb/JAXBEncoder.java +++ b/jaxb-jakarta/src/main/java/feign/jaxb/JAXBEncoder.java @@ -15,7 +15,6 @@ */ package feign.jaxb; -import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -61,7 +60,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) { Marshaller marshaller = jaxbContextFactory.createMarshaller((Class) bodyType); StringWriter stringWriter = new StringWriter(); marshaller.marshal(object, stringWriter); - template.body(Request.Body.of(stringWriter.toString())); + template.body(stringWriter.toString()); } catch (JAXBException e) { throw new EncodeException(e.toString(), e); } diff --git a/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java b/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java index a4f62453de..d79d3c4725 100644 --- a/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java +++ b/jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java @@ -17,13 +17,14 @@ import static feign.Util.UTF_8; import static feign.assertj.FeignAssertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import feign.Request; import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; +import feign.Util; import feign.codec.DecodeException; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -198,7 +199,8 @@ void decodesXml() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -221,7 +223,8 @@ class ParameterizedHolder { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body("", UTF_8) .build(); @@ -269,9 +272,10 @@ void decodeAnnotatedParameterizedTypes() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) - .body(template.requestBody().map(this::bodyAsBytes).orElse(null)) + .body(template.body()) .build(); new JAXBDecoder(new JAXBContextFactory.Builder().build()).decode(response, Box.class); @@ -284,7 +288,8 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .build(); assertThat( @@ -307,7 +312,8 @@ void decodeThrowsExceptionWhenUnmarshallingFailsWithSetSchema() throws Exception Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -335,7 +341,8 @@ void decodesIgnoringErrorsWithEventHandler() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -386,10 +393,6 @@ void encodesIgnoringErrorsWithEventHandler() throws Exception { """); } - private byte[] bodyAsBytes(Request.Body body) { - return assertDoesNotThrow(body::writeToByteArray); - } - @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) static class MockIntObject { diff --git a/jaxb-jakarta/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java b/jaxb-jakarta/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java index b1f98bd8a2..d355afb691 100644 --- a/jaxb-jakarta/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java +++ b/jaxb-jakarta/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java @@ -16,12 +16,10 @@ package feign.jaxb.examples; import static feign.Util.UTF_8; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.Request; import feign.RequestTemplate; import java.net.URI; -import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.time.Clock; import javax.crypto.Mac; @@ -74,7 +72,8 @@ private static String canonicalString(RequestTemplate input, String host) { canonicalRequest.append("host").append('\n'); // HexEncode(Hash(Payload)) - String bodyText = input.requestBody().map(AWSSignatureVersion4::bodyAsUtf8String).orElse(null); + byte[] data = input.body(); + String bodyText = (data != null) ? new String(data, input.requestCharset()) : null; if (bodyText != null) { canonicalRequest.append(hex(sha256(bodyText))); } else { @@ -83,10 +82,6 @@ private static String canonicalString(RequestTemplate input, String host) { return canonicalRequest.toString(); } - private static String bodyAsUtf8String(Request.Body body) { - return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); - } - private static String toSign(String timestamp, String credentialScope, String canonicalRequest) { StringBuilder toSign = new StringBuilder(); // Algorithm + '\n' + @@ -121,7 +116,7 @@ public Request apply(RequestTemplate input) { if (!input.headers().isEmpty()) { throw new UnsupportedOperationException("headers not supported"); } - if (input.requestBody().isPresent()) { + if (input.body() != null) { throw new UnsupportedOperationException("body not supported"); } diff --git a/jaxb/src/main/java/feign/jaxb/JAXBEncoder.java b/jaxb/src/main/java/feign/jaxb/JAXBEncoder.java index 4c05d82e71..aae439cae6 100644 --- a/jaxb/src/main/java/feign/jaxb/JAXBEncoder.java +++ b/jaxb/src/main/java/feign/jaxb/JAXBEncoder.java @@ -15,7 +15,6 @@ */ package feign.jaxb; -import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -61,7 +60,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) { Marshaller marshaller = jaxbContextFactory.createMarshaller((Class) bodyType); StringWriter stringWriter = new StringWriter(); marshaller.marshal(object, stringWriter); - template.body(Request.Body.of(stringWriter.toString())); + template.body(stringWriter.toString()); } catch (JAXBException e) { throw new EncodeException(e.toString(), e); } diff --git a/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java b/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java index 139615175f..464d857b8c 100644 --- a/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java +++ b/jaxb/src/test/java/feign/jaxb/JAXBCodecTest.java @@ -17,13 +17,14 @@ import static feign.Util.UTF_8; import static feign.assertj.FeignAssertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import feign.Request; import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; +import feign.Util; import feign.codec.DecodeException; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -198,7 +199,8 @@ void decodesXml() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -221,7 +223,8 @@ class ParameterizedHolder { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body("", UTF_8) .build(); @@ -269,9 +272,10 @@ void decodeAnnotatedParameterizedTypes() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) - .body(template.requestBody().map(this::bodyAsBytes).orElse(null)) + .body(template.body()) .build(); new JAXBDecoder(new JAXBContextFactory.Builder().build()).decode(response, Box.class); @@ -284,7 +288,8 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .build(); assertThat( @@ -307,7 +312,8 @@ void decodeThrowsExceptionWhenUnmarshallingFailsWithSetSchema() throws Exception Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -335,7 +341,8 @@ void decodesIgnoringErrorsWithEventHandler() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockXml, UTF_8) .build(); @@ -387,10 +394,6 @@ void encodesIgnoringErrorsWithEventHandler() throws Exception { """); } - private byte[] bodyAsBytes(Request.Body body) { - return assertDoesNotThrow(body::writeToByteArray); - } - @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) static class MockIntObject { diff --git a/jaxb/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java b/jaxb/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java index b1f98bd8a2..d355afb691 100644 --- a/jaxb/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java +++ b/jaxb/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java @@ -16,12 +16,10 @@ package feign.jaxb.examples; import static feign.Util.UTF_8; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.Request; import feign.RequestTemplate; import java.net.URI; -import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.time.Clock; import javax.crypto.Mac; @@ -74,7 +72,8 @@ private static String canonicalString(RequestTemplate input, String host) { canonicalRequest.append("host").append('\n'); // HexEncode(Hash(Payload)) - String bodyText = input.requestBody().map(AWSSignatureVersion4::bodyAsUtf8String).orElse(null); + byte[] data = input.body(); + String bodyText = (data != null) ? new String(data, input.requestCharset()) : null; if (bodyText != null) { canonicalRequest.append(hex(sha256(bodyText))); } else { @@ -83,10 +82,6 @@ private static String canonicalString(RequestTemplate input, String host) { return canonicalRequest.toString(); } - private static String bodyAsUtf8String(Request.Body body) { - return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); - } - private static String toSign(String timestamp, String credentialScope, String canonicalRequest) { StringBuilder toSign = new StringBuilder(); // Algorithm + '\n' + @@ -121,7 +116,7 @@ public Request apply(RequestTemplate input) { if (!input.headers().isEmpty()) { throw new UnsupportedOperationException("headers not supported"); } - if (input.requestBody().isPresent()) { + if (input.body() != null) { throw new UnsupportedOperationException("body not supported"); } diff --git a/jaxrs2/src/main/java/feign/jaxrs2/JAXRSClient.java b/jaxrs2/src/main/java/feign/jaxrs2/JAXRSClient.java index 555012f4b8..5ecdb94511 100644 --- a/jaxrs2/src/main/java/feign/jaxrs2/JAXRSClient.java +++ b/jaxrs2/src/main/java/feign/jaxrs2/JAXRSClient.java @@ -19,6 +19,7 @@ import feign.Request.Options; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.Charset; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; @@ -31,7 +32,7 @@ import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import javax.ws.rs.core.StreamingOutput; +import javax.ws.rs.core.Variant; /** * This module directs Feign's http requests to javax.ws.rs.client.Client . Ex: @@ -76,11 +77,15 @@ public feign.Response execute(feign.Request request, Options options) throws IOE .build(); } - private Entity createRequestEntity(feign.Request request) { - return request - .body() - .map(body -> Entity.entity((StreamingOutput) body::writeTo, mediaType(request.headers()))) - .orElse(null); + private Entity createRequestEntity(feign.Request request) { + if (request.body() == null) { + return null; + } + + return Entity.entity( + request.body(), + new Variant( + mediaType(request.headers()), locale(request.headers()), encoding(request.charset()))); } private Integer integerHeader(Response response, String header) { @@ -97,16 +102,22 @@ private Integer integerHeader(Response response, String header) { } } + private String encoding(Charset charset) { + if (charset == null) return null; + + return charset.name(); + } + private String locale(Map> headers) { if (!headers.containsKey(HttpHeaders.CONTENT_LANGUAGE)) return null; return headers.get(HttpHeaders.CONTENT_LANGUAGE).iterator().next(); } - private String mediaType(Map> headers) { - if (!headers.containsKey(HttpHeaders.CONTENT_TYPE)) return MediaType.APPLICATION_OCTET_STREAM; + private MediaType mediaType(Map> headers) { + if (!headers.containsKey(HttpHeaders.CONTENT_TYPE)) return null; - return headers.get(HttpHeaders.CONTENT_TYPE).iterator().next(); + return MediaType.valueOf(headers.get(HttpHeaders.CONTENT_TYPE).iterator().next()); } private MultivaluedMap toMultivaluedMap(Map> headers) { diff --git a/json/src/main/java/feign/json/JsonEncoder.java b/json/src/main/java/feign/json/JsonEncoder.java index 1ef3cd6fb1..655bb7594a 100644 --- a/json/src/main/java/feign/json/JsonEncoder.java +++ b/json/src/main/java/feign/json/JsonEncoder.java @@ -17,7 +17,6 @@ import static java.lang.String.format; -import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -59,7 +58,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException { if (object == null) return; if (object instanceof JSONArray || object instanceof JSONObject) { - template.body(Request.Body.of(object.toString())); + template.body(object.toString()); } else { throw new EncodeException(format("%s is not a type supported by this encoder.", bodyType)); } diff --git a/json/src/test/java/feign/json/JsonCodecTest.java b/json/src/test/java/feign/json/JsonCodecTest.java index 502b32eb9b..becd040ee5 100644 --- a/json/src/test/java/feign/json/JsonCodecTest.java +++ b/json/src/test/java/feign/json/JsonCodecTest.java @@ -17,7 +17,6 @@ import static feign.Util.toByteArray; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.Feign; import feign.Param; @@ -28,7 +27,6 @@ import feign.mock.MockTarget; import java.io.IOException; import java.io.InputStream; -import java.nio.charset.StandardCharsets; import org.json.JSONArray; import org.json.JSONObject; import org.junit.jupiter.api.BeforeEach; @@ -82,9 +80,8 @@ void encodes() { "{\"login\":\"radio-rogal\",\"contributions\":0}"); JSONObject response = github.create("openfeign", "feign", contributor); Request request = mockClient.verifyOne(HttpMethod.POST, "/repos/openfeign/feign/contributors"); - assertThat(request.body()).isPresent(); - String json = - assertDoesNotThrow(() -> request.body().get().writeToString(StandardCharsets.UTF_8)); + assertThat(request.body()).isNotNull(); + String json = new String(request.body()); assertThat(json).contains("\"login\":\"radio-rogal\""); assertThat(json).contains("\"contributions\":0"); assertThat(response.getString("login")).isEqualTo("radio-rogal"); diff --git a/json/src/test/java/feign/json/JsonDecoderTest.java b/json/src/test/java/feign/json/JsonDecoderTest.java index 4147e3c469..1635aa7f67 100644 --- a/json/src/test/java/feign/json/JsonDecoderTest.java +++ b/json/src/test/java/feign/json/JsonDecoderTest.java @@ -26,6 +26,7 @@ import feign.Response; import feign.codec.DecodeException; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.time.Clock; import java.util.Collections; import org.json.JSONArray; @@ -53,7 +54,8 @@ static void setUpClass() { Request.HttpMethod.GET, "/qwerty", Collections.emptyMap(), - Request.Body.of("xyz"), + "xyz".getBytes(StandardCharsets.UTF_8), + StandardCharsets.UTF_8, null); } diff --git a/json/src/test/java/feign/json/JsonEncoderTest.java b/json/src/test/java/feign/json/JsonEncoderTest.java index d7cb951026..a8d2d1f360 100644 --- a/json/src/test/java/feign/json/JsonEncoderTest.java +++ b/json/src/test/java/feign/json/JsonEncoderTest.java @@ -15,14 +15,12 @@ */ package feign.json; +import static feign.Util.UTF_8; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; -import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; -import java.nio.charset.StandardCharsets; import java.time.Clock; import org.json.JSONArray; import org.json.JSONObject; @@ -51,24 +49,20 @@ void setUp() { void encodesArray() { new JsonEncoder().encode(jsonArray, JSONArray.class, requestTemplate); JSONAssert.assertEquals( - "[{\"a\":\"b\",\"c\":1},123]", - requestTemplate.requestBody().map(this::bodyAsUtf8String).orElse(null), - false); + "[{\"a\":\"b\",\"c\":1},123]", new String(requestTemplate.body(), UTF_8), false); } @Test void encodesObject() { new JsonEncoder().encode(jsonObject, JSONObject.class, requestTemplate); JSONAssert.assertEquals( - "{\"a\":\"b\",\"c\":1}", - requestTemplate.requestBody().map(this::bodyAsUtf8String).orElse(null), - false); + "{\"a\":\"b\",\"c\":1}", new String(requestTemplate.body(), UTF_8), false); } @Test void encodesNull() { new JsonEncoder().encode(null, JSONObject.class, new RequestTemplate()); - assertThat(requestTemplate.requestBody()).isEmpty(); + assertThat(requestTemplate.body()).isNull(); } @Test @@ -80,8 +74,4 @@ void unknownTypeThrowsEncodeException() { assertThat(exception.getMessage()) .isEqualTo("class java.time.Clock is not a type supported by this encoder."); } - - private String bodyAsUtf8String(Request.Body body) { - return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); - } } diff --git a/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt b/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt index 3f02011df5..aa1d25266b 100644 --- a/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt +++ b/kotlin/src/test/kotlin/feign/kotlin/CoroutineFeignTest.kt @@ -19,7 +19,6 @@ import com.google.gson.Gson import com.google.gson.JsonIOException import feign.Param import feign.QueryMapEncoder -import feign.Request import feign.RequestInterceptor import feign.RequestLine import feign.Response @@ -178,9 +177,9 @@ class CoroutineFeignTest { private val delegate = CoroutineFeign.builder() .decoder(DefaultDecoder()).encoder { `object`, bodyType, template -> if (`object` is Map<*, *>) { - template.body(Request.Body.of(Gson().toJson(`object`))) + template.body(Gson().toJson(`object`)) } else { - template.body(Request.Body.of(`object`.toString())) + template.body(`object`.toString()) } } diff --git a/micrometer/src/main/java/feign/micrometer/MeteredEncoder.java b/micrometer/src/main/java/feign/micrometer/MeteredEncoder.java index 784aa86c3b..2fb73d12f5 100644 --- a/micrometer/src/main/java/feign/micrometer/MeteredEncoder.java +++ b/micrometer/src/main/java/feign/micrometer/MeteredEncoder.java @@ -15,19 +15,13 @@ */ package feign.micrometer; -import static feign.Util.CONTENT_LENGTH; import static feign.micrometer.MetricTagResolver.EMPTY_TAGS_ARRAY; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; -import io.micrometer.core.instrument.DistributionSummary; -import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.Tag; -import io.micrometer.core.instrument.Tags; -import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.*; import java.lang.reflect.Type; -import java.util.Collections; /** Wrap feign {@link Encoder} with metrics. */ public class MeteredEncoder implements Encoder { @@ -58,11 +52,9 @@ public void encode(Object object, Type bodyType, RequestTemplate template) createTimer(object, bodyType, template) .record(() -> encoder.encode(object, bodyType, template)); - template.headers().getOrDefault(CONTENT_LENGTH, Collections.emptySet()).stream() - .findFirst() - .ifPresent( - contentLength -> - createSummary(object, bodyType, template).record(Long.parseLong(contentLength))); + if (template.body() != null) { + createSummary(object, bodyType, template).record(template.body().length); + } } protected Timer createTimer(Object object, Type bodyType, RequestTemplate template) { diff --git a/mock/src/main/java/feign/mock/RequestKey.java b/mock/src/main/java/feign/mock/RequestKey.java index 1d572875e3..50ed918e48 100644 --- a/mock/src/main/java/feign/mock/RequestKey.java +++ b/mock/src/main/java/feign/mock/RequestKey.java @@ -18,9 +18,10 @@ import static feign.Util.UTF_8; import feign.Request; -import java.io.IOException; +import feign.Util; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collection; import java.util.Map; @@ -35,6 +36,8 @@ public static class Builder { private RequestHeaders headers; + private Charset charset; + private byte[] body; private Builder(HttpMethod method, String url) { @@ -53,6 +56,11 @@ public Builder headers(RequestHeaders headers) { return this; } + public Builder charset(Charset charset) { + this.charset = charset; + return this; + } + public Builder body(String body) { return body(body.getBytes(UTF_8)); } @@ -77,7 +85,7 @@ public static RequestKey create(Request request) { private static String buildUrl(Request request) { try { - return URLDecoder.decode(request.url(), UTF_8.name()); + return URLDecoder.decode(request.url(), Util.UTF_8.name()); } catch (final UnsupportedEncodingException e) { throw new RuntimeException(e); } @@ -89,12 +97,15 @@ private static String buildUrl(Request request) { private final RequestHeaders headers; + private final Charset charset; + private final byte[] body; private RequestKey(Builder builder) { this.method = builder.method; this.url = builder.url; this.headers = builder.headers; + this.charset = builder.charset; this.body = builder.body; } @@ -102,19 +113,8 @@ private RequestKey(Request request) { this.method = HttpMethod.valueOf(request.httpMethod().name()); this.url = buildUrl(request); this.headers = RequestHeaders.of(request.headers()); - this.body = - request - .body() - .filter(Request.Body::isRepeatable) - .map( - body -> { - try { - return body.writeToByteArray(); - } catch (IOException ignored) { - return null; - } - }) - .orElse(null); + this.charset = request.charset(); + this.body = request.body(); } public HttpMethod getMethod() { @@ -129,6 +129,10 @@ public RequestHeaders getHeaders() { return headers; } + public Charset getCharset() { + return charset; + } + public byte[] getBody() { return body; } @@ -167,8 +171,10 @@ public boolean equalsExtended(Object obj) { RequestKey other = (RequestKey) obj; boolean headersEqual = other.headers == null || headers == null || headers.equals(other.headers); - boolean bodyEqual = other.body == null || body == null || Arrays.equals(body, other.body); - return headersEqual && bodyEqual; + boolean charsetEqual = + other.charset == null || charset == null || charset.equals(other.charset); + boolean bodyEqual = other.body == null || body == null || Arrays.equals(other.body, body); + return headersEqual && charsetEqual && bodyEqual; } return false; } @@ -176,7 +182,10 @@ public boolean equalsExtended(Object obj) { @Override public String toString() { return String.format( - "Request [%s %s: %s headers]", - method, url, headers == null ? "without" : "with " + headers); + "Request [%s %s: %s headers and %s]", + method, + url, + headers == null ? "without" : "with " + headers, + charset == null ? "no charset" : "charset " + charset); } } diff --git a/mock/src/test/java/feign/mock/MockClientTest.java b/mock/src/test/java/feign/mock/MockClientTest.java index 3f14d92d90..77916f4194 100644 --- a/mock/src/test/java/feign/mock/MockClientTest.java +++ b/mock/src/test/java/feign/mock/MockClientTest.java @@ -15,10 +15,10 @@ */ package feign.mock; +import static feign.Util.UTF_8; import static feign.Util.toByteArray; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.Body; import feign.Feign; @@ -36,9 +36,7 @@ import java.io.InputStream; import java.lang.reflect.Type; import java.net.HttpURLConnection; -import java.nio.charset.StandardCharsets; import java.util.List; -import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -99,6 +97,16 @@ public Object decode(Response response, Type type) void setup() throws IOException { try (InputStream input = getClass().getResourceAsStream("/fixtures/contributors.json")) { byte[] data = toByteArray(input); + RequestKey postContributorKey = + RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") + .charset(UTF_8) + .headers( + RequestHeaders.builder() + .add("Content-Length", "55") + .add("Content-Type", "application/json") + .build()) + .body("{\"login\":\"velo_at_github\",\"type\":\"preposterous hacker\"}") + .build(); mockClient = new MockClient(); github = Feign.builder() @@ -111,10 +119,7 @@ void setup() throws IOException { HttpMethod.GET, "/repos/netflix/feign/contributors?client_id=7 7", new ByteArrayInputStream(data)) - .ok( - HttpMethod.POST, - "/repos/netflix/feign/contributors", - "{\"login\":\"velo\",\"contributions\":0}") + .ok(postContributorKey, "{\"login\":\"velo\",\"contributions\":0}") .noContent(HttpMethod.PATCH, "/repos/velo/feign-mock/contributors") .add( HttpMethod.GET, @@ -175,6 +180,16 @@ void paramsEncoding() { @Test void verifyInvocation() { + RequestKey testRequestKey = + RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") + .headers( + RequestHeaders.builder() + .add("Content-Length", "55") + .add("Content-Type", "application/json") + .build()) + .body("{\"login\":\"velo_at_github\",\"type\":\"preposterous hacker\"}") + .build(); + Contributor contribution = github.create("netflix", "feign", "velo_at_github", "preposterous hacker"); // making sure it received a proper response @@ -185,12 +200,14 @@ void verifyInvocation() { List results = mockClient.verifyTimes(HttpMethod.POST, "/repos/netflix/feign/contributors", 1); assertThat(results).hasSize(1); + results = mockClient.verifyTimes(testRequestKey, 1); + assertThat(results).hasSize(1); - Optional body = - mockClient.verifyOne(HttpMethod.POST, "/repos/netflix/feign/contributors").body(); - assertThat(body).isPresent(); + assertThat(mockClient.verifyOne(testRequestKey).body()).isNotNull(); + byte[] body = mockClient.verifyOne(HttpMethod.POST, "/repos/netflix/feign/contributors").body(); + assertThat(body).isNotNull(); - String message = assertDoesNotThrow(() -> body.get().writeToString(StandardCharsets.UTF_8)); + String message = new String(body); assertThat(message).contains("velo_at_github"); assertThat(message).contains("preposterous hacker"); @@ -205,6 +222,7 @@ void verifyNone() { testRequestKey = RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") + .charset(UTF_8) .headers( RequestHeaders.builder() .add("Content-Length", "55") @@ -225,6 +243,7 @@ void verifyNone() { testRequestKey = RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") + .charset(UTF_8) .headers( RequestHeaders.builder() .add("Content-Length", "55") diff --git a/mock/src/test/java/feign/mock/RequestKeyTest.java b/mock/src/test/java/feign/mock/RequestKeyTest.java index 9b03f3c0eb..23d6d75fb2 100644 --- a/mock/src/test/java/feign/mock/RequestKeyTest.java +++ b/mock/src/test/java/feign/mock/RequestKeyTest.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; import feign.Request; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; @@ -32,7 +33,12 @@ class RequestKeyTest { @BeforeEach void setUp() { RequestHeaders headers = RequestHeaders.builder().add("my-header", "val").build(); - requestKey = RequestKey.builder(HttpMethod.GET, "a").headers(headers).body("content").build(); + requestKey = + RequestKey.builder(HttpMethod.GET, "a") + .headers(headers) + .charset(StandardCharsets.UTF_16) + .body("content") + .build(); } @Test @@ -41,6 +47,7 @@ void builder() throws Exception { assertThat(requestKey.getUrl()).isEqualTo("a"); assertThat(requestKey.getHeaders().size()).isEqualTo(1); assertThat(requestKey.getHeaders().fetch("my-header")).isEqualTo(Arrays.asList("val")); + assertThat(requestKey.getCharset()).isEqualTo(StandardCharsets.UTF_16); } @SuppressWarnings("deprecation") @@ -49,13 +56,20 @@ void create() throws Exception { Map> map = new HashMap<>(); map.put("my-header", Arrays.asList("val")); Request request = - Request.create(Request.HttpMethod.GET, "a", map, Request.Body.of("content"), null); + Request.create( + Request.HttpMethod.GET, + "a", + map, + "content".getBytes(StandardCharsets.UTF_8), + StandardCharsets.UTF_16); requestKey = RequestKey.create(request); assertThat(requestKey.getMethod()).isEqualTo(HttpMethod.GET); assertThat(requestKey.getUrl()).isEqualTo("a"); assertThat(requestKey.getHeaders().size()).isEqualTo(1); assertThat(requestKey.getHeaders().fetch("my-header")).isEqualTo(Arrays.asList("val")); + assertThat(requestKey.getCharset()).isEqualTo(StandardCharsets.UTF_16); + assertThat(requestKey.getBody()).isEqualTo("content".getBytes(StandardCharsets.UTF_8)); } @Test @@ -103,7 +117,11 @@ void equalMinimum() { @Test void equalExtra() { RequestHeaders headers = RequestHeaders.builder().add("my-other-header", "other value").build(); - RequestKey requestKey2 = RequestKey.builder(HttpMethod.GET, "a").headers(headers).build(); + RequestKey requestKey2 = + RequestKey.builder(HttpMethod.GET, "a") + .headers(headers) + .charset(StandardCharsets.ISO_8859_1) + .build(); assertThat(requestKey.hashCode()).isEqualTo(requestKey2.hashCode()); assertThat(requestKey).isEqualTo(requestKey2); @@ -120,7 +138,11 @@ void equalsExtended() { @Test void equalsExtendedExtra() { RequestHeaders headers = RequestHeaders.builder().add("my-other-header", "other value").build(); - RequestKey requestKey2 = RequestKey.builder(HttpMethod.GET, "a").headers(headers).build(); + RequestKey requestKey2 = + RequestKey.builder(HttpMethod.GET, "a") + .headers(headers) + .charset(StandardCharsets.ISO_8859_1) + .build(); assertThat(requestKey.hashCode()).isEqualTo(requestKey2.hashCode()); assertThat(requestKey.equalsExtended(requestKey2)).isEqualTo(false); @@ -129,7 +151,7 @@ void equalsExtendedExtra() { @Test void testToString() throws Exception { assertThat(requestKey.toString()).startsWith("Request [GET a: "); - assertThat(requestKey.toString()).contains(" with my-header=[val] "); + assertThat(requestKey.toString()).contains(" with my-header=[val] ", " UTF-16]"); } @Test @@ -137,6 +159,7 @@ void toStringSimple() throws Exception { requestKey = RequestKey.builder(HttpMethod.GET, "a").build(); assertThat(requestKey.toString()).startsWith("Request [GET a: "); - assertThat(requestKey.toString()).contains(" without "); + assertThat(requestKey.toString()).contains(" without ", " no charset"); } } +// diff --git a/moshi/src/main/java/feign/moshi/MoshiEncoder.java b/moshi/src/main/java/feign/moshi/MoshiEncoder.java index fdd7507741..b65f705e27 100644 --- a/moshi/src/main/java/feign/moshi/MoshiEncoder.java +++ b/moshi/src/main/java/feign/moshi/MoshiEncoder.java @@ -17,7 +17,6 @@ import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.Moshi; -import feign.Request; import feign.RequestTemplate; import feign.codec.Encoder; import feign.codec.JsonEncoder; @@ -42,6 +41,6 @@ public MoshiEncoder(Iterable> adapters) { @Override public void encode(Object object, Type bodyType, RequestTemplate template) { JsonAdapter jsonAdapter = moshi.adapter(bodyType).indent(" "); - template.body(Request.Body.of(jsonAdapter.toJson(object))); + template.body(jsonAdapter.toJson(object)); } } diff --git a/moshi/src/test/java/feign/moshi/MoshiDecoderTest.java b/moshi/src/test/java/feign/moshi/MoshiDecoderTest.java index 7aabefc708..885a57b6df 100644 --- a/moshi/src/test/java/feign/moshi/MoshiDecoderTest.java +++ b/moshi/src/test/java/feign/moshi/MoshiDecoderTest.java @@ -22,6 +22,7 @@ import com.squareup.moshi.Moshi; import feign.Request; import feign.Response; +import feign.Util; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; @@ -59,7 +60,8 @@ class Zone extends LinkedHashMap { .reason("OK") .headers(Collections.emptyMap()) .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(zonesJson, UTF_8) .build(); @@ -104,7 +106,8 @@ void nullBodyDecodesToNull() throws Exception { .reason("OK") .headers(Collections.emptyMap()) .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .build(); assertThat(new MoshiDecoder().decode(response, String.class)).isNull(); } @@ -117,7 +120,8 @@ void emptyBodyDecodesToNull() throws Exception { .reason("OK") .headers(Collections.emptyMap()) .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); assertThat(new MoshiDecoder().decode(response, String.class)).isNull(); @@ -132,7 +136,8 @@ void notFoundDecodesToEmpty() throws Exception { .reason("NOT FOUND") .headers(Collections.emptyMap()) .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .build(); assertThat((byte[]) new MoshiDecoder().decode(response, byte[].class)).isEmpty(); } @@ -153,7 +158,8 @@ void customDecoder() throws Exception { .reason("OK") .headers(Collections.emptyMap()) .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(zonesJson, UTF_8) .build(); @@ -175,7 +181,8 @@ void customObjectDecoder() throws Exception { .reason("OK") .headers(Collections.emptyMap()) .request( - Request.create(Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + Request.create( + Request.HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .body(videoGamesJson, UTF_8) .build(); diff --git a/okhttp/src/main/java/feign/okhttp/OkHttpClient.java b/okhttp/src/main/java/feign/okhttp/OkHttpClient.java index ee582ad7a4..25a8b7f1b1 100644 --- a/okhttp/src/main/java/feign/okhttp/OkHttpClient.java +++ b/okhttp/src/main/java/feign/okhttp/OkHttpClient.java @@ -29,15 +29,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Headers; -import okhttp3.MediaType; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import okio.BufferedSink; +import okhttp3.*; /** * This module directs Feign's http requests to @@ -75,6 +67,9 @@ static Request toOkHttpRequest(feign.Request input) { requestBuilder.addHeader(field, value); if (field.equalsIgnoreCase("Content-Type")) { mediaType = MediaType.parse(value); + if (input.charset() != null) { + mediaType.charset(input.charset()); + } } } } @@ -83,40 +78,19 @@ static Request toOkHttpRequest(feign.Request input) { requestBuilder.addHeader("Accept", "*/*"); } - RequestBody body = input.httpMethod().isWithBody() ? toRequestBody(input, mediaType) : null; - requestBuilder.method(input.httpMethod().name(), body); - return requestBuilder.build(); - } - - static RequestBody toRequestBody(feign.Request request, MediaType mediaType) { - return request - .body() - .map(body -> toRequestBody(body, mediaType)) - .orElseGet(() -> RequestBody.create(new byte[0], mediaType)); - } - - static RequestBody toRequestBody(feign.Request.Body body, MediaType mediaType) { - return new RequestBody() { - @Override - public MediaType contentType() { - return mediaType; - } - - @Override - public long contentLength() { - return body.contentLength(); - } - - @Override - public boolean isOneShot() { - return !body.isRepeatable(); + byte[] inputBody = input.body(); + if (input.httpMethod().isWithBody()) { + requestBuilder.removeHeader("Content-Type"); + if (inputBody == null) { + // write an empty BODY to conform with okhttp 2.4.0+ + // http://johnfeng.github.io/blog/2015/06/30/okhttp-updates-post-wouldnt-be-allowed-to-have-null-body/ + inputBody = new byte[0]; } + } - @Override - public void writeTo(BufferedSink sink) throws IOException { - body.writeTo(sink.outputStream()); - } - }; + RequestBody body = inputBody != null ? RequestBody.create(mediaType, inputBody) : null; + requestBuilder.method(input.httpMethod().name(), body); + return requestBuilder.build(); } private static feign.Response toFeignResponse(Response response, feign.Request request) diff --git a/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java b/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java index c03eb1ef4b..79150b86b9 100644 --- a/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java +++ b/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java @@ -16,6 +16,7 @@ package feign.okhttp; import static feign.assertj.MockWebServerAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.assertj.core.data.MapEntry.entry; @@ -527,7 +528,7 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (final FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEmpty(); + assertThat(e.contentUTF8()).isEqualTo("Request body"); return; } fail(""); @@ -564,7 +565,7 @@ void whenReturnTypeIsResponseNoErrorHandling() throws Throwable { .status(302) .reason("Found") .headers(headers) - .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/", Collections.emptyMap(), null, Util.UTF_8)) .body(new byte[0]) .build(); @@ -768,7 +769,7 @@ private Response responseWithText(String text) { return Response.builder() .body(text, Util.UTF_8) .status(200) - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(new HashMap<>()) .build(); } @@ -1026,9 +1027,9 @@ static final class TestInterfaceAsyncBuilder { .encoder( (object, _, template) -> { if (object instanceof Map) { - template.body(Request.Body.of(new Gson().toJson(object))); + template.body(new Gson().toJson(object)); } else { - template.body(Request.Body.of(object.toString())); + template.body(object.toString()); } }); diff --git a/pom.xml b/pom.xml index afcb4317da..3b613d5f81 100644 --- a/pom.xml +++ b/pom.xml @@ -983,14 +983,6 @@ @feign.Experimental feign.graphql - - feign.Request - - feign.RequestTemplate - - feign.mock.RequestKey - - feign.vertx.VertxHttpClient public diff --git a/ribbon/src/main/java/feign/ribbon/LBClient.java b/ribbon/src/main/java/feign/ribbon/LBClient.java index 260b57df9e..1062abb173 100644 --- a/ribbon/src/main/java/feign/ribbon/LBClient.java +++ b/ribbon/src/main/java/feign/ribbon/LBClient.java @@ -122,18 +122,15 @@ static class RibbonRequest extends ClientRequest implements Cloneable { @SuppressWarnings("deprecation") Request toRequest() { + // add header "Content-Length" according to the request body + final byte[] body = request.body(); + final int bodyLength = body != null ? body.length : 0; // create a new Map to avoid side effect, not to change the old headers Map> headers = new LinkedHashMap>(); headers.putAll(request.headers()); - String contentLength = - request.body().map(body -> String.valueOf(body.contentLength())).orElse("0"); - headers.put(Util.CONTENT_LENGTH, Collections.singletonList(contentLength)); + headers.put(Util.CONTENT_LENGTH, Collections.singletonList(String.valueOf(bodyLength))); return Request.create( - request.httpMethod(), - getUri().toASCIIString(), - headers, - request.body().orElse(null), - null); + request.httpMethod(), getUri().toASCIIString(), headers, body, request.charset()); } Client client() { diff --git a/ribbon/src/test/java/feign/ribbon/LBClientTest.java b/ribbon/src/test/java/feign/ribbon/LBClientTest.java index b2086c6744..ad29059cbe 100644 --- a/ribbon/src/test/java/feign/ribbon/LBClientTest.java +++ b/ribbon/src/test/java/feign/ribbon/LBClientTest.java @@ -22,6 +22,7 @@ import feign.ribbon.LBClient.RibbonRequest; import java.net.URI; import java.net.URISyntaxException; +import java.nio.charset.Charset; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; @@ -47,7 +48,8 @@ void ribbonRequest() throws URISyntaxException { URI uri = new URI(urlWithEncodedJson); Map> headers = new LinkedHashMap<>(); // create a Request for recreating another Request by toRequest() - Request requestOrigin = Request.create(method, uri.toASCIIString(), headers, null, null); + Request requestOrigin = + Request.create(method, uri.toASCIIString(), headers, null, Charset.forName("utf-8")); RibbonRequest ribbonRequest = new RibbonRequest(null, requestOrigin, uri); // use toRequest() recreate a Request diff --git a/sax/src/test/java/feign/sax/SAXDecoderTest.java b/sax/src/test/java/feign/sax/SAXDecoderTest.java index 5b23f6eb1e..21fdc29890 100644 --- a/sax/src/test/java/feign/sax/SAXDecoderTest.java +++ b/sax/src/test/java/feign/sax/SAXDecoderTest.java @@ -22,6 +22,7 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; +import feign.Util; import feign.codec.Decoder; import java.io.IOException; import java.text.ParseException; @@ -76,7 +77,7 @@ private Response statusFailedResponse() { return Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body(statusFailed, UTF_8) .build(); @@ -88,7 +89,8 @@ void nullBodyDecodesToEmpty() throws Exception { Response.builder() .status(204) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .build(); assertThat((byte[]) decoder.decode(response, byte[].class)).isEmpty(); @@ -101,7 +103,8 @@ void notFoundDecodesToEmpty() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .build(); assertThat((byte[]) decoder.decode(response, byte[].class)).isEmpty(); diff --git a/sax/src/test/java/feign/sax/examples/AWSSignatureVersion4.java b/sax/src/test/java/feign/sax/examples/AWSSignatureVersion4.java index bfb107a583..aac5a2ede5 100644 --- a/sax/src/test/java/feign/sax/examples/AWSSignatureVersion4.java +++ b/sax/src/test/java/feign/sax/examples/AWSSignatureVersion4.java @@ -16,12 +16,10 @@ package feign.sax.examples; import static feign.Util.UTF_8; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import feign.Request; import feign.RequestTemplate; import java.net.URI; -import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.time.Clock; import javax.crypto.Mac; @@ -74,7 +72,8 @@ private static String canonicalString(RequestTemplate input, String host) { canonicalRequest.append("host").append('\n'); // HexEncode(Hash(Payload)) - String bodyText = input.requestBody().map(AWSSignatureVersion4::bodyAsUtf8String).orElse(null); + byte[] data = input.body(); + String bodyText = (data != null) ? new String(data, input.requestCharset()) : null; if (bodyText != null) { canonicalRequest.append(hex(sha256(bodyText))); } else { @@ -83,10 +82,6 @@ private static String canonicalString(RequestTemplate input, String host) { return canonicalRequest.toString(); } - private static String bodyAsUtf8String(Request.Body body) { - return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); - } - private static String toSign(String timestamp, String credentialScope, String canonicalRequest) { StringBuilder toSign = new StringBuilder(); // Algorithm + '\n' + @@ -121,7 +116,7 @@ public Request apply(RequestTemplate input) { if (!input.headers().isEmpty()) { throw new UnsupportedOperationException("headers not supported"); } - if (input.requestBody().isPresent()) { + if (input.body() != null) { throw new UnsupportedOperationException("body not supported"); } diff --git a/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java b/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java index 6df54f9ef7..c4eaf5bfd5 100644 --- a/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java +++ b/slf4j/src/test/java/feign/slf4j/Slf4jLoggerTest.java @@ -42,7 +42,7 @@ public class Slf4jLoggerTest { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body(new byte[0]) .build(); @@ -125,7 +125,8 @@ void rebuffersResponseBodyWhenLogLevelIsInfo() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body("{\"error\":\"test\"}", Util.UTF_8) .build(); @@ -150,7 +151,8 @@ void rebuffersResponseBodyWhenLogLevelIsFull() throws Exception { Response.builder() .status(500) .reason("Internal Server Error") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body("{\"message\":\"error details\"}", Util.UTF_8) .build(); @@ -176,7 +178,8 @@ void responseBodyReadableMultipleTimes() throws Exception { .status(400) .reason("Bad Request") .request( - Request.create(HttpMethod.POST, "/api/submit", Collections.emptyMap(), null, null)) + Request.create( + HttpMethod.POST, "/api/submit", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.>emptyMap()) .body(originalBody, Util.UTF_8) .build(); diff --git a/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java b/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java index 31bc768304..709b7f2a13 100644 --- a/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java +++ b/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java @@ -15,7 +15,6 @@ */ package feign.soap; -import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -33,11 +32,7 @@ import java.nio.charset.StandardCharsets; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; @@ -136,7 +131,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) { } else { soapMessage.writeTo(bos); } - template.body(Request.Body.of(bos.toByteArray())); + template.body(bos.toString()); } catch (SOAPException | JAXBException | ParserConfigurationException diff --git a/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java b/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java index 8634ff9815..0cbb94be42 100644 --- a/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java +++ b/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java @@ -17,13 +17,14 @@ import static feign.Util.UTF_8; import static feign.assertj.FeignAssertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import feign.Request; import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; +import feign.Util; import feign.codec.Encoder; import feign.jaxb.JAXBContextFactory; import jakarta.xml.bind.annotation.XmlAccessType; @@ -253,7 +254,8 @@ void decodesSoap() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -288,7 +290,8 @@ void decodesSoapWithSchemaOnEnvelope() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -325,7 +328,8 @@ void decodesSoap1_2Protocol() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -349,7 +353,8 @@ class ParameterizedHolder { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body( """ @@ -399,9 +404,10 @@ void decodeAnnotatedParameterizedTypes() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) - .body(template.requestBody().map(this::bodyAsBytes).orElse(null)) + .body(template.body()) .build(); new SOAPDecoder(new JAXBContextFactory.Builder().build()).decode(response, Box.class); @@ -414,7 +420,8 @@ void notFoundDecodesToNull() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat( @@ -459,10 +466,6 @@ void changeSoapProtocolAndSetHeader() { assertThat(template).hasBody(soapEnvelop); } - private byte[] bodyAsBytes(Request.Body body) { - return assertDoesNotThrow(body::writeToByteArray); - } - @XmlRootElement static class Box { diff --git a/soap-jakarta/src/test/java/feign/soap/SOAPFaultDecoderTest.java b/soap-jakarta/src/test/java/feign/soap/SOAPFaultDecoderTest.java index 85cd3979a5..c94f83b16a 100644 --- a/soap-jakarta/src/test/java/feign/soap/SOAPFaultDecoderTest.java +++ b/soap-jakarta/src/test/java/feign/soap/SOAPFaultDecoderTest.java @@ -23,6 +23,7 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; +import feign.Util; import feign.jaxb.JAXBContextFactory; import jakarta.xml.soap.SOAPConstants; import jakarta.xml.ws.soap.SOAPFaultException; @@ -49,7 +50,8 @@ void soapDecoderThrowsSOAPFaultException() throws IOException { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(getResourceBytes("/samples/SOAP_1_2_FAULT.xml")) .build(); @@ -71,7 +73,8 @@ void errorDecoderReturnsSOAPFaultException() throws IOException { Response.builder() .status(400) .reason("BAD REQUEST") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(getResourceBytes("/samples/SOAP_1_1_FAULT.xml")) .build(); @@ -88,7 +91,8 @@ void errorDecoderReturnsFeignExceptionOn503Status() throws IOException { Response.builder() .status(503) .reason("Service Unavailable") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body("Service Unavailable", UTF_8) .build(); @@ -119,7 +123,8 @@ void errorDecoderReturnsFeignExceptionOnEmptyFault() throws IOException { Response.builder() .status(500) .reason("Internal Server Error") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(responseBody, UTF_8) .build(); diff --git a/soap/src/main/java/feign/soap/SOAPEncoder.java b/soap/src/main/java/feign/soap/SOAPEncoder.java index 711c44171f..24f10da917 100644 --- a/soap/src/main/java/feign/soap/SOAPEncoder.java +++ b/soap/src/main/java/feign/soap/SOAPEncoder.java @@ -15,7 +15,6 @@ */ package feign.soap; -import feign.Request; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; @@ -136,7 +135,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) { } else { soapMessage.writeTo(bos); } - template.body(Request.Body.of(bos.toByteArray())); + template.body(new String(bos.toByteArray())); } catch (SOAPException | JAXBException | ParserConfigurationException diff --git a/soap/src/test/java/feign/soap/SOAPCodecTest.java b/soap/src/test/java/feign/soap/SOAPCodecTest.java index 59d38432da..002a0e33b6 100644 --- a/soap/src/test/java/feign/soap/SOAPCodecTest.java +++ b/soap/src/test/java/feign/soap/SOAPCodecTest.java @@ -17,13 +17,14 @@ import static feign.Util.UTF_8; import static feign.assertj.FeignAssertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import feign.Request; import feign.Request.HttpMethod; import feign.RequestTemplate; import feign.Response; +import feign.Util; import feign.codec.Encoder; import feign.jaxb.JAXBContextFactory; import java.lang.reflect.Type; @@ -253,7 +254,8 @@ void decodesSoap() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -288,7 +290,8 @@ void decodesSoapWithSchemaOnEnvelope() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -325,7 +328,8 @@ void decodesSoap1_2Protocol() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(mockSoapEnvelop, UTF_8) .build(); @@ -349,7 +353,8 @@ class ParameterizedHolder { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body( """ @@ -409,9 +414,10 @@ void decodeAnnotatedParameterizedTypes() throws Exception { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) - .body(template.requestBody().map(this::bodyAsBytes).orElse(null)) + .body(template.body()) .build(); new SOAPDecoder(new JAXBContextFactory.Builder().build()).decode(response, Box.class); @@ -424,7 +430,8 @@ void notFoundDecodesToNull() throws Exception { Response.builder() .status(404) .reason("NOT FOUND") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .build(); assertThat( @@ -469,10 +476,6 @@ void changeSoapProtocolAndSetHeader() { assertThat(template).hasBody(soapEnvelop); } - private byte[] bodyAsBytes(Request.Body body) { - return assertDoesNotThrow(body::writeToByteArray); - } - static class ChangedProtocolAndHeaderSOAPEncoder extends SOAPEncoder { public ChangedProtocolAndHeaderSOAPEncoder(JAXBContextFactory jaxbContextFactory) { diff --git a/soap/src/test/java/feign/soap/SOAPFaultDecoderTest.java b/soap/src/test/java/feign/soap/SOAPFaultDecoderTest.java index 810f173f11..15d3f76696 100644 --- a/soap/src/test/java/feign/soap/SOAPFaultDecoderTest.java +++ b/soap/src/test/java/feign/soap/SOAPFaultDecoderTest.java @@ -23,6 +23,7 @@ import feign.Request; import feign.Request.HttpMethod; import feign.Response; +import feign.Util; import feign.jaxb.JAXBContextFactory; import java.io.DataInputStream; import java.io.IOException; @@ -42,7 +43,8 @@ void soapDecoderThrowsSOAPFaultException() throws IOException { Response.builder() .status(200) .reason("OK") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(getResourceBytes("/samples/SOAP_1_2_FAULT.xml")) .build(); @@ -63,7 +65,8 @@ void errorDecoderReturnsSOAPFaultException() throws IOException { Response.builder() .status(400) .reason("BAD REQUEST") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(getResourceBytes("/samples/SOAP_1_1_FAULT.xml")) .build(); @@ -80,7 +83,8 @@ void errorDecoderReturnsFeignExceptionOn503Status() throws IOException { Response.builder() .status(503) .reason("Service Unavailable") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body("Service Unavailable", UTF_8) .build(); @@ -111,7 +115,8 @@ void errorDecoderReturnsFeignExceptionOnEmptyFault() throws IOException { Response.builder() .status(500) .reason("Internal Server Error") - .request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, null)) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) .headers(Collections.emptyMap()) .body(responseBody, UTF_8) .build(); diff --git a/spring/src/test/java/feign/spring/SpringContractTest.java b/spring/src/test/java/feign/spring/SpringContractTest.java index 7788815757..4f0277d70e 100755 --- a/spring/src/test/java/feign/spring/SpringContractTest.java +++ b/spring/src/test/java/feign/spring/SpringContractTest.java @@ -16,7 +16,6 @@ package feign.spring; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertThrows; import feign.Feign; @@ -182,8 +181,7 @@ void nonRequiredRequestBodyIsNull() { resource.checkWithNonRequiredRequestBody(null); Request request = mockClient.verifyOne(HttpMethod.POST, "/health/withNonRequiredRequestBody"); - assertThat(request.requestTemplate().requestBody().map(this::bodyAsUtf8String)) - .contains("null"); + assertThat(request.requestTemplate().body()).asString().isEqualTo("null"); } @Test @@ -193,8 +191,7 @@ void nonRequiredRequestBodyIsObject() { resource.checkWithNonRequiredRequestBody(object); Request request = mockClient.verifyOne(HttpMethod.POST, "/health/withNonRequiredRequestBody"); - assertThat(request.requestTemplate().requestBody().map(this::bodyAsUtf8String).orElse(null)) - .contains("\"name\" : \"hello\""); + assertThat(request.requestTemplate().body()).asString().contains("\"name\" : \"hello\""); } @Test @@ -284,10 +281,6 @@ void consumeAndProduce() { assertThat(request.headers()).containsEntry("Accept", Arrays.asList("text/plain")); } - private String bodyAsUtf8String(Request.Body body) { - return assertDoesNotThrow(() -> body.writeToString(StandardCharsets.UTF_8)); - } - interface GenericResource { @RequestMapping(value = "generic", method = RequestMethod.GET) diff --git a/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java b/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java index 36748ac295..b2c977a242 100644 --- a/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java +++ b/validation-jakarta/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java @@ -20,7 +20,6 @@ import feign.Feign; import feign.Param; -import feign.Request; import feign.RequestLine; import jakarta.validation.ConstraintViolationException; import jakarta.validation.Valid; @@ -77,8 +76,7 @@ interface Api { private Api api() { return Feign.builder() - .encoder( - (object, bodyType, template) -> template.body(Request.Body.of(String.valueOf(object)))) + .encoder((object, bodyType, template) -> template.body(String.valueOf(object))) .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory()) .target(Api.class, "http://localhost:" + server.getPort()); } diff --git a/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java b/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java index a25b393a38..11c19dd111 100644 --- a/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java +++ b/validation/src/test/java/feign/validation/BeanValidationMethodInterceptorTest.java @@ -20,7 +20,6 @@ import feign.Feign; import feign.Param; -import feign.Request; import feign.RequestLine; import javax.validation.ConstraintViolationException; import javax.validation.Valid; @@ -77,8 +76,7 @@ interface Api { private Api api() { return Feign.builder() - .encoder( - (object, bodyType, template) -> template.body(Request.Body.of(String.valueOf(object)))) + .encoder((object, bodyType, template) -> template.body(String.valueOf(object))) .methodInterceptor(BeanValidationMethodInterceptor.usingDefaultFactory()) .target(Api.class, "http://localhost:" + server.getPort()); } diff --git a/vertx/feign-vertx/src/main/java/feign/VertxFeign.java b/vertx/feign-vertx/src/main/java/feign/VertxFeign.java index 24a24cef59..09a6264ebe 100644 --- a/vertx/feign-vertx/src/main/java/feign/VertxFeign.java +++ b/vertx/feign-vertx/src/main/java/feign/VertxFeign.java @@ -28,7 +28,6 @@ import feign.querymap.FieldQueryMapEncoder; import feign.vertx.VertxDelegatingContract; import feign.vertx.VertxHttpClient; -import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.client.HttpRequest; import io.vertx.ext.web.client.WebClient; @@ -95,7 +94,6 @@ public T newInstance(final Target target) { /** VertxFeign builder. */ public static final class Builder extends Feign.Builder { - private Vertx vertx; private WebClient webClient; private final List requestInterceptors = new ArrayList<>(); private Logger.Level logLevel = Logger.Level.NONE; @@ -124,11 +122,6 @@ public Builder invocationHandlerFactory( throw new UnsupportedOperationException(); } - public Builder vertx(final Vertx vertx) { - this.vertx = vertx; - return this; - } - /** * Sets a vertx WebClient. * @@ -377,12 +370,10 @@ public Feign.Builder options(final Request.Options options) { @Override public VertxFeign internalBuild() { - checkNotNull(this.vertx, "Vertx instance wasn't provided in VertxFeign builder"); checkNotNull( this.webClient, "Vertx WebClient instance wasn't provided in VertxFeign builder"); - final VertxHttpClient client = - new VertxHttpClient(vertx, webClient, timeout, requestPreProcessor); + final VertxHttpClient client = new VertxHttpClient(webClient, timeout, requestPreProcessor); final VertxMethodHandler.Factory methodHandlerFactory = new VertxMethodHandler.Factory( client, retryer, requestInterceptors, logger, logLevel, decode404); diff --git a/vertx/feign-vertx/src/main/java/feign/vertx/OutputToReadStream.java b/vertx/feign-vertx/src/main/java/feign/vertx/OutputToReadStream.java deleted file mode 100644 index e124976ad7..0000000000 --- a/vertx/feign-vertx/src/main/java/feign/vertx/OutputToReadStream.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package feign.vertx; - -import io.vertx.core.AsyncResult; -import io.vertx.core.Context; -import io.vertx.core.Future; -import io.vertx.core.Handler; -import io.vertx.core.Promise; -import io.vertx.core.Vertx; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.streams.ReadStream; -import io.vertx.core.streams.WriteStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Objects; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; - -/** - * A conversion utility to help move data from a Java classic blocking IO to a Vert.x asynchronous - * stream. - * - *

Adapted from {@code io.cloudonix.vertx.javaio.OutputToReadStream} in {@code - * io.cloudonix:vertx-java.io:5.0.8} (MIT License), with local changes for Feign. - * - *

This class is copied here to keep compatibility with both Vert.x 4 and Vert.x 5. - * - *

Main compatibility change: {@link #pipeFromInput(InputStream, WriteStream)} uses {@code - * Future.onComplete(...)} rather than {@code Future.andThen(...)} to avoid a runtime linkage to - * {@code io.vertx.core.Completable}, which does not exist in Vert.x 4. - * - *

Use this class to create an {@link OutputStream} that pushes data written to it to a {@link - * ReadStream} API. - * - *

The ReadStream handlers are called on a Vert.x context, and {@link #close()} must be called - * for the ReadStream end handler to be triggered. - * - *

It is recommended to use this class in a blocking try-with-resources block, to ensure that - * streams are closed properly. For example: - * - *

{@code try (final OutputToReadStream os = new OutputToReadStream(vertx); final InputStream is - * = getInput()) { os.pipeTo(someWriteStream); is.transferTo(os); } } - * - * @author guss77 - */ -public class OutputToReadStream extends OutputStream implements ReadStream { - - private AtomicReference paused = new AtomicReference<>(new CountDownLatch(0)); - private boolean closed; - private AtomicLong demand = new AtomicLong(0); - private Handler endHandler = v -> {}; - private Handler dataHandler = d -> {}; - private Handler errorHandler = t -> {}; - private Context context; - - public OutputToReadStream(Vertx vertx) { - context = vertx.getOrCreateContext(); - } - - /** - * Helper utility to pipe a Java {@link InputStream} to a {@link WriteStream}. - * - *

This method is non-blocking and Vert.x context safe. It uses the common ForkJoinPool to - * perform the Java blocking IO and will try to propagate IO failures to the returned {@link - * Future}. - * - *

Compatibility note: this implementation intentionally uses {@code - * onComplete} (not {@code andThen}) so it works on Vert.x 4 and Vert.x 5. - * - *

This method uses {@link InputStream#transferTo(OutputStream)} to copy all the data, and will - * then attempt to close both streams asynchronously. Some Java compilers might not detect that - * the streams will be safely closed and will issue leak warnings. - * - * @param source InputStream to drain - * @param sink WriteStream to pipe data to - * @return a Future that will succeed when all the data have been written and the streams closed, - * or fail if an {@link IOException} has occurred - */ - public Future pipeFromInput(InputStream source, WriteStream sink) { - Promise promise = Promise.promise(); - pipeTo(sink) - .onComplete( - ar -> { - if (ar.succeeded()) { - promise.complete(ar.result()); - } else { - promise.fail(ar.cause()); - } - }); - ForkJoinPool.commonPool() - .submit( - () -> { - try (final InputStream is = source; - final OutputStream os = this) { - source.transferTo(this); - } catch (IOException e) { - promise.tryFail(e); - } - }); - return promise.future(); - } - - /** - * Helper utility to pipe a Java {@link InputStream} to a {@link WriteStream}. - * - *

This method is non-blocking and Vert.x context safe. It uses the common ForkJoinPool to - * perform the Java blocking IO and will try to propagate IO failures to the returned {@link - * Future} - * - *

This method uses {@link InputStream#transferTo(OutputStream)} to copy all the data, and will - * then attempt to close both streams asynchronously. Some Java compilers might not detect that - * the streams will be safely closed and will issue leak warnings. - * - * @param source InputStream to drain - * @param sink WriteStream to pipe data to - * @param handler a handler that will be called when all the data have been written and the - * streams closed, or if an {@link IOException} has occurred. - */ - public void pipeFromInput( - InputStream source, WriteStream sink, Handler> handler) { - pipeFromInput(source, sink).onComplete(handler); - } - - /** - * Propagate an out-of-band error (likely generated or handled by the code that feeds the output - * stream) to the end of the read stream to let them know that the result is not going to be good. - * - * @param t error to be propagated down the stream - */ - public void sendError(Throwable t) { - context.executeBlocking( - () -> { - errorHandler.handle(t); - return null; - }); - } - - /* ReadStream stuff */ - - /** - * {@inheritDoc} - * - * @param handler {@inheritDoc} - * @return {@inheritDoc} - */ - @Override - public OutputToReadStream exceptionHandler(Handler handler) { - // we are usually not propagating exceptions as OutputStream has no mechanism for propagating - // exceptions down, - // except when wrapping an input stream, in which case we can forward InputStream read errors to - // the error handler. - errorHandler = Objects.requireNonNullElse(handler, t -> {}); - return this; - } - - /** - * {@inheritDoc} - * - * @param handler {@inheritDoc} - * @return {@inheritDoc} - */ - @Override - public OutputToReadStream handler(Handler handler) { - this.dataHandler = Objects.requireNonNullElse(handler, d -> {}); - return this; - } - - /** - * {@inheritDoc} - * - * @return {@inheritDoc} - */ - @Override - public OutputToReadStream pause() { - paused.getAndSet(new CountDownLatch(1)).countDown(); - return this; - } - - /** - * {@inheritDoc} - * - * @return {@inheritDoc} - */ - @Override - public OutputToReadStream resume() { - paused.getAndSet(new CountDownLatch(0)).countDown(); - return this; - } - - /** - * {@inheritDoc} - * - * @param amount {@inheritDoc} - * @return {@inheritDoc} - */ - @Override - public OutputToReadStream fetch(long amount) { - resume(); - demand.addAndGet(amount); - return null; - } - - /** - * {@inheritDoc} - * - * @param endHandler {@inheritDoc} - * @return {@inheritDoc} - */ - @Override - public OutputToReadStream endHandler(Handler endHandler) { - this.endHandler = Objects.requireNonNullElse(endHandler, v -> {}); - return this; - } - - /* OutputStream stuff */ - - /** - * {@inheritDoc} - * - * @param b {@inheritDoc} - * @throws IOException {@inheritDoc} - */ - @Override - public synchronized void write(int b) throws IOException { - if (closed) throw new IOException("OutputStream is closed"); - try { - paused.get().await(); - } catch (InterruptedException e) { - throw new IOException("Interrupted a wait for stream to resume", e); - } - push(Buffer.buffer(1).appendByte((byte) (b & 0xFF))); - } - - /** - * {@inheritDoc} - * - * @param b {@inheritDoc} - * @param off {@inheritDoc} - * @param len {@inheritDoc} - * @throws IOException {@inheritDoc} - */ - @Override - public synchronized void write(byte[] b, int off, int len) throws IOException { - if (closed) throw new IOException("OutputStream is closed"); - try { - paused.get().await(); - } catch (InterruptedException e) { - throw new IOException("Interrupted a wait for stream to resume", e); - } - push(Buffer.buffer(len - off).appendBytes(b, off, len)); - } - - /** - * {@inheritDoc} - * - * @throws IOException {@inheritDoc} - */ - @Override - public synchronized void close() throws IOException { - if (closed) return; - closed = true; - try { - paused.get().await(); - } catch (InterruptedException e) { - throw new IOException("Interrupted a wait for stream to resume", e); - } - push(null); - } - - /* Internal implementation */ - - private void push(Buffer data) { - var awaiter = new CountDownLatch(1); - context.runOnContext( - v -> { - try { - if (data == null) // end of stream - endHandler.handle(null); - else dataHandler.handle(data); - } catch (Throwable t) { - errorHandler.handle(t); - } finally { - awaiter.countDown(); - } - }); - try { - awaiter.await(); - } catch (InterruptedException e) { - } - } -} diff --git a/vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java b/vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java index 0a00bd2adb..0b196b6ffb 100644 --- a/vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java +++ b/vertx/feign-vertx/src/main/java/feign/vertx/VertxHttpClient.java @@ -44,7 +44,6 @@ */ @SuppressWarnings("unused") public final class VertxHttpClient { - private final Vertx vertx; private final WebClient webClient; private final long timeout; private final UnaryOperator> requestPreProcessor; @@ -57,15 +56,12 @@ public final class VertxHttpClient { * @param requestPreProcessor request pre-processor */ public VertxHttpClient( - final Vertx vertx, final WebClient webClient, final long timeout, final UnaryOperator> requestPreProcessor) { - checkNotNull(vertx, "Argument vertx must not be null"); checkNotNull(webClient, "Argument webClient must not be null"); checkNotNull(requestPreProcessor, "Argument requestPreProcessor must be not null"); - this.vertx = vertx; this.webClient = webClient; this.timeout = timeout; this.requestPreProcessor = requestPreProcessor; @@ -89,25 +85,9 @@ public Future execute(final Request request) { } final Future> responseFuture = - request - .body() - .map( - body -> { - OutputToReadStream stream = new OutputToReadStream(vertx); - Future> sendStreamFuture = - httpClientRequest.sendStream(stream); - Future writeFuture = - vertx.executeBlocking( - () -> { - try (stream) { - body.writeTo(stream); - } - return null; - }); - return Future.all(sendStreamFuture, writeFuture) - .map(composite -> sendStreamFuture.result()); - }) - .orElseGet(httpClientRequest::send); + request.body() != null + ? httpClientRequest.sendBuffer(Buffer.buffer(request.body())) + : httpClientRequest.send(); return responseFuture.compose( response -> { diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java b/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java index dd7f496b6b..5931c7acb4 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/ConnectionsLeakTests.java @@ -81,7 +81,6 @@ void http11NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { HelloServiceAPI client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) @@ -109,7 +108,6 @@ void http2NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { HelloServiceAPI client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java index 88dab3713b..fae9a70e9d 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/Http11ClientReconnectTest.java @@ -38,7 +38,6 @@ protected void createClient(final Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java index 69e3d5dfd8..39a43a8adb 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/QueryMapEncoderTest.java @@ -55,7 +55,6 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .queryMapEncoder(new CustomQueryMapEncoder()) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java index e816622474..48f46b4b49 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/RawContractTest.java @@ -45,7 +45,6 @@ class RawContractTest extends AbstractFeignVertxTest { static void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(WebClient.create(vertx)) .encoder(new JacksonEncoder(TestUtils.MAPPER)) .decoder(new JacksonDecoder(TestUtils.MAPPER)) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java index 2d88afa6c9..87850cb9e3 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/RequestPreProcessorTest.java @@ -47,7 +47,6 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .requestPreProcessor(req -> req.addQueryParam("version", "v1")) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java index 89691c9d5a..b294d99363 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/RetryingTest.java @@ -48,7 +48,6 @@ class RetryingTest extends AbstractFeignVertxTest { static void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(WebClient.create(vertx)) .decoder(new JacksonDecoder(MAPPER)) .retryer(new DefaultRetryer(100, SECONDS.toMillis(1), 5)) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java index 5bd97dd4a5..29e7efa6e1 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/TimeoutHandlingTest.java @@ -48,7 +48,6 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .timeout(1000) diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java index 005568436b..eca7765385 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpClientTest.java @@ -65,7 +65,6 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) @@ -218,7 +217,6 @@ class WhenMakePostRequest { void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(WebClient.create(vertx)) .encoder(new JacksonEncoder(TestUtils.MAPPER)) .decoder(new JacksonDecoder(TestUtils.MAPPER)) @@ -306,23 +304,6 @@ void whenVertxMissing() { ThrowableAssert.ThrowingCallable instantiateContractForgottenVertx = () -> VertxFeign.builder().target(IcecreamServiceApi.class, wireMock.baseUrl()); - /* Then */ - assertThatCode(instantiateContractForgottenVertx) - .isInstanceOf(NullPointerException.class) - .hasMessage("Vertx instance wasn't provided in VertxFeign builder"); - } - - @Test - @DisplayName("when Vertx WebClient is not provided") - void whenVertxWebClientMissing(Vertx vertx) { - - /* Given */ - ThrowableAssert.ThrowingCallable instantiateContractForgottenVertx = - () -> - VertxFeign.builder() - .vertx(vertx) - .target(IcecreamServiceApi.class, wireMock.baseUrl()); - /* Then */ assertThatCode(instantiateContractForgottenVertx) .isInstanceOf(NullPointerException.class) @@ -337,7 +318,6 @@ void whenTryToInstantiateBrokenContract(Vertx vertx) { ThrowableAssert.ThrowingCallable instantiateBrokenContract = () -> VertxFeign.builder() - .vertx(vertx) .webClient(WebClient.create(vertx)) .target(IcecreamServiceApiBroken.class, wireMock.baseUrl()); diff --git a/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java index 21eefbe9ca..626376a347 100644 --- a/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java +++ b/vertx/feign-vertx/src/test/java/feign/vertx/VertxHttpOptionsTest.java @@ -65,7 +65,6 @@ void httpClientOptions(Vertx vertx, VertxTestContext testContext) { IcecreamServiceApi client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) @@ -87,7 +86,6 @@ void requestOptions(Vertx vertx, VertxTestContext testContext) { IcecreamServiceApi client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java index 4dcde50338..b76b751ed0 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/ConnectionsLeakTests.java @@ -84,7 +84,6 @@ void http11NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { HelloServiceAPI client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) @@ -112,7 +111,6 @@ void http2NoConnectionLeak(Vertx vertx, VertxTestContext testContext) { HelloServiceAPI client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java index bb6edaf4a8..207ae8a89e 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/Http11ClientReconnectTest.java @@ -36,7 +36,6 @@ protected void createClient(final Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder()) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java index 69e3d5dfd8..39a43a8adb 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/QueryMapEncoderTest.java @@ -55,7 +55,6 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .queryMapEncoder(new CustomQueryMapEncoder()) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java index e816622474..48f46b4b49 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RawContractTest.java @@ -45,7 +45,6 @@ class RawContractTest extends AbstractFeignVertxTest { static void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(WebClient.create(vertx)) .encoder(new JacksonEncoder(TestUtils.MAPPER)) .decoder(new JacksonDecoder(TestUtils.MAPPER)) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java index 2d88afa6c9..87850cb9e3 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RequestPreProcessorTest.java @@ -47,7 +47,6 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .requestPreProcessor(req -> req.addQueryParam("version", "v1")) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java index 89691c9d5a..b294d99363 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/RetryingTest.java @@ -48,7 +48,6 @@ class RetryingTest extends AbstractFeignVertxTest { static void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(WebClient.create(vertx)) .decoder(new JacksonDecoder(MAPPER)) .retryer(new DefaultRetryer(100, SECONDS.toMillis(1), 5)) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java index 5bd97dd4a5..29e7efa6e1 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/TimeoutHandlingTest.java @@ -48,7 +48,6 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .timeout(1000) diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java index 005568436b..eca7765385 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpClientTest.java @@ -65,7 +65,6 @@ void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) @@ -218,7 +217,6 @@ class WhenMakePostRequest { void createClient(Vertx vertx) { client = VertxFeign.builder() - .vertx(vertx) .webClient(WebClient.create(vertx)) .encoder(new JacksonEncoder(TestUtils.MAPPER)) .decoder(new JacksonDecoder(TestUtils.MAPPER)) @@ -306,23 +304,6 @@ void whenVertxMissing() { ThrowableAssert.ThrowingCallable instantiateContractForgottenVertx = () -> VertxFeign.builder().target(IcecreamServiceApi.class, wireMock.baseUrl()); - /* Then */ - assertThatCode(instantiateContractForgottenVertx) - .isInstanceOf(NullPointerException.class) - .hasMessage("Vertx instance wasn't provided in VertxFeign builder"); - } - - @Test - @DisplayName("when Vertx WebClient is not provided") - void whenVertxWebClientMissing(Vertx vertx) { - - /* Given */ - ThrowableAssert.ThrowingCallable instantiateContractForgottenVertx = - () -> - VertxFeign.builder() - .vertx(vertx) - .target(IcecreamServiceApi.class, wireMock.baseUrl()); - /* Then */ assertThatCode(instantiateContractForgottenVertx) .isInstanceOf(NullPointerException.class) @@ -337,7 +318,6 @@ void whenTryToInstantiateBrokenContract(Vertx vertx) { ThrowableAssert.ThrowingCallable instantiateBrokenContract = () -> VertxFeign.builder() - .vertx(vertx) .webClient(WebClient.create(vertx)) .target(IcecreamServiceApiBroken.class, wireMock.baseUrl()); diff --git a/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java index 2ca7a54cb6..0e83d3ea62 100644 --- a/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java +++ b/vertx/feign-vertx4-test/src/test/java/feign/vertx/VertxHttpOptionsTest.java @@ -64,7 +64,6 @@ void httpClientOptions(Vertx vertx, VertxTestContext testContext) { IcecreamServiceApi client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) @@ -86,7 +85,6 @@ void requestOptions(Vertx vertx, VertxTestContext testContext) { IcecreamServiceApi client = VertxFeign.builder() - .vertx(vertx) .webClient(webClient) .decoder(new JacksonDecoder(TestUtils.MAPPER)) .logger(new Slf4jLogger()) From 2c5582154e69e5eb429a63836043bf55cebac9cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:56:32 +0000 Subject: [PATCH 560/615] build(deps): Bump jackson.version from 2.21.3 to 2.22.0 Bumps `jackson.version` from 2.21.3 to 2.22.0. Updates `com.fasterxml.jackson:jackson-bom` from 2.21.3 to 2.22.0 - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.21.3...jackson-bom-2.22.0) Updates `com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider` from 2.21.3 to 2.22.0 --- updated-dependencies: - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-version: 2.22.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson:jackson-bom dependency-version: 2.22.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3b613d5f81..1eb4cf6aaa 100644 --- a/pom.xml +++ b/pom.xml @@ -174,7 +174,7 @@ 4.0.6 6.1.0 - 2.21.3 + 2.22.0 3.1.3 3.27.7 5.23.0 diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 718138ecdc..518822a8b5 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -31,7 +31,7 @@ 11 - 2.21.3 + 2.22.0 From 83a98e32c7cff8cd3d8c476b56371ff95081faf8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:58:05 +0000 Subject: [PATCH 561/615] build(deps): Bump org.hibernate.validator:hibernate-validator Bumps [org.hibernate.validator:hibernate-validator](https://github.com/hibernate/hibernate-validator) from 6.2.5.Final to 9.1.0.Final. - [Release notes](https://github.com/hibernate/hibernate-validator/releases) - [Changelog](https://github.com/hibernate/hibernate-validator/blob/main/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-validator/compare/6.2.5.Final...9.1.0.Final) --- updated-dependencies: - dependency-name: org.hibernate.validator:hibernate-validator dependency-version: 9.1.0.Final dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3b613d5f81..15aad04c41 100644 --- a/pom.xml +++ b/pom.xml @@ -237,8 +237,8 @@ 2.3.1 2.0.1.Final 3.1.1 - 6.2.5.Final - 8.0.1.Final + 9.1.0.Final + 9.1.0.Final 3.0.4 6.0.0 1.19.4 From 0684947cefc21b1f8ebb36b1bc4238d5bcb7ee92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 05:12:38 +0000 Subject: [PATCH 562/615] build(deps): Bump org.springframework.cloud:spring-cloud-dependencies Bumps [org.springframework.cloud:spring-cloud-dependencies](https://github.com/spring-cloud/spring-cloud-release) from 2025.1.1 to 2025.1.2. - [Release notes](https://github.com/spring-cloud/spring-cloud-release/releases) - [Commits](https://github.com/spring-cloud/spring-cloud-release/compare/v2025.1.1...v2025.1.2) --- updated-dependencies: - dependency-name: org.springframework.cloud:spring-cloud-dependencies dependency-version: 2025.1.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3b613d5f81..fac91fd459 100644 --- a/pom.xml +++ b/pom.xml @@ -251,7 +251,7 @@ 2.1.1 1.5.3 3.0.2 - 2025.1.1 + 2025.1.2 5.0.1 7.0.7 7.0.7 From ee44507f4c017377d2fdffca3d8fb0c57c025b83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 05:13:11 +0000 Subject: [PATCH 563/615] build(deps-dev): Bump jersey.version from 3.1.11 to 3.1.12 in /jaxrs3 Bumps `jersey.version` from 3.1.11 to 3.1.12. Updates `org.glassfish.jersey.core:jersey-client` from 3.1.11 to 3.1.12 Updates `org.glassfish.jersey.inject:jersey-hk2` from 3.1.11 to 3.1.12 --- updated-dependencies: - dependency-name: org.glassfish.jersey.core:jersey-client dependency-version: 3.1.12 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: org.glassfish.jersey.inject:jersey-hk2 dependency-version: 3.1.12 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- jaxrs3/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index b5dabe1d19..0e3193bb0d 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -31,7 +31,7 @@ 11 - 3.1.11 + 3.1.12 From 77342a7907bba99ebbca2ad3cd1af4ec0f190a2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 05:24:57 +0000 Subject: [PATCH 564/615] build(deps-dev): Bump org.springframework.cloud:spring-cloud-starter-openfeign Bumps [org.springframework.cloud:spring-cloud-starter-openfeign](https://github.com/spring-cloud/spring-cloud-openfeign) from 5.0.1 to 5.0.2. - [Release notes](https://github.com/spring-cloud/spring-cloud-openfeign/releases) - [Commits](https://github.com/spring-cloud/spring-cloud-openfeign/compare/v5.0.1...v5.0.2) --- updated-dependencies: - dependency-name: org.springframework.cloud:spring-cloud-starter-openfeign dependency-version: 5.0.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fac91fd459..63728c151d 100644 --- a/pom.xml +++ b/pom.xml @@ -252,7 +252,7 @@ 1.5.3 3.0.2 2025.1.2 - 5.0.1 + 5.0.2 7.0.7 7.0.7 2.4.1.Final From 0a5a9983f2696cc0a57ea960b8d297cff7a78abf Mon Sep 17 00:00:00 2001 From: velo Date: Sat, 13 Jun 2026 08:17:01 -0300 Subject: [PATCH 565/615] Keep legacy validation on Hibernate Validator 6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 15aad04c41..826b0a680e 100644 --- a/pom.xml +++ b/pom.xml @@ -237,7 +237,7 @@ 2.3.1 2.0.1.Final 3.1.1 - 9.1.0.Final + 6.2.5.Final 9.1.0.Final 3.0.4 6.0.0 From 61154cb1879dea98b495257ecb088548e0bce200 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Jun 2026 11:51:58 +0000 Subject: [PATCH 566/615] build(deps): Bump tools.jackson:jackson-bom from 3.1.3 to 3.2.0 Bumps [tools.jackson:jackson-bom](https://github.com/FasterXML/jackson-bom) from 3.1.3 to 3.2.0. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-3.1.3...jackson-bom-3.2.0) --- updated-dependencies: - dependency-name: tools.jackson:jackson-bom dependency-version: 3.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 28b3673d9b..3038cdeec0 100644 --- a/pom.xml +++ b/pom.xml @@ -175,7 +175,7 @@ 6.1.0 2.22.0 - 3.1.3 + 3.2.0 3.27.7 5.23.0 2.0.61.android8 From 058693793a56a6b8191beed912cd4bccb3c916f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Jun 2026 11:52:09 +0000 Subject: [PATCH 567/615] build(deps): Bump springboot.version from 4.0.6 to 4.1.0 Bumps `springboot.version` from 4.0.6 to 4.1.0. Updates `org.springframework.boot:spring-boot-maven-plugin` from 4.0.6 to 4.1.0 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.6...v4.1.0) Updates `org.springframework.boot:spring-boot-starter-web` from 4.0.6 to 4.1.0 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.6...v4.1.0) Updates `org.springframework.boot:spring-boot-starter-test` from 4.0.6 to 4.1.0 - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v4.0.6...v4.1.0) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-maven-plugin dependency-version: 4.1.0 dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: org.springframework.boot:spring-boot-starter-test dependency-version: 4.1.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.springframework.boot:spring-boot-starter-web dependency-version: 4.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 28b3673d9b..8bab55f28f 100644 --- a/pom.xml +++ b/pom.xml @@ -171,7 +171,7 @@ 1.15.2 2.0.18 20260522 - 4.0.6 + 4.1.0 6.1.0 2.22.0 From 82992960be9e6ba4d7fe3a49251fd2b26f1959ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Jun 2026 11:57:36 +0000 Subject: [PATCH 568/615] build(deps): Bump com.squareup.okhttp3:okhttp-bom from 5.3.2 to 5.4.0 Bumps [com.squareup.okhttp3:okhttp-bom](https://github.com/square/okhttp) from 5.3.2 to 5.4.0. - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-5.3.2...parent-5.4.0) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp-bom dependency-version: 5.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 28b3673d9b..9e77247efb 100644 --- a/pom.xml +++ b/pom.xml @@ -164,7 +164,7 @@ ${main.java.version} ${main.java.version} - 5.3.2 + 5.4.0 33.6.0-jre 2.1.0 2.14.0 From a4bcd853d1f99938100b17d3696f3979e129f3b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Jun 2026 11:57:38 +0000 Subject: [PATCH 569/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx5-test Bumps `vertx.version` from 5.1.1 to 5.1.2. Updates `io.vertx:vertx-junit5` from 5.1.1 to 5.1.2 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/5.1.1...5.1.2) Updates `io.vertx:vertx-web-client` from 5.1.1 to 5.1.2 - [Commits](https://github.com/vert-x3/vertx-web/compare/5.1.1...5.1.2) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 5.1.2 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 5.1.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx5-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 3cd071e05d..0501998954 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.1.1 + 5.1.2 From b5b41dcaada75a0e4d66417c17fa2a56b3c89d4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Jun 2026 11:57:39 +0000 Subject: [PATCH 570/615] build(deps): Bump reactor.version from 3.8.5 to 3.8.6 Bumps `reactor.version` from 3.8.5 to 3.8.6. Updates `io.projectreactor:reactor-core` from 3.8.5 to 3.8.6 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.5...v3.8.6) Updates `io.projectreactor:reactor-test` from 3.8.5 to 3.8.6 - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.5...v3.8.6) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-core dependency-version: 3.8.6 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.projectreactor:reactor-test dependency-version: 3.8.6 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- reactive/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reactive/pom.xml b/reactive/pom.xml index d06c79ff62..9b6da88b97 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -29,7 +29,7 @@ Reactive Wrapper for Feign Clients - 3.8.5 + 3.8.6 1.0.4 2.2.21 From 05035c61937992dd07b2aaecd032ce6e8bd41ba2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Jun 2026 11:57:42 +0000 Subject: [PATCH 571/615] build(deps): Bump micrometer.version from 1.16.5 to 1.17.0 Bumps `micrometer.version` from 1.16.5 to 1.17.0. Updates `io.micrometer:micrometer-core` from 1.16.5 to 1.17.0 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.5...v1.17.0) Updates `io.micrometer:micrometer-test` from 1.16.5 to 1.17.0 - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.16.5...v1.17.0) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-version: 1.17.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: io.micrometer:micrometer-test dependency-version: 1.17.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- micrometer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/micrometer/pom.xml b/micrometer/pom.xml index 6092d53273..c53fb2d6c8 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -28,7 +28,7 @@ Feign Micrometer Application Metrics - 1.16.5 + 1.17.0 From 02e4448ab1ae18dac31cd2039ccf5bb58768d63a Mon Sep 17 00:00:00 2001 From: alhuda <50839256+alhudz@users.noreply.github.com> Date: Sat, 13 Jun 2026 17:35:32 +0530 Subject: [PATCH 572/615] guard numeric retry-after against long overflow (#3405) Co-authored-by: alhudz Co-authored-by: Marvin --- core/src/main/java/feign/codec/ErrorDecoder.java | 12 ++++++------ .../test/java/feign/codec/RetryAfterDecoderTest.java | 5 +++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/feign/codec/ErrorDecoder.java b/core/src/main/java/feign/codec/ErrorDecoder.java index a2a55dc54a..89e0ac279e 100644 --- a/core/src/main/java/feign/codec/ErrorDecoder.java +++ b/core/src/main/java/feign/codec/ErrorDecoder.java @@ -120,14 +120,14 @@ public Long apply(String retryAfter) { if (retryAfter == null) { return null; } - if (retryAfter.matches("^[0-9]+\\.?0*$")) { - retryAfter = retryAfter.replaceAll("\\.0*$", ""); - long deltaMillis = SECONDS.toMillis(Long.parseLong(retryAfter)); - return currentTimeMillis() + deltaMillis; - } try { + if (retryAfter.matches("^[0-9]+\\.?0*$")) { + retryAfter = retryAfter.replaceAll("\\.0*$", ""); + long deltaMillis = SECONDS.toMillis(Long.parseLong(retryAfter)); + return currentTimeMillis() + deltaMillis; + } return ZonedDateTime.parse(retryAfter, dateTimeFormatter).toInstant().toEpochMilli(); - } catch (NullPointerException | DateTimeParseException ignored) { + } catch (NumberFormatException | NullPointerException | DateTimeParseException ignored) { return null; } } diff --git a/core/src/test/java/feign/codec/RetryAfterDecoderTest.java b/core/src/test/java/feign/codec/RetryAfterDecoderTest.java index 6ee79ae540..0310ce05e8 100644 --- a/core/src/test/java/feign/codec/RetryAfterDecoderTest.java +++ b/core/src/test/java/feign/codec/RetryAfterDecoderTest.java @@ -55,6 +55,11 @@ void relativeSecondsParseDecimalIntegers() throws ParseException { assertThat(decoder.apply("86400.0")).isEqualTo(parseDateTime("Sun, 2 Jan 2000 00:00:00 GMT")); } + @Test + void overflowingRelativeSecondsFailsGracefully() { + assertThat(decoder.apply("99999999999999999999")).isNull(); + } + private Long parseDateTime(String text) { try { return ZonedDateTime.parse(text, RFC_1123_DATE_TIME).toInstant().toEpochMilli(); From cb5554b6149769ab770bd46758d3f434ccfb8ab7 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Sat, 13 Jun 2026 09:11:49 -0300 Subject: [PATCH 573/615] Align Apache HttpClient checked-exception handling with master's #1487 fix Signed-off-by: Marvin Froeder --- .../java/feign/SynchronousMethodHandler.java | 28 +++++++------------ .../feign/httpclient/ApacheHttpClient.java | 8 ++---- .../httpclient/ApacheHttpClientTest.java | 15 ---------- 3 files changed, 12 insertions(+), 39 deletions(-) diff --git a/core/src/main/java/feign/SynchronousMethodHandler.java b/core/src/main/java/feign/SynchronousMethodHandler.java index 4e611a12e4..64b81d43b4 100644 --- a/core/src/main/java/feign/SynchronousMethodHandler.java +++ b/core/src/main/java/feign/SynchronousMethodHandler.java @@ -24,7 +24,6 @@ import feign.interceptor.Invocation; import feign.interceptor.MethodInterceptor; import java.io.IOException; -import java.lang.reflect.Method; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @@ -76,13 +75,16 @@ private Object runWithRetry(Invocation invocation, Options options) throws Throw retryer.continueOrPropagate(e); } catch (RetryableException th) { Throwable cause = th.getCause(); - if (methodHandlerConfiguration.getPropagationPolicy() == UNWRAP - && cause != null - && (cause instanceof RuntimeException - || cause instanceof Error - || isDeclaredCheckedException( - cause, methodHandlerConfiguration.getMetadata().method()))) { - throw cause; + if (methodHandlerConfiguration.getPropagationPolicy() == UNWRAP && cause != null) { + if (cause instanceof RuntimeException || cause instanceof Error) { + throw cause; + } + for (Class exceptionType : + methodHandlerConfiguration.getMetadata().method().getExceptionTypes()) { + if (exceptionType.isAssignableFrom(cause.getClass())) { + throw cause; + } + } } throw th; } @@ -165,16 +167,6 @@ Options findOptions(Object[] argv) { .getMethodOptions(methodHandlerConfiguration.getMetadata().method().getName())); } - private static boolean isDeclaredCheckedException(Throwable cause, Method method) { - Class[] exceptionTypes = method.getExceptionTypes(); - for (Class exType : exceptionTypes) { - if (exType.isAssignableFrom(cause.getClass())) { - return true; - } - } - return false; - } - static class Factory implements MethodHandler.Factory { private final Client client; diff --git a/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java b/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java index 5ab2ba459e..010c229cb7 100644 --- a/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java +++ b/httpclient/src/main/java/feign/httpclient/ApacheHttpClient.java @@ -81,12 +81,8 @@ public Response execute(Request request, Request.Options options) throws IOExcep } catch (URISyntaxException e) { throw new IOException("URL '" + request.url() + "' couldn't be parsed into a URI", e); } - try { - HttpResponse httpResponse = client.execute(httpUriRequest); - return toFeignResponse(httpResponse, request); - } catch (Exception e) { - throw new IOException(e); - } + HttpResponse httpResponse = client.execute(httpUriRequest); + return toFeignResponse(httpResponse, request); } HttpUriRequest toHttpUriRequest(Request request, Request.Options options) diff --git a/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java b/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java index 079d70dc0d..4ab3601425 100644 --- a/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java +++ b/httpclient/src/test/java/feign/httpclient/ApacheHttpClientTest.java @@ -112,21 +112,6 @@ void notFollowRedirectIsRespected() throws InterruptedException { assertThat(server.takeRequest().getPath()).isEqualTo("/withOptions"); } - @Test - void redirectWithoutLocationHeader() { - JaxRsTestInterface api = - Feign.builder() - .contract(new JAXRSContract()) - .retryer(Retryer.NEVER_RETRY) - .client(new ApacheHttpClient(HttpClientBuilder.create().build())) - .target(JaxRsTestInterface.class, "http://localhost:" + server.getPort()); - - server.enqueue(new MockResponse().setResponseCode(303)); - RetryableException exception = - assertThrows(RetryableException.class, () -> api.withoutBody("foo")); - assertThat(exception.getMessage()).contains("org.apache.http.client.ClientProtocolException"); - } - private JaxRsTestInterface buildTestInterface() { return Feign.builder() .contract(new JAXRSContract()) From 865a0f6f83e112c0ee7754a2ef0f0b981fa22ff9 Mon Sep 17 00:00:00 2001 From: Marvin Date: Sat, 13 Jun 2026 10:43:37 -0300 Subject: [PATCH 574/615] build(deps): consolidate spring-web/spring-context into single spring.version 7.0.8 (#3413) Signed-off-by: Marvin Froeder --- core/pom.xml | 2 +- form-spring/pom.xml | 2 +- pom.xml | 3 +-- spring/pom.xml | 1 - spring4/pom.xml | 4 ---- 5 files changed, 3 insertions(+), 9 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 58f79c5871..a99c574c42 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,7 @@ org.springframework spring-context - ${spring-context.version} + ${spring.version} test diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 18a880fc1a..9d8cee4ad0 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -58,7 +58,7 @@ org.springframework spring-web - ${spring-web.version} + ${spring.version} compile diff --git a/pom.xml b/pom.xml index fc7a366722..5afb6b3601 100644 --- a/pom.xml +++ b/pom.xml @@ -253,8 +253,7 @@ 3.0.2 2025.1.2 5.0.2 - 7.0.7 - 7.0.7 + 7.0.8 2.4.1.Final 1.18.0 diff --git a/spring/pom.xml b/spring/pom.xml index 540a72cfb2..6c225e178b 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -31,7 +31,6 @@ 17 - 7.0.7 diff --git a/spring4/pom.xml b/spring4/pom.xml index c137a8ce87..faf785491e 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -36,10 +36,6 @@ - - 4.3.30.RELEASE - - io.github.openfeign From 2a2344d365540bcf1dedb2dd7f2920f61e85c3b5 Mon Sep 17 00:00:00 2001 From: velo Date: Sat, 13 Jun 2026 13:56:13 -0300 Subject: [PATCH 575/615] prepare release 13.13 --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- feign-bom/pom.xml | 90 +++++++++++------------ form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- http-cache/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- validation-jakarta/pom.xml | 2 +- validation/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 55 files changed, 99 insertions(+), 99 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 25e1be69c0..486fb8ab6f 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index c36dc2789b..22786640b5 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 6f79e261e1..0ec4819be7 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index a99c574c42..c437c066d1 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index b1d584a4fc..fdad3983e7 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index 97ebea5884..ba23ee0790 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 671b20e06f..186a1adee0 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 2458198a11..52f9bdd403 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index 6424011e8b..d93d37099c 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 551c2969b6..4e18d0bd7b 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index 7162b3f4a7..ac9f0cacb3 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-fastjson2 diff --git a/feign-bom/pom.xml b/feign-bom/pom.xml index cc24c5f34c..51941b4a36 100644 --- a/feign-bom/pom.xml +++ b/feign-bom/pom.xml @@ -28,7 +28,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 ../pom.xml @@ -42,222 +42,222 @@ io.github.openfeign feign-core - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-gson - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-http-cache - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jaxrs - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-httpclient - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jaxrs2 - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-hc5 - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-hystrix - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jackson - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jackson3 - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jackson-jaxb - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jackson-jr - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jaxb - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jaxb-jakarta - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jaxrs3 - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jaxrs4 - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-java11 - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-jakarta - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-mock - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-json - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-okhttp - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-googlehttpclient - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-ribbon - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-sax - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-slf4j - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-spring - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-soap - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-soap-jakarta - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-reactive-wrappers - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-micrometer - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-dropwizard-metrics4 - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-dropwizard-metrics5 - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-kotlin - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-graphql - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-annotation-error-decoder - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-form - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-form-spring - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-moshi - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-fastjson2 - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-validation - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-validation-jakarta - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-vertx - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-vertx4-test - 13.13-SNAPSHOT + 13.13 io.github.openfeign feign-vertx5-test - 13.13-SNAPSHOT + 13.13 diff --git a/form-spring/pom.xml b/form-spring/pom.xml index 9d8cee4ad0..ce4bf7aaa4 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index 1777951c51..aad3e05cc5 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index d89718f877..9f9997552b 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index b0a60a58b8..d316c1a8bf 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index bd014420c1..b540524a3f 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index dce2da755f..33bfafc1e1 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 22ab8b2d9e..83ec9ffd6f 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-hc5 diff --git a/http-cache/pom.xml b/http-cache/pom.xml index 0722503a98..6388223cc4 100644 --- a/http-cache/pom.xml +++ b/http-cache/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-http-cache diff --git a/httpclient/pom.xml b/httpclient/pom.xml index b5ccf87a10..9c0cd57d19 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index f3c0589009..e1f005d877 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index 3e8dd5daef..a733366798 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index a1f5f2b3ad..bc1eb4011c 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index 3bed5201dd..c3f6520416 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index 7a66128ed0..f00778e28f 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 0d992c5158..84505402be 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index a2dcc3ade6..2d21ae3713 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 9d9db921df..3e7a16d399 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index 7d8949d48f..b4a8b97de4 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 3f35a80f53..294bf526fc 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index a1e3c801c5..561046981e 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 0e3193bb0d..6c1f41aca3 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 2b8f6defd1..2d2e4a3bb1 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 2e8e847a2d..169095489c 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index a3d5857bc0..a78c53d6e5 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index c53fb2d6c8..bf5d2d2767 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index 97896b3c9b..cf767530f2 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 81fb5c5c45..006e7ea606 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index 30963523e1..a28dc7e54e 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-okhttp diff --git a/pom.xml b/pom.xml index 5afb6b3601..cdb57878e0 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 9b6da88b97..65ba529b01 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index a4723450dc..aaeb03fd28 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index 071c4ace14..d83fb5b162 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index 54fb06d0a1..ae3fe95dbb 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 99ba3ad6ad..377f6b4398 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 382a46ea81..1450e2ccba 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 6c225e178b..06dd1e03d6 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index faf785491e..797c3fd78c 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-spring4 diff --git a/validation-jakarta/pom.xml b/validation-jakarta/pom.xml index ee695e787f..a2fd4eb4f3 100644 --- a/validation-jakarta/pom.xml +++ b/validation-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-validation-jakarta diff --git a/validation/pom.xml b/validation/pom.xml index adc5841f93..32e3f2bbb3 100644 --- a/validation/pom.xml +++ b/validation/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-validation diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index 518822a8b5..bef9ad2652 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.13-SNAPSHOT + 13.13 feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index 8b48f808a7..cd6bfb8dd0 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.13-SNAPSHOT + 13.13 feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 0501998954..efbf9b60ba 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.13-SNAPSHOT + 13.13 feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index 185047b3f1..c4c479ad47 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13-SNAPSHOT + 13.13 feign-vertx-parent From 46a38306e34e5709e5f7134f54864d77be1aaf94 Mon Sep 17 00:00:00 2001 From: velo Date: Sat, 13 Jun 2026 13:56:14 -0300 Subject: [PATCH 576/615] [ci skip] updating versions to next development iteration 13.14-SNAPSHOT --- annotation-error-decoder/pom.xml | 2 +- apt-test-generator/pom.xml | 2 +- benchmark/pom.xml | 2 +- core/pom.xml | 2 +- dropwizard-metrics4/pom.xml | 2 +- dropwizard-metrics5/pom.xml | 2 +- example-github-with-coroutine/pom.xml | 2 +- example-github/pom.xml | 2 +- example-wikipedia-with-springboot/pom.xml | 2 +- example-wikipedia/pom.xml | 2 +- fastjson2/pom.xml | 2 +- feign-bom/pom.xml | 90 +++++++++++------------ form-spring/pom.xml | 2 +- form/pom.xml | 2 +- googlehttpclient/pom.xml | 2 +- graphql-apt/pom.xml | 2 +- graphql/pom.xml | 2 +- gson/pom.xml | 2 +- hc5/pom.xml | 2 +- http-cache/pom.xml | 2 +- httpclient/pom.xml | 2 +- hystrix/pom.xml | 2 +- jackson-jaxb/pom.xml | 2 +- jackson-jr/pom.xml | 2 +- jackson/pom.xml | 2 +- jackson3/pom.xml | 2 +- jakarta/pom.xml | 2 +- java11/pom.xml | 2 +- jaxb-jakarta/pom.xml | 2 +- jaxb/pom.xml | 2 +- jaxrs/pom.xml | 2 +- jaxrs2/pom.xml | 2 +- jaxrs3/pom.xml | 2 +- jaxrs4/pom.xml | 2 +- json/pom.xml | 2 +- kotlin/pom.xml | 2 +- micrometer/pom.xml | 2 +- mock/pom.xml | 2 +- moshi/pom.xml | 2 +- okhttp/pom.xml | 2 +- pom.xml | 2 +- reactive/pom.xml | 2 +- ribbon/pom.xml | 2 +- sax/pom.xml | 2 +- slf4j/pom.xml | 2 +- soap-jakarta/pom.xml | 2 +- soap/pom.xml | 2 +- spring/pom.xml | 2 +- spring4/pom.xml | 2 +- validation-jakarta/pom.xml | 2 +- validation/pom.xml | 2 +- vertx/feign-vertx/pom.xml | 2 +- vertx/feign-vertx4-test/pom.xml | 2 +- vertx/feign-vertx5-test/pom.xml | 2 +- vertx/pom.xml | 2 +- 55 files changed, 99 insertions(+), 99 deletions(-) diff --git a/annotation-error-decoder/pom.xml b/annotation-error-decoder/pom.xml index 486fb8ab6f..f6ef0447f9 100644 --- a/annotation-error-decoder/pom.xml +++ b/annotation-error-decoder/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-annotation-error-decoder diff --git a/apt-test-generator/pom.xml b/apt-test-generator/pom.xml index 22786640b5..1617a5effb 100644 --- a/apt-test-generator/pom.xml +++ b/apt-test-generator/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT io.github.openfeign.experimental diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 0ec4819be7..1114211299 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-benchmark diff --git a/core/pom.xml b/core/pom.xml index c437c066d1..f33eed07af 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-core diff --git a/dropwizard-metrics4/pom.xml b/dropwizard-metrics4/pom.xml index fdad3983e7..834db1a745 100644 --- a/dropwizard-metrics4/pom.xml +++ b/dropwizard-metrics4/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-dropwizard-metrics4 Feign Dropwizard Metrics4 diff --git a/dropwizard-metrics5/pom.xml b/dropwizard-metrics5/pom.xml index ba23ee0790..03633fdff4 100644 --- a/dropwizard-metrics5/pom.xml +++ b/dropwizard-metrics5/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-dropwizard-metrics5 Feign Dropwizard Metrics5 diff --git a/example-github-with-coroutine/pom.xml b/example-github-with-coroutine/pom.xml index 186a1adee0..af9e97ccc8 100644 --- a/example-github-with-coroutine/pom.xml +++ b/example-github-with-coroutine/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-example-github-with-coroutine diff --git a/example-github/pom.xml b/example-github/pom.xml index 52f9bdd403..5f38c01dd9 100644 --- a/example-github/pom.xml +++ b/example-github/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-example-github diff --git a/example-wikipedia-with-springboot/pom.xml b/example-wikipedia-with-springboot/pom.xml index d93d37099c..066b63d52c 100644 --- a/example-wikipedia-with-springboot/pom.xml +++ b/example-wikipedia-with-springboot/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-example-wikipedia-with-springboot diff --git a/example-wikipedia/pom.xml b/example-wikipedia/pom.xml index 4e18d0bd7b..014bfdd0a3 100644 --- a/example-wikipedia/pom.xml +++ b/example-wikipedia/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT io.github.openfeign diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml index ac9f0cacb3..8b1ae28bb0 100644 --- a/fastjson2/pom.xml +++ b/fastjson2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-fastjson2 diff --git a/feign-bom/pom.xml b/feign-bom/pom.xml index 51941b4a36..6ba3f81610 100644 --- a/feign-bom/pom.xml +++ b/feign-bom/pom.xml @@ -28,7 +28,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT ../pom.xml @@ -42,222 +42,222 @@ io.github.openfeign feign-core - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-gson - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-http-cache - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jaxrs - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-httpclient - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jaxrs2 - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-hc5 - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-hystrix - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jackson - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jackson3 - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jackson-jaxb - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jackson-jr - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jaxb - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jaxb-jakarta - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jaxrs3 - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jaxrs4 - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-java11 - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-jakarta - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-mock - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-json - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-okhttp - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-googlehttpclient - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-ribbon - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-sax - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-slf4j - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-spring - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-soap - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-soap-jakarta - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-reactive-wrappers - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-micrometer - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-dropwizard-metrics4 - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-dropwizard-metrics5 - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-kotlin - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-graphql - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-annotation-error-decoder - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-form - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-form-spring - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-moshi - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-fastjson2 - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-validation - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-validation-jakarta - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-vertx - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-vertx4-test - 13.13 + 13.14-SNAPSHOT io.github.openfeign feign-vertx5-test - 13.13 + 13.14-SNAPSHOT diff --git a/form-spring/pom.xml b/form-spring/pom.xml index ce4bf7aaa4..cb08616583 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-form-spring diff --git a/form/pom.xml b/form/pom.xml index aad3e05cc5..b248eecfb2 100644 --- a/form/pom.xml +++ b/form/pom.xml @@ -23,7 +23,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-form diff --git a/googlehttpclient/pom.xml b/googlehttpclient/pom.xml index 9f9997552b..c653ac1f31 100644 --- a/googlehttpclient/pom.xml +++ b/googlehttpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-googlehttpclient diff --git a/graphql-apt/pom.xml b/graphql-apt/pom.xml index d316c1a8bf..10d645fa64 100644 --- a/graphql-apt/pom.xml +++ b/graphql-apt/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT io.github.openfeign.experimental diff --git a/graphql/pom.xml b/graphql/pom.xml index b540524a3f..9d931fcdd8 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-graphql diff --git a/gson/pom.xml b/gson/pom.xml index 33bfafc1e1..eadea8b124 100644 --- a/gson/pom.xml +++ b/gson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-gson diff --git a/hc5/pom.xml b/hc5/pom.xml index 83ec9ffd6f..30a538f44a 100644 --- a/hc5/pom.xml +++ b/hc5/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-hc5 diff --git a/http-cache/pom.xml b/http-cache/pom.xml index 6388223cc4..c6ef73808f 100644 --- a/http-cache/pom.xml +++ b/http-cache/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-http-cache diff --git a/httpclient/pom.xml b/httpclient/pom.xml index 9c0cd57d19..a24f5671b7 100644 --- a/httpclient/pom.xml +++ b/httpclient/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-httpclient diff --git a/hystrix/pom.xml b/hystrix/pom.xml index e1f005d877..42cf19cf49 100644 --- a/hystrix/pom.xml +++ b/hystrix/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-hystrix diff --git a/jackson-jaxb/pom.xml b/jackson-jaxb/pom.xml index a733366798..5d0ab9493f 100644 --- a/jackson-jaxb/pom.xml +++ b/jackson-jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jackson-jaxb diff --git a/jackson-jr/pom.xml b/jackson-jr/pom.xml index bc1eb4011c..33e15c76fc 100644 --- a/jackson-jr/pom.xml +++ b/jackson-jr/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jackson-jr diff --git a/jackson/pom.xml b/jackson/pom.xml index c3f6520416..e5f58a13eb 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jackson diff --git a/jackson3/pom.xml b/jackson3/pom.xml index f00778e28f..f95ab2587f 100644 --- a/jackson3/pom.xml +++ b/jackson3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jackson3 diff --git a/jakarta/pom.xml b/jakarta/pom.xml index 84505402be..b026ef1a50 100644 --- a/jakarta/pom.xml +++ b/jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jakarta diff --git a/java11/pom.xml b/java11/pom.xml index 2d21ae3713..15b342e11a 100644 --- a/java11/pom.xml +++ b/java11/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-java11 diff --git a/jaxb-jakarta/pom.xml b/jaxb-jakarta/pom.xml index 3e7a16d399..bfb3501e93 100644 --- a/jaxb-jakarta/pom.xml +++ b/jaxb-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jaxb-jakarta diff --git a/jaxb/pom.xml b/jaxb/pom.xml index b4a8b97de4..7e45e66109 100644 --- a/jaxb/pom.xml +++ b/jaxb/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jaxb diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml index 294bf526fc..3647078c3e 100644 --- a/jaxrs/pom.xml +++ b/jaxrs/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jaxrs diff --git a/jaxrs2/pom.xml b/jaxrs2/pom.xml index 561046981e..c583e9fe8f 100644 --- a/jaxrs2/pom.xml +++ b/jaxrs2/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jaxrs2 diff --git a/jaxrs3/pom.xml b/jaxrs3/pom.xml index 6c1f41aca3..1d3960ab52 100644 --- a/jaxrs3/pom.xml +++ b/jaxrs3/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jaxrs3 diff --git a/jaxrs4/pom.xml b/jaxrs4/pom.xml index 2d2e4a3bb1..397f4ea1a3 100644 --- a/jaxrs4/pom.xml +++ b/jaxrs4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-jaxrs4 diff --git a/json/pom.xml b/json/pom.xml index 169095489c..759208abb6 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-json diff --git a/kotlin/pom.xml b/kotlin/pom.xml index a78c53d6e5..8200b3135b 100644 --- a/kotlin/pom.xml +++ b/kotlin/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-kotlin diff --git a/micrometer/pom.xml b/micrometer/pom.xml index bf5d2d2767..e4f85282a6 100644 --- a/micrometer/pom.xml +++ b/micrometer/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-micrometer Feign Micrometer diff --git a/mock/pom.xml b/mock/pom.xml index cf767530f2..5fef7b967e 100644 --- a/mock/pom.xml +++ b/mock/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-mock diff --git a/moshi/pom.xml b/moshi/pom.xml index 006e7ea606..a46bc101bb 100644 --- a/moshi/pom.xml +++ b/moshi/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-moshi diff --git a/okhttp/pom.xml b/okhttp/pom.xml index a28dc7e54e..159ed7329d 100644 --- a/okhttp/pom.xml +++ b/okhttp/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-okhttp diff --git a/pom.xml b/pom.xml index cdb57878e0..5da5e97db3 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT pom Feign (Parent) diff --git a/reactive/pom.xml b/reactive/pom.xml index 65ba529b01..f22ef9272f 100644 --- a/reactive/pom.xml +++ b/reactive/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-reactive-wrappers diff --git a/ribbon/pom.xml b/ribbon/pom.xml index aaeb03fd28..7fb261e1ca 100644 --- a/ribbon/pom.xml +++ b/ribbon/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-ribbon diff --git a/sax/pom.xml b/sax/pom.xml index d83fb5b162..131ba32b80 100644 --- a/sax/pom.xml +++ b/sax/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-sax diff --git a/slf4j/pom.xml b/slf4j/pom.xml index ae3fe95dbb..3e5a8befb7 100644 --- a/slf4j/pom.xml +++ b/slf4j/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-slf4j diff --git a/soap-jakarta/pom.xml b/soap-jakarta/pom.xml index 377f6b4398..cfb055cf7b 100644 --- a/soap-jakarta/pom.xml +++ b/soap-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-soap-jakarta diff --git a/soap/pom.xml b/soap/pom.xml index 1450e2ccba..2ea09d44c8 100644 --- a/soap/pom.xml +++ b/soap/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-soap diff --git a/spring/pom.xml b/spring/pom.xml index 06dd1e03d6..359db0a448 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-spring diff --git a/spring4/pom.xml b/spring4/pom.xml index 797c3fd78c..27f7358c92 100644 --- a/spring4/pom.xml +++ b/spring4/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-spring4 diff --git a/validation-jakarta/pom.xml b/validation-jakarta/pom.xml index a2fd4eb4f3..91aec5f039 100644 --- a/validation-jakarta/pom.xml +++ b/validation-jakarta/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-validation-jakarta diff --git a/validation/pom.xml b/validation/pom.xml index 32e3f2bbb3..7aacc6e42f 100644 --- a/validation/pom.xml +++ b/validation/pom.xml @@ -22,7 +22,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-validation diff --git a/vertx/feign-vertx/pom.xml b/vertx/feign-vertx/pom.xml index bef9ad2652..5dc883e661 100644 --- a/vertx/feign-vertx/pom.xml +++ b/vertx/feign-vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.13 + 13.14-SNAPSHOT feign-vertx diff --git a/vertx/feign-vertx4-test/pom.xml b/vertx/feign-vertx4-test/pom.xml index cd6bfb8dd0..f3467662a7 100644 --- a/vertx/feign-vertx4-test/pom.xml +++ b/vertx/feign-vertx4-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.13 + 13.14-SNAPSHOT feign-vertx4-test diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index efbf9b60ba..4f9d853346 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-vertx-parent - 13.13 + 13.14-SNAPSHOT feign-vertx5-test diff --git a/vertx/pom.xml b/vertx/pom.xml index c4c479ad47..fbee5079b1 100644 --- a/vertx/pom.xml +++ b/vertx/pom.xml @@ -21,7 +21,7 @@ io.github.openfeign feign-parent - 13.13 + 13.14-SNAPSHOT feign-vertx-parent From f1e142673aa634d3af348ee0961107e726806119 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 05:14:52 +0000 Subject: [PATCH 577/615] build(deps): Bump org.hibernate.validator:hibernate-validator Bumps [org.hibernate.validator:hibernate-validator](https://github.com/hibernate/hibernate-validator) from 6.2.5.Final to 9.1.0.Final. - [Release notes](https://github.com/hibernate/hibernate-validator/releases) - [Changelog](https://github.com/hibernate/hibernate-validator/blob/main/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-validator/compare/6.2.5.Final...9.1.0.Final) --- updated-dependencies: - dependency-name: org.hibernate.validator:hibernate-validator dependency-version: 9.1.0.Final dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5da5e97db3..86228b4199 100644 --- a/pom.xml +++ b/pom.xml @@ -237,7 +237,7 @@ 2.3.1 2.0.1.Final 3.1.1 - 6.2.5.Final + 9.1.0.Final 9.1.0.Final 3.0.4 6.0.0 From c99bc9b08e3f546e2b94b1d8bdb29337cf8afe5f Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 15 Jun 2026 11:26:05 -0300 Subject: [PATCH 578/615] build(deps): import spring-boot-dependencies BOM to pin spring-boot artifacts to springboot.version Signed-off-by: Marvin Froeder --- pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pom.xml b/pom.xml index 66519298cd..7f02218d28 100644 --- a/pom.xml +++ b/pom.xml @@ -460,6 +460,14 @@ ${project.version} + + org.springframework.boot + spring-boot-dependencies + ${springboot.version} + pom + import + + org.junit junit-bom From e47fed56bd83bbd5f825005b3e91df2b48755594 Mon Sep 17 00:00:00 2001 From: Marvin Froeder Date: Mon, 15 Jun 2026 11:36:07 -0300 Subject: [PATCH 579/615] build(deps): scope spring-boot-dependencies BOM to form-spring to avoid disturbing other modules Signed-off-by: Marvin Froeder --- form-spring/pom.xml | 12 ++++++++++++ pom.xml | 8 -------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/form-spring/pom.xml b/form-spring/pom.xml index cb08616583..5561fb99fd 100644 --- a/form-spring/pom.xml +++ b/form-spring/pom.xml @@ -35,6 +35,18 @@ true + + + + org.springframework.boot + spring-boot-dependencies + ${springboot.version} + pom + import + + + + org.apache.commons diff --git a/pom.xml b/pom.xml index e8fb492279..84dc5f3e84 100644 --- a/pom.xml +++ b/pom.xml @@ -460,14 +460,6 @@ ${project.version} - - org.springframework.boot - spring-boot-dependencies - ${springboot.version} - pom - import - - org.junit junit-bom From 3dc2070bb74f160731522bd974fcb4a97ea7d65f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2026 05:12:51 +0000 Subject: [PATCH 580/615] build(deps-dev): Bump org.sonatype.central:central-publishing-maven-plugin Bumps [org.sonatype.central:central-publishing-maven-plugin](https://github.com/sonatype/central-publishing-maven-plugin) from 0.10.0 to 0.11.0. - [Commits](https://github.com/sonatype/central-publishing-maven-plugin/commits) --- updated-dependencies: - dependency-name: org.sonatype.central:central-publishing-maven-plugin dependency-version: 0.11.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 84dc5f3e84..82a0e40125 100644 --- a/pom.xml +++ b/pom.xml @@ -191,7 +191,7 @@ 3.3.1 6.0.2 0.1.1 - 0.10.0 + 0.11.0 3.5.6 0.300.0 file://${project.basedir}/src/config/bom.xml From 83f1896b70a7ab6b49a49c4f25d76909e343fc5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2026 05:13:03 +0000 Subject: [PATCH 581/615] build(deps): Bump com.github.jknack:handlebars from 4.5.1 to 4.5.2 Bumps [com.github.jknack:handlebars](https://github.com/jknack/handlebars.java) from 4.5.1 to 4.5.2. - [Release notes](https://github.com/jknack/handlebars.java/releases) - [Commits](https://github.com/jknack/handlebars.java/compare/v4.5.1...v4.5.2) --- updated-dependencies: - dependency-name: com.github.jknack:handlebars dependency-version: 4.5.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 84dc5f3e84..652eb428be 100644 --- a/pom.xml +++ b/pom.xml @@ -220,7 +220,7 @@ 1.15.0 0.23.0 26.0 - 4.5.1 + 4.5.2 4.5.14 5.6.1 1.13.0 From 47e99c111c74ab9942db5f6bb4329610c27f6b3e Mon Sep 17 00:00:00 2001 From: velo Date: Wed, 17 Jun 2026 08:17:36 -0300 Subject: [PATCH 582/615] Keep javax validation on Hibernate Validator 6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 86228b4199..5da5e97db3 100644 --- a/pom.xml +++ b/pom.xml @@ -237,7 +237,7 @@ 2.3.1 2.0.1.Final 3.1.1 - 9.1.0.Final + 6.2.5.Final 9.1.0.Final 3.0.4 6.0.0 From 39c4f41bac791fd7de77b0a751604d21e0886b85 Mon Sep 17 00:00:00 2001 From: seonwoojung Date: Wed, 17 Jun 2026 20:20:41 +0900 Subject: [PATCH 583/615] Honor jdk.httpclient.allowRestrictedHeaders in Http2Client (#2975) (#3419) The new Java HttpClient lets callers opt in to setting otherwise restricted headers (such as Host) via the jdk.httpclient.allowRestrictedHeaders system property. Http2Client kept its own static DISALLOWED_HEADERS_SET and stripped those headers before handing the request to the JDK client, so the opt-in had no effect and the header was silently dropped. Mirror jdk.internal.net.http.common.Utils#getDisallowedHeaders() by removing any headers listed in the property from the disallowed set. Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com> --- .../java/feign/http2client/Http2Client.java | 19 ++++++-- .../http2client/Http2ClientHeadersTest.java | 43 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 java11/src/test/java/feign/http2client/Http2ClientHeadersTest.java diff --git a/java11/src/main/java/feign/http2client/Http2Client.java b/java11/src/main/java/feign/http2client/Http2Client.java index 40d4548a22..8b59bfb310 100644 --- a/java11/src/main/java/feign/http2client/Http2Client.java +++ b/java11/src/main/java/feign/http2client/Http2Client.java @@ -242,13 +242,26 @@ private Builder newRequestBuilder(Request request, Options options) throws URISy * * @see jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET */ - private static final Set DISALLOWED_HEADERS_SET; + private static final Set DISALLOWED_HEADERS_SET = + disallowedHeaders(System.getProperty("jdk.httpclient.allowRestrictedHeaders")); - static { + /** + * Builds the set of headers the underlying JDK HttpClient refuses to send. Mirrors {@code + * jdk.internal.net.http.common.Utils#getDisallowedHeaders()}: headers listed (comma separated) in + * the {@code jdk.httpclient.allowRestrictedHeaders} system property are removed from the set, so + * that callers who opt in at the JDK level (e.g. to set {@code Host}) are not silently filtered + * out here as well. + */ + static Set disallowedHeaders(String allowRestrictedHeaders) { // A case insensitive TreeSet of strings. final TreeSet treeSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); treeSet.addAll(Set.of("connection", "content-length", "expect", "host", "upgrade")); - DISALLOWED_HEADERS_SET = Collections.unmodifiableSet(treeSet); + if (allowRestrictedHeaders != null) { + for (String header : allowRestrictedHeaders.split(",")) { + treeSet.remove(header.trim()); + } + } + return Collections.unmodifiableSet(treeSet); } private Map> filterRestrictedHeaders( diff --git a/java11/src/test/java/feign/http2client/Http2ClientHeadersTest.java b/java11/src/test/java/feign/http2client/Http2ClientHeadersTest.java new file mode 100644 index 0000000000..a185d033e8 --- /dev/null +++ b/java11/src/test/java/feign/http2client/Http2ClientHeadersTest.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.http2client; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class Http2ClientHeadersTest { + + @Test + void filtersAllRestrictedHeadersByDefault() { + assertThat(Http2Client.disallowedHeaders(null)) + .contains("connection", "content-length", "expect", "host", "upgrade"); + } + + @Test + void allowsHeaderListedInSystemProperty() { + assertThat(Http2Client.disallowedHeaders("host")) + .doesNotContain("host") + .contains("connection", "content-length", "expect", "upgrade"); + } + + @Test + void allowsMultipleHeadersCaseInsensitivelyAndIgnoresWhitespace() { + assertThat(Http2Client.disallowedHeaders("Host, Connection")) + .doesNotContain("host", "connection") + .contains("content-length", "expect", "upgrade"); + } +} From 8694ed6a118dc038954aaa948e0a943aeceb8eb3 Mon Sep 17 00:00:00 2001 From: alhuda <50839256+alhudz@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:50:52 +0530 Subject: [PATCH 584/615] escape crlf and quotes in multipart content-disposition headers (#3417) --- .../feign/form/multipart/AbstractWriter.java | 21 +++++++- .../form/multipart/SingleParameterWriter.java | 2 +- .../form/multipart/AbstractWriterTest.java | 49 +++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 form/src/test/java/feign/form/multipart/AbstractWriterTest.java diff --git a/form/src/main/java/feign/form/multipart/AbstractWriter.java b/form/src/main/java/feign/form/multipart/AbstractWriter.java index 3062505197..d445974a36 100644 --- a/form/src/main/java/feign/form/multipart/AbstractWriter.java +++ b/form/src/main/java/feign/form/multipart/AbstractWriter.java @@ -64,10 +64,14 @@ protected void writeFileMetadata( val contentDespositionBuilder = new StringBuilder() .append("Content-Disposition: form-data; name=\"") - .append(name) + .append(escapeHeaderParameter(name)) .append("\""); if (fileName != null) { - contentDespositionBuilder.append("; ").append("filename=\"").append(fileName).append("\""); + contentDespositionBuilder + .append("; ") + .append("filename=\"") + .append(escapeHeaderParameter(fileName)) + .append("\""); } String fileContentType = contentType; @@ -94,4 +98,17 @@ protected void writeFileMetadata( output.write(string); } + + /** + * Escapes a {@code multipart/form-data} header parameter value so an attacker-supplied name or + * file name cannot break out of the quoted string and inject extra headers or part boundaries. + * Carriage return, line feed and double quote are percent-encoded, matching the WHATWG form-data + * encoding rules. + * + * @param value the raw parameter value. + * @return the escaped value, safe to place inside a quoted header parameter. + */ + protected static String escapeHeaderParameter(String value) { + return value.replace("\r", "%0D").replace("\n", "%0A").replace("\"", "%22"); + } } diff --git a/form/src/main/java/feign/form/multipart/SingleParameterWriter.java b/form/src/main/java/feign/form/multipart/SingleParameterWriter.java index d9c978cadf..c20c0ff1b6 100644 --- a/form/src/main/java/feign/form/multipart/SingleParameterWriter.java +++ b/form/src/main/java/feign/form/multipart/SingleParameterWriter.java @@ -37,7 +37,7 @@ protected void write(Output output, String key, Object value) throws EncodeExcep val string = new StringBuilder() .append("Content-Disposition: form-data; name=\"") - .append(key) + .append(escapeHeaderParameter(key)) .append('"') .append(CRLF) .append("Content-Type: text/plain; charset=") diff --git a/form/src/test/java/feign/form/multipart/AbstractWriterTest.java b/form/src/test/java/feign/form/multipart/AbstractWriterTest.java new file mode 100644 index 0000000000..05e40094cf --- /dev/null +++ b/form/src/test/java/feign/form/multipart/AbstractWriterTest.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.form.multipart; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.assertj.core.api.Assertions.assertThat; + +import feign.form.FormData; +import org.junit.jupiter.api.Test; + +class AbstractWriterTest { + + @Test + void fileNameWithCrlfAndQuoteIsEscaped() { + Output output = new Output(UTF_8); + FormData formData = + new FormData("text/plain", "evil\"\r\nX-Injected: 1", "body".getBytes(UTF_8)); + + new FormDataWriter().write(output, "boundary", "file", formData); + String written = new String(output.toByteArray(), UTF_8); + + assertThat(written).contains("filename=\"evil%22%0D%0AX-Injected: 1\""); + assertThat(written).doesNotContain("\r\nX-Injected: 1"); + } + + @Test + void parameterNameWithCrlfIsEscaped() { + Output output = new Output(UTF_8); + + new SingleParameterWriter().write(output, "boundary", "a\"\r\nX-Injected: 1", "value"); + String written = new String(output.toByteArray(), UTF_8); + + assertThat(written).contains("name=\"a%22%0D%0AX-Injected: 1\""); + assertThat(written).doesNotContain("\r\nX-Injected: 1"); + } +} From 3f233b97fdbb7bac4fc6de5500096c29657670db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 05:12:22 +0000 Subject: [PATCH 585/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.37.0 to 3.38.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.37.0...v3.38.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.38.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5465e9161a..d71320b1af 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ 1.2.8 4.0.0 6.41.0 - 3.37.0 + 3.38.0 3.36.0 0.26.1 1.0 From 1a47cede2fd445a37f34a4698c5b6e680baa48af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 05:13:22 +0000 Subject: [PATCH 586/615] build(deps): Bump org.hibernate.validator:hibernate-validator Bumps [org.hibernate.validator:hibernate-validator](https://github.com/hibernate/hibernate-validator) from 6.2.5.Final to 9.1.0.Final. - [Release notes](https://github.com/hibernate/hibernate-validator/releases) - [Changelog](https://github.com/hibernate/hibernate-validator/blob/main/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-validator/compare/6.2.5.Final...9.1.0.Final) --- updated-dependencies: - dependency-name: org.hibernate.validator:hibernate-validator dependency-version: 9.1.0.Final dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5465e9161a..d8e60d39f4 100644 --- a/pom.xml +++ b/pom.xml @@ -237,7 +237,7 @@ 2.3.1 2.0.1.Final 3.1.1 - 6.2.5.Final + 9.1.0.Final 9.1.0.Final 3.0.4 6.0.0 From a9bf809cddfb55430af58bcfa04475e9c0cf4165 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 05:24:30 +0000 Subject: [PATCH 587/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.41.0 to 6.42.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.41.0...v6.42.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.42.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d71320b1af..1684a52724 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,7 @@ 3.2.0 1.2.8 4.0.0 - 6.41.0 + 6.42.0 3.38.0 3.36.0 0.26.1 From dc0525d51dbc4a30695c8bd150510c38bd963584 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 05:24:51 +0000 Subject: [PATCH 588/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.36.0 to 3.37.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.36.0...v3.37.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.37.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d71320b1af..b1181d6f0c 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ 4.0.0 6.41.0 3.38.0 - 3.36.0 + 3.37.0 0.26.1 1.0 From 35609a1bda8a30232e046001c334fb6b7416970c Mon Sep 17 00:00:00 2001 From: velo Date: Thu, 18 Jun 2026 08:17:17 -0300 Subject: [PATCH 589/615] Keep javax validation on compatible provider --- pom.xml | 4 ++-- validation-jakarta/pom.xml | 2 +- validation/pom.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index d8e60d39f4..15c9e17d7c 100644 --- a/pom.xml +++ b/pom.xml @@ -237,8 +237,8 @@ 2.3.1 2.0.1.Final 3.1.1 - 9.1.0.Final - 9.1.0.Final + 6.2.5.Final + 9.1.0.Final 3.0.4 6.0.0 1.19.4 diff --git a/validation-jakarta/pom.xml b/validation-jakarta/pom.xml index 91aec5f039..2a34260bcf 100644 --- a/validation-jakarta/pom.xml +++ b/validation-jakarta/pom.xml @@ -58,7 +58,7 @@ org.hibernate.validator hibernate-validator - ${hibernate-validator-8.version} + ${hibernate-validator-jakarta.version} test diff --git a/validation/pom.xml b/validation/pom.xml index 7aacc6e42f..65ca7898b9 100644 --- a/validation/pom.xml +++ b/validation/pom.xml @@ -52,7 +52,7 @@ org.hibernate.validator hibernate-validator - ${hibernate-validator-6.version} + ${hibernate-validator-javax.version} test From db9ae4b451448dd9cc3ef3bdd150feff1ff81e40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 05:13:02 +0000 Subject: [PATCH 590/615] build(deps): Bump org.hibernate.validator:hibernate-validator Bumps [org.hibernate.validator:hibernate-validator](https://github.com/hibernate/hibernate-validator) from 6.2.5.Final to 9.1.0.Final. - [Release notes](https://github.com/hibernate/hibernate-validator/releases) - [Changelog](https://github.com/hibernate/hibernate-validator/blob/main/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-validator/compare/6.2.5.Final...9.1.0.Final) --- updated-dependencies: - dependency-name: org.hibernate.validator:hibernate-validator dependency-version: 9.1.0.Final dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3fd3304d2f..d6cd1421c0 100644 --- a/pom.xml +++ b/pom.xml @@ -237,7 +237,7 @@ 2.3.1 2.0.1.Final 3.1.1 - 6.2.5.Final + 9.1.0.Final 9.1.0.Final 3.0.4 6.0.0 From 9d7ffef247f1421947e31c6d08f40b76935cf886 Mon Sep 17 00:00:00 2001 From: velo Date: Fri, 19 Jun 2026 08:16:02 -0300 Subject: [PATCH 591/615] Keep javax validation on Hibernate Validator 6 --- .github/dependabot.yml | 3 +++ pom.xml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index fa14f951f4..d25a05febb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -24,6 +24,9 @@ updates: # SAAJ impl at 1.x (soap) and 3.x (soap-jakarta) - dependency-name: "com.sun.xml.messaging.saaj:saaj-impl" update-types: ["version-update:semver-major"] + # feign-validation is intentionally on javax.validation; Hibernate Validator 7+ is Jakarta-only. + - dependency-name: "org.hibernate.validator:hibernate-validator" + update-types: ["version-update:semver-major"] # Jersey 2.x for jaxrs2 - package-ecosystem: "maven" diff --git a/pom.xml b/pom.xml index d6cd1421c0..3fd3304d2f 100644 --- a/pom.xml +++ b/pom.xml @@ -237,7 +237,7 @@ 2.3.1 2.0.1.Final 3.1.1 - 9.1.0.Final + 6.2.5.Final 9.1.0.Final 3.0.4 6.0.0 From 247fb46def599ec82e29dd5332bf53600a65ed0e Mon Sep 17 00:00:00 2001 From: alhuda <50839256+alhudz@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:48:56 +0530 Subject: [PATCH 592/615] fall back to utf-8 for invalid content-type charset (#3427) Response.charset() and feign-form's FormEncoder.getCharset() passed the parsed charset token straight to Charset.forName, so an unsupported or illegal name from a Content-Type header threw instead of using the documented UTF-8 default. Catch the charset exceptions in both and fall back to UTF-8, as FeignException.getResponseCharset already does. --- core/src/main/java/feign/Response.java | 8 ++- core/src/test/java/feign/ResponseTest.java | 30 +++++++++++ .../src/main/java/feign/form/FormEncoder.java | 11 +++- .../feign/form/FormEncoderCharsetTest.java | 53 +++++++++++++++++++ 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 form/src/test/java/feign/form/FormEncoderCharsetTest.java diff --git a/core/src/main/java/feign/Response.java b/core/src/main/java/feign/Response.java index 2bf64d56e2..c1b175ced8 100644 --- a/core/src/main/java/feign/Response.java +++ b/core/src/main/java/feign/Response.java @@ -20,7 +20,9 @@ import feign.Request.ProtocolVersion; import java.io.*; import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.StandardCharsets; +import java.nio.charset.UnsupportedCharsetException; import java.util.*; /** An immutable response to an http invocation which only returns string content. */ @@ -219,7 +221,11 @@ public Charset charset() { String[] charsetParts = contentTypeParmeters[1].split("="); if (charsetParts.length == 2 && "charset".equalsIgnoreCase(charsetParts[0].trim())) { String charsetString = charsetParts[1].replaceAll("\"", ""); - return Charset.forName(charsetString); + try { + return Charset.forName(charsetString); + } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { + return Util.UTF_8; + } } } } diff --git a/core/src/test/java/feign/ResponseTest.java b/core/src/test/java/feign/ResponseTest.java index 9af1ceb887..e781bce669 100644 --- a/core/src/test/java/feign/ResponseTest.java +++ b/core/src/test/java/feign/ResponseTest.java @@ -87,6 +87,36 @@ void charsetSupportsMediaTypesWithQuotedCharset() { assertThat(response.charset()).isEqualTo(Util.UTF_8); } + @Test + void charsetDefaultsToUtf8ForIllegalCharsetName() { + Map> headersMap = new LinkedHashMap<>(); + headersMap.put("Content-Type", Collections.singletonList("text/plain; charset=@")); + Response response = + Response.builder() + .status(200) + .headers(headersMap) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .body(new byte[0]) + .build(); + assertThat(response.charset()).isEqualTo(Util.UTF_8); + } + + @Test + void charsetDefaultsToUtf8ForUnsupportedCharset() { + Map> headersMap = new LinkedHashMap<>(); + headersMap.put("Content-Type", Collections.singletonList("text/plain; charset=made-up-99")); + Response response = + Response.builder() + .status(200) + .headers(headersMap) + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .body(new byte[0]) + .build(); + assertThat(response.charset()).isEqualTo(Util.UTF_8); + } + @Test void headerValuesWithSameNameOnlyVaryingInCaseAreMerged() { Map> headersMap = new LinkedHashMap<>(); diff --git a/form/src/main/java/feign/form/FormEncoder.java b/form/src/main/java/feign/form/FormEncoder.java index e01e24976c..fb05cde7cd 100644 --- a/form/src/main/java/feign/form/FormEncoder.java +++ b/form/src/main/java/feign/form/FormEncoder.java @@ -27,6 +27,8 @@ import feign.codec.Encoder; import java.lang.reflect.Type; import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -130,6 +132,13 @@ private String getContentTypeValue(Map> headers) { private Charset getCharset(String contentTypeValue) { val matcher = CHARSET_PATTERN.matcher(contentTypeValue); - return matcher.find() ? Charset.forName(matcher.group(1)) : UTF_8; + if (!matcher.find()) { + return UTF_8; + } + try { + return Charset.forName(matcher.group(1)); + } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { + return UTF_8; + } } } diff --git a/form/src/test/java/feign/form/FormEncoderCharsetTest.java b/form/src/test/java/feign/form/FormEncoderCharsetTest.java new file mode 100644 index 0000000000..d100fa65bc --- /dev/null +++ b/form/src/test/java/feign/form/FormEncoderCharsetTest.java @@ -0,0 +1,53 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.form; + +import static org.assertj.core.api.Assertions.assertThat; + +import feign.RequestTemplate; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class FormEncoderCharsetTest { + + @Test + void illegalCharsetInContentTypeFallsBackToUtf8() { + RequestTemplate template = new RequestTemplate(); + template.header("Content-Type", "application/x-www-form-urlencoded; charset=_bad"); + + Map data = new LinkedHashMap<>(); + data.put("foo", "bar"); + + new FormEncoder().encode(data, Map.class, template); + + assertThat(new String(template.body(), StandardCharsets.UTF_8)).isEqualTo("foo=bar"); + } + + @Test + void unsupportedCharsetInContentTypeFallsBackToUtf8() { + RequestTemplate template = new RequestTemplate(); + template.header("Content-Type", "application/x-www-form-urlencoded; charset=made-up-99"); + + Map data = new LinkedHashMap<>(); + data.put("foo", "bar"); + + new FormEncoder().encode(data, Map.class, template); + + assertThat(new String(template.body(), StandardCharsets.UTF_8)).isEqualTo("foo=bar"); + } +} From 837dcd575f0840750b6683db413c0a06a4cc7268 Mon Sep 17 00:00:00 2001 From: seonwoojung Date: Fri, 19 Jun 2026 20:19:29 +0900 Subject: [PATCH 593/615] Make Expressions max length configurable (#3422) The maximum length of a single template expression was hard-coded to 10000 characters in feign.template.Expressions, throwing IllegalArgumentException for anything longer with no way to opt out. Make the limit configurable through the "feign.template.expression.maxLength" system property (default 10000), and allow disabling the check entirely by setting it to a non-positive value. Fixes #2916 Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com> --- .../main/java/feign/template/Expressions.java | 21 ++++++++-- .../java/feign/template/ExpressionsTest.java | 40 +++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/feign/template/Expressions.java b/core/src/main/java/feign/template/Expressions.java index 65fa5123e2..1368364d59 100644 --- a/core/src/main/java/feign/template/Expressions.java +++ b/core/src/main/java/feign/template/Expressions.java @@ -25,7 +25,14 @@ public final class Expressions { - private static final int MAX_EXPRESSION_LENGTH = 10000; + /** + * System property controlling the maximum allowed length of a single expression. Defaults to + * {@link #DEFAULT_MAX_EXPRESSION_LENGTH}. Setting it to {@code 0} (or any non-positive value) + * disables the length check entirely. + */ + static final String MAX_EXPRESSION_LENGTH_PROPERTY = "feign.template.expression.maxLength"; + + private static final int DEFAULT_MAX_EXPRESSION_LENGTH = 10000; private static final String PATH_STYLE_OPERATOR = ";"; @@ -73,10 +80,16 @@ public static Expression create(final String value) { throw new IllegalArgumentException("an expression is required."); } - /* Check if the expression is too long */ - if (expression.length() > MAX_EXPRESSION_LENGTH) { + /* + * Check if the expression is too long. The limit is configurable through the + * "feign.template.expression.maxLength" system property and can be disabled by setting it to a + * non-positive value. + */ + final int maxExpressionLength = + Integer.getInteger(MAX_EXPRESSION_LENGTH_PROPERTY, DEFAULT_MAX_EXPRESSION_LENGTH); + if (maxExpressionLength > 0 && expression.length() > maxExpressionLength) { throw new IllegalArgumentException( - "expression is too long. Max length: " + MAX_EXPRESSION_LENGTH); + "expression is too long. Max length: " + maxExpressionLength); } /* create a new regular expression matcher for the expression */ diff --git a/core/src/test/java/feign/template/ExpressionsTest.java b/core/src/test/java/feign/template/ExpressionsTest.java index 0586bd231e..77241770f5 100644 --- a/core/src/test/java/feign/template/ExpressionsTest.java +++ b/core/src/test/java/feign/template/ExpressionsTest.java @@ -16,13 +16,53 @@ package feign.template; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatObject; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.Collections; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; class ExpressionsTest { + @AfterEach + void clearMaxExpressionLengthProperty() { + System.clearProperty(Expressions.MAX_EXPRESSION_LENGTH_PROPERTY); + } + + @Test + void tooLongExpressionFailsWithDefaultLimit() { + String tooLong = "{" + "a".repeat(10001) + "}"; + assertThatThrownBy(() -> Expressions.create(tooLong)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("expression is too long"); + } + + @Test + void maxExpressionLengthIsConfigurable() { + System.setProperty(Expressions.MAX_EXPRESSION_LENGTH_PROPERTY, "5"); + assertThatThrownBy(() -> Expressions.create("{foobar}")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Max length: 5"); + } + + @Test + void lengthCheckCanBeDisabled() { + // An expression well beyond the default 10000 limit, expressed as a name plus a regular + // expression value modifier so the disabled length check is exercised in isolation. + String longExpression = "{name:" + "a".repeat(15000) + "}"; + assertThatThrownBy(() -> Expressions.create(longExpression)) + .as("guarded by default limit") + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("expression is too long"); + + System.setProperty(Expressions.MAX_EXPRESSION_LENGTH_PROPERTY, "0"); + assertThatNoException() + .as("length check disabled") + .isThrownBy(() -> Expressions.create(longExpression)); + } + @Test void simpleExpression() { Expression expression = Expressions.create("{foo}"); From bd7a5377fdf1e6519e072402d0f7dc751514c663 Mon Sep 17 00:00:00 2001 From: seonwoojung Date: Fri, 19 Jun 2026 20:20:01 +0900 Subject: [PATCH 594/615] Preserve delegate content type for multipart parameters (#3382) `DelegateWriter` encodes a parameter through the delegate `Encoder` (e.g. the Jackson encoder), which sets the correct `Content-Type` (such as `application/json`) on the throwaway `RequestTemplate`. That header was discarded and `SingleParameterWriter` hard-coded `text/plain`, so JSON parts of a multipart request were emitted as `text/plain`. `DelegateWriter` now reads the `Content-Type` produced by the delegate and passes it through to `SingleParameterWriter.writeWithContentType`, falling back to `text/plain; charset=` when the delegate sets no content type. The previous behaviour for plain single parameters is unchanged. Fixes #2813 Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) --- .../feign/form/multipart/DelegateWriter.java | 14 ++++- .../form/multipart/SingleParameterWriter.java | 21 ++++++- .../form/multipart/DelegateWriterTest.java | 57 +++++++++++++++++++ 3 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 form/src/test/java/feign/form/multipart/DelegateWriterTest.java diff --git a/form/src/main/java/feign/form/multipart/DelegateWriter.java b/form/src/main/java/feign/form/multipart/DelegateWriter.java index 7161c21a46..17620d77f6 100644 --- a/form/src/main/java/feign/form/multipart/DelegateWriter.java +++ b/form/src/main/java/feign/form/multipart/DelegateWriter.java @@ -48,6 +48,18 @@ protected void write(Output output, String key, Object value) throws EncodeExcep delegate.encode(value, value.getClass(), fake); val bytes = fake.body(); val string = new String(bytes, output.getCharset()).replaceAll("\n", ""); - parameterWriter.write(output, key, string); + parameterWriter.writeWithContentType(output, key, string, contentType(fake)); + } + + private static String contentType(RequestTemplate template) { + val headers = template.headers().get("Content-Type"); + if (headers != null) { + for (val header : headers) { + if (header != null && !header.isEmpty()) { + return header; + } + } + } + return null; } } diff --git a/form/src/main/java/feign/form/multipart/SingleParameterWriter.java b/form/src/main/java/feign/form/multipart/SingleParameterWriter.java index c20c0ff1b6..55eab20204 100644 --- a/form/src/main/java/feign/form/multipart/SingleParameterWriter.java +++ b/form/src/main/java/feign/form/multipart/SingleParameterWriter.java @@ -34,14 +34,31 @@ public boolean isApplicable(Object value) { @Override protected void write(Output output, String key, Object value) throws EncodeException { + writeWithContentType(output, key, value, null); + } + + /** + * Writes a single parameter using the given content type. + * + * @param output output writer. + * @param key name for piece of data. + * @param value piece of data. + * @param contentType the content type of the part. May be {@code null}, in which case {@code + * text/plain} with the output charset is used. + * @throws EncodeException in case of write errors + */ + protected void writeWithContentType(Output output, String key, Object value, String contentType) + throws EncodeException { + val contentTypeHeader = + contentType != null ? contentType : "text/plain; charset=" + output.getCharset().name(); val string = new StringBuilder() .append("Content-Disposition: form-data; name=\"") .append(escapeHeaderParameter(key)) .append('"') .append(CRLF) - .append("Content-Type: text/plain; charset=") - .append(output.getCharset().name()) + .append("Content-Type: ") + .append(contentTypeHeader) .append(CRLF) .append(CRLF) .append(value.toString()) diff --git a/form/src/test/java/feign/form/multipart/DelegateWriterTest.java b/form/src/test/java/feign/form/multipart/DelegateWriterTest.java new file mode 100644 index 0000000000..365cfe9d0e --- /dev/null +++ b/form/src/test/java/feign/form/multipart/DelegateWriterTest.java @@ -0,0 +1,57 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.form.multipart; + +import static org.assertj.core.api.Assertions.assertThat; + +import feign.codec.Encoder; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +class DelegateWriterTest { + + private static final String BOUNDARY = "boundary"; + + private static final String KEY = "metadata"; + + @Test + void usesContentTypeFromDelegate() throws Exception { + Encoder delegate = + (object, bodyType, template) -> { + template.header("Content-Type", "application/json"); + template.body("{\"hash\":\"somehash\"}"); + }; + + assertThat(write(delegate)) + .contains("Content-Type: application/json") + .doesNotContain("Content-Type: text/plain"); + } + + @Test + void fallsBackToTextPlainWhenDelegateSetsNoContentType() throws Exception { + Encoder delegate = (object, bodyType, template) -> template.body("plain"); + + assertThat(write(delegate)).contains("Content-Type: text/plain; charset=UTF-8"); + } + + private static String write(Encoder delegate) throws Exception { + DelegateWriter writer = new DelegateWriter(delegate); + try (Output output = new Output(StandardCharsets.UTF_8)) { + writer.write(output, BOUNDARY, KEY, new Object()); + return new String(output.toByteArray(), StandardCharsets.UTF_8); + } + } +} From 425cc8177c31c5cb4375d49f6c11e46e1cc6e8a0 Mon Sep 17 00:00:00 2001 From: alhuda <50839256+alhudz@users.noreply.github.com> Date: Sat, 20 Jun 2026 16:45:46 +0530 Subject: [PATCH 595/615] cap Content-Length before narrowing to int in Http2Client (#3431) --- .../java/feign/http2client/Http2Client.java | 6 +- .../Http2ClientContentLengthTest.java | 113 ++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 java11/src/test/java/feign/http2client/Http2ClientContentLengthTest.java diff --git a/java11/src/main/java/feign/http2client/Http2Client.java b/java11/src/main/java/feign/http2client/Http2Client.java index 8b59bfb310..9eb718df97 100644 --- a/java11/src/main/java/feign/http2client/Http2Client.java +++ b/java11/src/main/java/feign/http2client/Http2Client.java @@ -130,6 +130,10 @@ public CompletableFuture execute( protected Response toFeignResponse(Request request, HttpResponse httpResponse) { final OptionalLong length = httpResponse.headers().firstValueAsLong("Content-Length"); + final Integer contentLength = + length.isPresent() && length.getAsLong() >= 0 && length.getAsLong() <= Integer.MAX_VALUE + ? (int) length.getAsLong() + : null; InputStream body = httpResponse.body(); @@ -144,7 +148,7 @@ protected Response toFeignResponse(Request request, HttpResponse ht return Response.builder() .protocolVersion(enumForName(ProtocolVersion.class, httpResponse.version())) - .body(body, length.isPresent() ? (int) length.getAsLong() : null) + .body(body, contentLength) .reason(httpResponse.headers().firstValue("Reason-Phrase").orElse(null)) .request(request) .status(httpResponse.statusCode()) diff --git a/java11/src/test/java/feign/http2client/Http2ClientContentLengthTest.java b/java11/src/test/java/feign/http2client/Http2ClientContentLengthTest.java new file mode 100644 index 0000000000..ff6ed83fa5 --- /dev/null +++ b/java11/src/test/java/feign/http2client/Http2ClientContentLengthTest.java @@ -0,0 +1,113 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.http2client; + +import static org.assertj.core.api.Assertions.assertThat; + +import feign.Request; +import feign.Request.HttpMethod; +import feign.Response; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.URI; +import java.net.http.HttpClient.Version; +import java.net.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import javax.net.ssl.SSLSession; +import org.junit.jupiter.api.Test; + +class Http2ClientContentLengthTest { + + private static HttpResponse responseWithContentLength(String contentLength) { + final HttpHeaders headers = + HttpHeaders.of(Map.of("Content-Length", List.of(contentLength)), (name, value) -> true); + return new HttpResponse<>() { + @Override + public int statusCode() { + return 200; + } + + @Override + public HttpRequest request() { + return null; + } + + @Override + public Optional> previousResponse() { + return Optional.empty(); + } + + @Override + public HttpHeaders headers() { + return headers; + } + + @Override + public InputStream body() { + return new ByteArrayInputStream(new byte[0]); + } + + @Override + public Optional sslSession() { + return Optional.empty(); + } + + @Override + public URI uri() { + return URI.create("http://localhost"); + } + + @Override + public Version version() { + return Version.HTTP_2; + } + }; + } + + private static Response decode(String contentLength) { + final Request request = + Request.create( + HttpMethod.GET, + "http://localhost", + Collections.emptyMap(), + null, + StandardCharsets.UTF_8, + null); + return new Http2Client().toFeignResponse(request, responseWithContentLength(contentLength)); + } + + @Test + void contentLengthAboveIntMaxIsReportedAsUnknown() { + // 2^31, a valid Content-Length larger than Integer.MAX_VALUE + assertThat(decode("2147483648").body().length()).isNull(); + } + + @Test + void negativeContentLengthIsReportedAsUnknown() { + assertThat(decode("-1").body().length()).isNull(); + } + + @Test + void contentLengthWithinIntRangeIsPreserved() { + assertThat(decode("1024").body().length()).isEqualTo(1024); + } +} From 0a250fd90a37ec87085a4d59ecb94ceecd9c3d8a Mon Sep 17 00:00:00 2001 From: alhuda <50839256+alhudz@users.noreply.github.com> Date: Sat, 20 Jun 2026 16:46:02 +0530 Subject: [PATCH 596/615] generate multipart boundary from SecureRandom (#3429) --- .../form/MultipartFormContentProcessor.java | 16 ++++- .../feign/form/MultipartBoundaryTest.java | 59 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 form/src/test/java/feign/form/MultipartBoundaryTest.java diff --git a/form/src/main/java/feign/form/MultipartFormContentProcessor.java b/form/src/main/java/feign/form/MultipartFormContentProcessor.java index af31d36eb6..2a38dc6d6b 100644 --- a/form/src/main/java/feign/form/MultipartFormContentProcessor.java +++ b/form/src/main/java/feign/form/MultipartFormContentProcessor.java @@ -33,6 +33,7 @@ import feign.form.multipart.Writer; import java.io.IOException; import java.nio.charset.Charset; +import java.security.SecureRandom; import java.util.Collection; import java.util.Collections; import java.util.Deque; @@ -49,6 +50,8 @@ @FieldDefaults(level = PRIVATE, makeFinal = true) public class MultipartFormContentProcessor implements ContentProcessor { + private static final SecureRandom RANDOM = new SecureRandom(); + Deque writers; Writer defaultPerocessor; @@ -75,7 +78,7 @@ public MultipartFormContentProcessor(Encoder delegate) { @Override public void process(RequestTemplate template, Charset charset, Map data) throws EncodeException { - val boundary = Long.toHexString(System.currentTimeMillis()); + val boundary = randomBoundary(); try (val output = new Output(charset)) { for (val entry : data.entrySet()) { if (entry == null || entry.getKey() == null || entry.getValue() == null) { @@ -158,4 +161,15 @@ private Writer findApplicableWriter(Object value) { } return defaultPerocessor; } + + private static String randomBoundary() { + val token = new byte[16]; + RANDOM.nextBytes(token); + val builder = new StringBuilder(token.length * 2); + for (val octet : token) { + builder.append(Character.forDigit((octet >> 4) & 0xF, 16)); + builder.append(Character.forDigit(octet & 0xF, 16)); + } + return builder.toString(); + } } diff --git a/form/src/test/java/feign/form/MultipartBoundaryTest.java b/form/src/test/java/feign/form/MultipartBoundaryTest.java new file mode 100644 index 0000000000..26399fcdc6 --- /dev/null +++ b/form/src/test/java/feign/form/MultipartBoundaryTest.java @@ -0,0 +1,59 @@ +/* + * Copyright © 2012 The Feign Authors (feign@commonhaus.dev) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feign.form; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.assertj.core.api.Assertions.assertThat; + +import feign.RequestTemplate; +import feign.codec.Encoder; +import java.util.LinkedHashMap; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class MultipartBoundaryTest { + + private static final Encoder NOOP_DELEGATE = (object, bodyType, template) -> {}; + + @Test + void boundaryIsNotDerivedFromTheClock() { + long before = System.currentTimeMillis(); + String boundary = generateBoundary(); + long after = System.currentTimeMillis(); + + for (long millis = before; millis <= after; millis++) { + assertThat(boundary).isNotEqualTo(Long.toHexString(millis)); + } + } + + @Test + void boundaryDiffersBetweenRequests() { + assertThat(generateBoundary()).isNotEqualTo(generateBoundary()); + } + + private static String generateBoundary() { + MultipartFormContentProcessor processor = new MultipartFormContentProcessor(NOOP_DELEGATE); + RequestTemplate template = new RequestTemplate(); + + Map data = new LinkedHashMap<>(); + data.put("field", "value"); + processor.process(template, UTF_8, data); + + String contentType = template.headers().get("Content-Type").iterator().next(); + int index = contentType.indexOf("boundary="); + return contentType.substring(index + "boundary=".length()); + } +} From 265c6570d90170371c7b42ec0d788519678bf98b Mon Sep 17 00:00:00 2001 From: alhuda <50839256+alhudz@users.noreply.github.com> Date: Sun, 21 Jun 2026 16:44:46 +0530 Subject: [PATCH 597/615] strip crlf from multipart content-type header (#3432) --- .../feign/form/multipart/AbstractWriter.java | 15 ++++++++++- .../form/multipart/SingleParameterWriter.java | 2 +- .../form/multipart/AbstractWriterTest.java | 25 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/form/src/main/java/feign/form/multipart/AbstractWriter.java b/form/src/main/java/feign/form/multipart/AbstractWriter.java index d445974a36..0869430145 100644 --- a/form/src/main/java/feign/form/multipart/AbstractWriter.java +++ b/form/src/main/java/feign/form/multipart/AbstractWriter.java @@ -89,7 +89,7 @@ protected void writeFileMetadata( .append(contentDespositionBuilder.toString()) .append(CRLF) .append("Content-Type: ") - .append(fileContentType) + .append(stripCrlf(fileContentType)) .append(CRLF) .append("Content-Transfer-Encoding: binary") .append(CRLF) @@ -111,4 +111,17 @@ protected void writeFileMetadata( protected static String escapeHeaderParameter(String value) { return value.replace("\r", "%0D").replace("\n", "%0A").replace("\"", "%22"); } + + /** + * Removes carriage return and line feed from a media type so an attacker-supplied content type + * cannot inject extra part headers or boundaries. Unlike a quoted parameter the {@code + * Content-Type} value is not quoted, so it cannot be percent-encoded without corrupting a + * legitimate media type; the control characters are dropped instead. + * + * @param contentType the raw content type value. + * @return the content type with CR and LF removed. + */ + protected static String stripCrlf(String contentType) { + return contentType.replace("\r", "").replace("\n", ""); + } } diff --git a/form/src/main/java/feign/form/multipart/SingleParameterWriter.java b/form/src/main/java/feign/form/multipart/SingleParameterWriter.java index 55eab20204..0866ee2ada 100644 --- a/form/src/main/java/feign/form/multipart/SingleParameterWriter.java +++ b/form/src/main/java/feign/form/multipart/SingleParameterWriter.java @@ -58,7 +58,7 @@ protected void writeWithContentType(Output output, String key, Object value, Str .append('"') .append(CRLF) .append("Content-Type: ") - .append(contentTypeHeader) + .append(stripCrlf(contentTypeHeader)) .append(CRLF) .append(CRLF) .append(value.toString()) diff --git a/form/src/test/java/feign/form/multipart/AbstractWriterTest.java b/form/src/test/java/feign/form/multipart/AbstractWriterTest.java index 05e40094cf..5b00f778f2 100644 --- a/form/src/test/java/feign/form/multipart/AbstractWriterTest.java +++ b/form/src/test/java/feign/form/multipart/AbstractWriterTest.java @@ -46,4 +46,29 @@ void parameterNameWithCrlfIsEscaped() { assertThat(written).contains("name=\"a%22%0D%0AX-Injected: 1\""); assertThat(written).doesNotContain("\r\nX-Injected: 1"); } + + @Test + void fileContentTypeWithCrlfIsStripped() { + Output output = new Output(UTF_8); + FormData formData = + new FormData("text/plain\r\nX-Injected: 1", "file.txt", "body".getBytes(UTF_8)); + + new FormDataWriter().write(output, "boundary", "file", formData); + String written = new String(output.toByteArray(), UTF_8); + + assertThat(written).contains("Content-Type: text/plainX-Injected: 1"); + assertThat(written).doesNotContain("\r\nX-Injected: 1"); + } + + @Test + void parameterContentTypeWithCrlfIsStripped() { + Output output = new Output(UTF_8); + + new SingleParameterWriter() + .writeWithContentType(output, "name", "value", "text/plain\r\nX-Injected: 1"); + String written = new String(output.toByteArray(), UTF_8); + + assertThat(written).contains("Content-Type: text/plainX-Injected: 1"); + assertThat(written).doesNotContain("\r\nX-Injected: 1"); + } } From d05f71a07112c459fe720cd9dbdcdea14f4b5a0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 05:13:20 +0000 Subject: [PATCH 598/615] build(deps-dev): Bump com.gradle:develocity-maven-extension Bumps com.gradle:develocity-maven-extension from 2.4.1 to 2.4.2. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: 2.4.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 1c05e35670..bfbb33c261 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.4.1 + 2.4.2 com.gradle From d32f2082b1f1962ae401147252ec6dd776a83d2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 05:13:27 +0000 Subject: [PATCH 599/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.38.0 to 3.40.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.38.0...v3.40.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.40.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3fd3304d2f..68a5c2be71 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ 1.2.8 4.0.0 6.42.0 - 3.38.0 + 3.40.0 3.37.0 0.26.1 1.0 From 711fa7ae02cb5b0f4fec43ebbdd9b7ee8a03f112 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 05:13:08 +0000 Subject: [PATCH 600/615] build(deps-dev): Bump vertx.version in /vertx/feign-vertx5-test Bumps `vertx.version` from 5.1.2 to 5.1.3. Updates `io.vertx:vertx-junit5` from 5.1.2 to 5.1.3 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/5.1.2...5.1.3) Updates `io.vertx:vertx-web-client` from 5.1.2 to 5.1.3 - [Commits](https://github.com/vert-x3/vertx-web/compare/5.1.2...5.1.3) --- updated-dependencies: - dependency-name: io.vertx:vertx-junit5 dependency-version: 5.1.3 dependency-type: direct:development update-type: version-update:semver-patch - dependency-name: io.vertx:vertx-web-client dependency-version: 5.1.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vertx/feign-vertx5-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vertx/feign-vertx5-test/pom.xml b/vertx/feign-vertx5-test/pom.xml index 4f9d853346..2798249acf 100644 --- a/vertx/feign-vertx5-test/pom.xml +++ b/vertx/feign-vertx5-test/pom.xml @@ -30,7 +30,7 @@ Tests with Vertx 5.x. - 5.1.2 + 5.1.3 From b46b35126c2d1ba955904eee7e3b1bb9ec101279 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 05:15:09 +0000 Subject: [PATCH 601/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.37.0 to 3.38.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.37.0...v3.38.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.38.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 68a5c2be71..279862715e 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ 4.0.0 6.42.0 3.40.0 - 3.37.0 + 3.38.0 0.26.1 1.0 From b547fb5b7e7b75352171ec5915bc6237d6ddf34c Mon Sep 17 00:00:00 2001 From: seonwoojung Date: Tue, 23 Jun 2026 20:14:03 +0900 Subject: [PATCH 602/615] Return response body in FeignException from errorReading (#2618) (#3415) * Return response body in FeignException from errorReading (#2618) FeignException.errorReading passed request.body() and request.headers() into the constructor's responseBody/responseHeaders parameters, so FeignException.responseBody()/contentUTF8()/responseHeaders() exposed the request data instead of the response when a read failure occurred while decoding a response. Read the response body (mirroring errorStatus, tolerating a streamed or already-consumed body) and pass the response headers instead. Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com> * test: assert response body in errorReading FeignException (#2618) The pre-existing throwsFeignException{Including,Without}Body tests in FeignTest, AsyncFeignTest and FeignUnderAsyncTest asserted the old behavior where FeignException.contentUTF8() returned the *request* body on the errorReading path. #2618 corrects this to return the *response* body, so update the assertions accordingly (and enqueue an empty response for the without-body case). Fixes the failing ci/circleci: pr-build. Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com> * test: assert response body in errorReading for async client modules (#2618) The okhttp/java11/hc5 async client tests still asserted the pre-#2618 request body in throwsFeignExceptionIncludingBody, turning ci/circleci: pr-build red. Align them with core to expect the response body, matching the new errorReading behavior. Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com> --------- Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com> --- core/src/main/java/feign/FeignException.java | 11 +++++++++-- core/src/test/java/feign/AsyncFeignTest.java | 3 ++- core/src/test/java/feign/FeignExceptionTest.java | 6 ++++++ core/src/test/java/feign/FeignTest.java | 5 +++-- core/src/test/java/feign/FeignUnderAsyncTest.java | 5 +++-- .../java/feign/hc5/AsyncApacheHttp5ClientTest.java | 3 ++- .../feign/http2client/test/Http2ClientAsyncTest.java | 3 ++- .../test/java/feign/okhttp/OkHttpClientAsyncTest.java | 3 ++- 8 files changed, 29 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/feign/FeignException.java b/core/src/main/java/feign/FeignException.java index b7ea794cae..0779598c61 100644 --- a/core/src/main/java/feign/FeignException.java +++ b/core/src/main/java/feign/FeignException.java @@ -177,13 +177,20 @@ public String contentUTF8() { } static FeignException errorReading(Request request, Response response, IOException cause) { + byte[] body = {}; + try { + if (response.body() != null) { + body = Util.toByteArray(response.body().asInputStream()); + } + } catch (IOException ignored) { // NOPMD + } return new FeignException( response.status(), format("%s reading %s %s", cause.getMessage(), request.httpMethod(), request.url()), request, cause, - request.body(), - request.headers()); + body, + response.headers()); } public static FeignException errorStatus(String methodKey, Response response) { diff --git a/core/src/test/java/feign/AsyncFeignTest.java b/core/src/test/java/feign/AsyncFeignTest.java index 300385be64..a67242b139 100644 --- a/core/src/test/java/feign/AsyncFeignTest.java +++ b/core/src/test/java/feign/AsyncFeignTest.java @@ -621,7 +621,8 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (FeignException e) { assertThat(e.getMessage()) .contains("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + // After #2618 the FeignException carries the response body, not the request body. + assertThat(e.contentUTF8()).isEqualTo("success!"); return; } fail(""); diff --git a/core/src/test/java/feign/FeignExceptionTest.java b/core/src/test/java/feign/FeignExceptionTest.java index f86d35fe19..e585d35e7c 100644 --- a/core/src/test/java/feign/FeignExceptionTest.java +++ b/core/src/test/java/feign/FeignExceptionTest.java @@ -43,16 +43,22 @@ void canCreateWithRequestAndResponse() { StandardCharsets.UTF_8, null); + Map> responseHeaders = + Collections.singletonMap("content-type", Collections.singletonList("application/json")); Response response = Response.builder() .status(400) .body("response".getBytes(StandardCharsets.UTF_8)) + .headers(responseHeaders) .request(request) .build(); FeignException exception = FeignException.errorReading(request, response, new IOException("socket closed")); assertThat(exception.responseBody()).isNotEmpty(); + // the exception must carry the response body, not the request body (gh-2618) + assertThat(exception.contentUTF8()).isEqualTo("response"); + assertThat(exception.responseHeaders()).containsKeys("content-type"); assertThat(exception.hasRequest()).isTrue(); assertThat(exception.request()).isNotNull(); } diff --git a/core/src/test/java/feign/FeignTest.java b/core/src/test/java/feign/FeignTest.java index 47a348bfaf..03acf67a51 100755 --- a/core/src/test/java/feign/FeignTest.java +++ b/core/src/test/java/feign/FeignTest.java @@ -607,13 +607,14 @@ void throwsFeignExceptionIncludingBody() { } catch (FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + // After #2618 the FeignException carries the response body, not the request body. + assertThat(e.contentUTF8()).isEqualTo("success!"); } } @Test void throwsFeignExceptionWithoutBody() { - server.enqueue(new MockResponse().setBody("success!")); + server.enqueue(new MockResponse()); TestInterface api = Feign.builder() diff --git a/core/src/test/java/feign/FeignUnderAsyncTest.java b/core/src/test/java/feign/FeignUnderAsyncTest.java index f18fd5d747..ac150ae370 100644 --- a/core/src/test/java/feign/FeignUnderAsyncTest.java +++ b/core/src/test/java/feign/FeignUnderAsyncTest.java @@ -493,13 +493,14 @@ void throwsFeignExceptionIncludingBody() { } catch (FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + // After #2618 the FeignException carries the response body, not the request body. + assertThat(e.contentUTF8()).isEqualTo("success!"); } } @Test void throwsFeignExceptionWithoutBody() { - server.enqueue(new MockResponse().setBody("success!")); + server.enqueue(new MockResponse()); TestInterface api = AsyncFeign.builder() diff --git a/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java b/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java index 6d5902d9c0..3b3a4f33cf 100644 --- a/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java +++ b/hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java @@ -535,7 +535,8 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (final FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + // After #2618 the FeignException carries the response body, not the request body. + assertThat(e.contentUTF8()).isEqualTo("success!"); return; } fail(""); diff --git a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java index 0d3cd6570b..c5a29c43e9 100644 --- a/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java +++ b/java11/src/test/java/feign/http2client/test/Http2ClientAsyncTest.java @@ -529,7 +529,8 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (final FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + // After #2618 the FeignException carries the response body, not the request body. + assertThat(e.contentUTF8()).isEqualTo("success!"); return; } fail(""); diff --git a/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java b/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java index 79150b86b9..5b2fbe3542 100644 --- a/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java +++ b/okhttp/src/test/java/feign/okhttp/OkHttpClientAsyncTest.java @@ -528,7 +528,8 @@ void throwsFeignExceptionIncludingBody() throws Throwable { } catch (final FeignException e) { assertThat(e.getMessage()) .isEqualTo("timeout reading POST http://localhost:" + server.getPort() + "/"); - assertThat(e.contentUTF8()).isEqualTo("Request body"); + // After #2618 the FeignException carries the response body, not the request body. + assertThat(e.contentUTF8()).isEqualTo("success!"); return; } fail(""); From 5cd6f57e0301b55dc4e953f092e141b59fd8554b Mon Sep 17 00:00:00 2001 From: alhuda <50839256+alhudz@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:46:36 +0530 Subject: [PATCH 603/615] treat invalid expression value modifier as a literal (#3437) --- .../main/java/feign/template/Expressions.java | 28 +++++++++++++------ .../test/java/feign/RequestTemplateTest.java | 11 ++++++++ .../java/feign/template/ExpressionsTest.java | 12 ++++++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/feign/template/Expressions.java b/core/src/main/java/feign/template/Expressions.java index 1368364d59..27b5f5e545 100644 --- a/core/src/main/java/feign/template/Expressions.java +++ b/core/src/main/java/feign/template/Expressions.java @@ -22,6 +22,7 @@ import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; public final class Expressions { @@ -117,15 +118,26 @@ public static Expression create(final String value) { } } - /* check for an operator */ - if (PATH_STYLE_OPERATOR.equalsIgnoreCase(operator)) { - return new PathStyleExpression(variableName, variablePattern); - } + /* + * The value modifier after the ':' is compiled as a regular expression. When the chunk is a + * dynamic value (for example a header-map value that happens to contain '{' and ':') the + * modifier is not a valid pattern, so treat the chunk as a literal instead of letting the + * PatternSyntaxException escape. + */ + try { + /* check for an operator */ + if (PATH_STYLE_OPERATOR.equalsIgnoreCase(operator)) { + return new PathStyleExpression(variableName, variablePattern); + } - /* default to simple */ - return SimpleExpression.isSimpleExpression(value) - ? new SimpleExpression(variableName, variablePattern) - : null; // Return null if it can't be validated as a Simple Expression -- Probably a Literal + /* default to simple */ + // Return null if it can't be validated as a Simple Expression -- Probably a Literal + return SimpleExpression.isSimpleExpression(value) + ? new SimpleExpression(variableName, variablePattern) + : null; + } catch (PatternSyntaxException e) { + return null; + } } private static String stripBraces(String expression) { diff --git a/core/src/test/java/feign/RequestTemplateTest.java b/core/src/test/java/feign/RequestTemplateTest.java index d66b8db289..622e9cf942 100644 --- a/core/src/test/java/feign/RequestTemplateTest.java +++ b/core/src/test/java/feign/RequestTemplateTest.java @@ -218,6 +218,17 @@ void resolveTemplateWithHeaderContainingJsonLiteral() { assertThat(template).hasHeaders(entry("A-Header", Collections.singletonList(json))); } + /** A header-map value containing brackets and a colon must not be parsed as a regex. */ + @Test + void resolveTemplateWithHeaderMapValueContainingPatternModifier() { + String value = "{range:[1:10}"; + RequestTemplate template = + new RequestTemplate().method(HttpMethod.GET).header("A-Header", value); + + template.resolve(new LinkedHashMap<>()); + assertThat(template).hasHeaders(entry("A-Header", Collections.singletonList(value))); + } + @Test void resolveTemplateWithHeaderWithJson() { String json = "{ \"string\": \"val\", \"string2\": \"this should not be truncated\"}"; diff --git a/core/src/test/java/feign/template/ExpressionsTest.java b/core/src/test/java/feign/template/ExpressionsTest.java index 77241770f5..451a3c18a9 100644 --- a/core/src/test/java/feign/template/ExpressionsTest.java +++ b/core/src/test/java/feign/template/ExpressionsTest.java @@ -84,6 +84,18 @@ void malformedExpression() { } } + @Test + void invalidValueModifierIsTreatedAsLiteral() { + // The text after ':' is compiled as a regex; an invalid one must not escape as a + // PatternSyntaxException, the chunk is a literal instead (Expressions.create returns null). + assertThatNoException().isThrownBy(() -> Expressions.create("{range:[1:10}")); + assertThat(Expressions.create("{a:[}")).isNull(); + assertThat(Expressions.create("{a:(}")).isNull(); + + // a valid value modifier still produces an expression + assertThat(Expressions.create("{id:[0-9]+}")).isNotNull(); + } + @Test void malformedBodyTemplate() { String bodyTemplate = "{" + "a".repeat(65536) + "}"; From 3062e80f3d4c951ac7b975b4d73ae215d444f9b4 Mon Sep 17 00:00:00 2001 From: alhuda <50839256+alhudz@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:46:41 +0530 Subject: [PATCH 604/615] encode collection values in urlencoded form bodies (#3436) --- .../feign/form/UrlencodedFormContentProcessor.java | 5 ++++- .../form/UrlencodedFormContentProcessorTest.java | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/form/src/main/java/feign/form/UrlencodedFormContentProcessor.java b/form/src/main/java/feign/form/UrlencodedFormContentProcessor.java index 14fb8166ec..6c82a5c9d2 100644 --- a/form/src/main/java/feign/form/UrlencodedFormContentProcessor.java +++ b/form/src/main/java/feign/form/UrlencodedFormContentProcessor.java @@ -106,7 +106,10 @@ private CharSequence createKeyValuePair( private CharSequence createKeyValuePair( CollectionFormat collectionFormat, String key, Stream values, Charset charset) { val stringValues = - values.filter(Objects::nonNull).map(Object::toString).collect(Collectors.toList()); + values + .filter(Objects::nonNull) + .map(value -> encode(value, charset)) + .collect(Collectors.toList()); return collectionFormat.join(key, stringValues, charset); } } diff --git a/form/src/test/java/feign/form/UrlencodedFormContentProcessorTest.java b/form/src/test/java/feign/form/UrlencodedFormContentProcessorTest.java index 17cf99ea68..be915fab92 100644 --- a/form/src/test/java/feign/form/UrlencodedFormContentProcessorTest.java +++ b/form/src/test/java/feign/form/UrlencodedFormContentProcessorTest.java @@ -46,6 +46,20 @@ void collectionValueUsesDefaultExplodedCollectionFormat() { Arrays.asList("one", "two"), Client::map); } + @Test + void arrayValueEncodesReservedCharacters() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=a%26b%3Dc&tags=d", + new String[] {"a&b=c", "d"}, Client::map); + } + + @Test + void collectionValueEncodesReservedCharacters() { + assertEncodedBody( + "from=%2B987654321&to=%2B123456789&tags=a%26b%3Dc&tags=d", + Arrays.asList("a&b=c", "d"), Client::map); + } + @Test void arrayValueUsesCsvCollectionFormat() { assertEncodedBody( From baeba5a7fa2245fb1987dbce8fbcf1468768445c Mon Sep 17 00:00:00 2001 From: alhuda <50839256+alhudz@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:46:47 +0530 Subject: [PATCH 605/615] encode soap request body with the configured charset (#3433) --- .../src/main/java/feign/soap/SOAPEncoder.java | 2 +- .../test/java/feign/soap/SOAPCodecTest.java | 34 +++++++++++++++++++ .../src/main/java/feign/soap/SOAPEncoder.java | 2 +- .../test/java/feign/soap/SOAPCodecTest.java | 34 +++++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java b/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java index 709b7f2a13..2b4a59cabb 100644 --- a/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java +++ b/soap-jakarta/src/main/java/feign/soap/SOAPEncoder.java @@ -131,7 +131,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) { } else { soapMessage.writeTo(bos); } - template.body(bos.toString()); + template.body(bos.toByteArray(), charsetEncoding); } catch (SOAPException | JAXBException | ParserConfigurationException diff --git a/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java b/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java index 0cbb94be42..d0be7ef62f 100644 --- a/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java +++ b/soap-jakarta/src/test/java/feign/soap/SOAPCodecTest.java @@ -131,6 +131,40 @@ void encodesSoapWithCustomJAXBMarshallerEncoding() { assertThat(template).hasBody(utf16Bytes); } + @Test + void encodesSoapWithNonAsciiContentInConfiguredCharset() { + JAXBContextFactory jaxbContextFactory = + new JAXBContextFactory.Builder().withMarshallerJAXBEncoding("UTF-16").build(); + + Encoder encoder = + new SOAPEncoder.Builder() + .withJAXBContextFactory(jaxbContextFactory) + .withCharsetEncoding(StandardCharsets.UTF_16) + .build(); + + GetPrice mock = new GetPrice(); + mock.item = new Item(); + mock.item.value = "Café"; + + RequestTemplate template = new RequestTemplate(); + encoder.encode(mock, GetPrice.class, template); + + String soapEnvelop = + """ + \ + \ + \ + \ + \ + Café\ + \ + \ + \ + """; + byte[] utf16Bytes = soapEnvelop.getBytes(StandardCharsets.UTF_16LE); + assertThat(template).hasBody(utf16Bytes); + } + @Test void encodesSoapWithCustomJAXBSchemaLocation() { JAXBContextFactory jaxbContextFactory = diff --git a/soap/src/main/java/feign/soap/SOAPEncoder.java b/soap/src/main/java/feign/soap/SOAPEncoder.java index 24f10da917..d22d97fefa 100644 --- a/soap/src/main/java/feign/soap/SOAPEncoder.java +++ b/soap/src/main/java/feign/soap/SOAPEncoder.java @@ -135,7 +135,7 @@ public void encode(Object object, Type bodyType, RequestTemplate template) { } else { soapMessage.writeTo(bos); } - template.body(new String(bos.toByteArray())); + template.body(bos.toByteArray(), charsetEncoding); } catch (SOAPException | JAXBException | ParserConfigurationException diff --git a/soap/src/test/java/feign/soap/SOAPCodecTest.java b/soap/src/test/java/feign/soap/SOAPCodecTest.java index 002a0e33b6..bddc2cdc27 100644 --- a/soap/src/test/java/feign/soap/SOAPCodecTest.java +++ b/soap/src/test/java/feign/soap/SOAPCodecTest.java @@ -131,6 +131,40 @@ void encodesSoapWithCustomJAXBMarshallerEncoding() { assertThat(template).hasBody(utf16Bytes); } + @Test + void encodesSoapWithNonAsciiContentInConfiguredCharset() { + JAXBContextFactory jaxbContextFactory = + new JAXBContextFactory.Builder().withMarshallerJAXBEncoding("UTF-16").build(); + + Encoder encoder = + new SOAPEncoder.Builder() + .withJAXBContextFactory(jaxbContextFactory) + .withCharsetEncoding(StandardCharsets.UTF_16) + .build(); + + GetPrice mock = new GetPrice(); + mock.item = new Item(); + mock.item.value = "Café"; + + RequestTemplate template = new RequestTemplate(); + encoder.encode(mock, GetPrice.class, template); + + String soapEnvelop = + """ + \ + \ + \ + \ + \ + Café\ + \ + \ + \ + """; + byte[] utf16Bytes = soapEnvelop.getBytes(StandardCharsets.UTF_16LE); + assertThat(template).hasBody(utf16Bytes); + } + @Test void encodesSoapWithCustomJAXBSchemaLocation() { JAXBContextFactory jaxbContextFactory = From cf283717787ecc57a3ca4ca0a28a1d3ad1e5bb31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 05:15:35 +0000 Subject: [PATCH 606/615] build(deps-dev): Bump io.undertow:undertow-core Bumps [io.undertow:undertow-core](https://github.com/undertow-io/undertow) from 2.4.1.Final to 2.4.2.Final. - [Release notes](https://github.com/undertow-io/undertow/releases) - [Commits](https://github.com/undertow-io/undertow/compare/2.4.1.Final...2.4.2.Final) --- updated-dependencies: - dependency-name: io.undertow:undertow-core dependency-version: 2.4.2.Final dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 279862715e..84a6a48466 100644 --- a/pom.xml +++ b/pom.xml @@ -254,7 +254,7 @@ 2025.1.2 5.0.2 7.0.8 - 2.4.1.Final + 2.4.2.Final 1.18.0 From 46d604fad649b40c9593c2796fe4853dd44e7cfb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 05:14:22 +0000 Subject: [PATCH 607/615] build(deps): Bump org.junit:junit-bom from 6.1.0 to 6.1.1 Bumps [org.junit:junit-bom](https://github.com/junit-team/junit-framework) from 6.1.0 to 6.1.1. - [Release notes](https://github.com/junit-team/junit-framework/releases) - [Commits](https://github.com/junit-team/junit-framework/compare/r6.1.0...r6.1.1) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-version: 6.1.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 84a6a48466..3783c908f6 100644 --- a/pom.xml +++ b/pom.xml @@ -173,7 +173,7 @@ 20260522 4.1.0 - 6.1.0 + 6.1.1 2.22.0 3.2.0 3.27.7 From 68815c8dbda0597deece78639cdefe16a2b58ea1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 05:12:23 +0000 Subject: [PATCH 608/615] build(deps): Bump org.apache.httpcomponents.client5:httpclient5 Bumps [org.apache.httpcomponents.client5:httpclient5](https://github.com/apache/httpcomponents-client) from 5.6.1 to 5.6.2. - [Changelog](https://github.com/apache/httpcomponents-client/blob/rel/v5.6.2/RELEASE_NOTES.txt) - [Commits](https://github.com/apache/httpcomponents-client/compare/rel/v5.6.1...rel/v5.6.2) --- updated-dependencies: - dependency-name: org.apache.httpcomponents.client5:httpclient5 dependency-version: 5.6.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3783c908f6..66651c98ee 100644 --- a/pom.xml +++ b/pom.xml @@ -222,7 +222,7 @@ 26.0 4.5.2 4.5.14 - 5.6.1 + 5.6.2 1.13.0 1.5.18 3.1.0 From e2ce674637dee19b648dad1ee87a092c4d513dc6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 05:13:06 +0000 Subject: [PATCH 609/615] build(deps): Bump com.gradle:common-custom-user-data-maven-extension Bumps [com.gradle:common-custom-user-data-maven-extension](https://github.com/gradle/common-custom-user-data-maven-extension) from 2.2.0 to 2.3.0. - [Release notes](https://github.com/gradle/common-custom-user-data-maven-extension/releases) - [Commits](https://github.com/gradle/common-custom-user-data-maven-extension/compare/v2.2.0...v2.3.0) --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-maven-extension dependency-version: 2.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index bfbb33c261..827961c116 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -24,6 +24,6 @@ com.gradle common-custom-user-data-maven-extension - 2.2.0 + 2.3.0 From 0181b6934b2ea291809e7d2bcba826bbc8ee0d5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 05:13:31 +0000 Subject: [PATCH 610/615] build(deps): Bump com.google.http-client:google-http-client Bumps [com.google.http-client:google-http-client](https://github.com/googleapis/google-http-java-client) from 2.1.0 to 2.1.1. - [Release notes](https://github.com/googleapis/google-http-java-client/releases) - [Changelog](https://github.com/googleapis/google-http-java-client/blob/main/CHANGELOG.md) - [Commits](https://github.com/googleapis/google-http-java-client/compare/v2.1.0...v2.1.1) --- updated-dependencies: - dependency-name: com.google.http-client:google-http-client dependency-version: 2.1.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3783c908f6..684b96dff5 100644 --- a/pom.xml +++ b/pom.xml @@ -166,7 +166,7 @@ 5.4.0 33.6.0-jre - 2.1.0 + 2.1.1 2.14.0 1.15.2 2.0.18 From b6474fa87fb24442a19cd92a1742107340aa01a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 05:13:02 +0000 Subject: [PATCH 611/615] build(deps): Bump com.github.jknack:handlebars from 4.5.2 to 4.5.3 Bumps [com.github.jknack:handlebars](https://github.com/jknack/handlebars.java) from 4.5.2 to 4.5.3. - [Release notes](https://github.com/jknack/handlebars.java/releases) - [Commits](https://github.com/jknack/handlebars.java/compare/v4.5.2...v4.5.3) --- updated-dependencies: - dependency-name: com.github.jknack:handlebars dependency-version: 4.5.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0f32bc2943..bbd4006377 100644 --- a/pom.xml +++ b/pom.xml @@ -220,7 +220,7 @@ 1.15.0 0.23.0 26.0 - 4.5.2 + 4.5.3 4.5.14 5.6.2 1.13.0 From 7446c1fe38eb5fc873635e07861ba152cabf10bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 05:13:40 +0000 Subject: [PATCH 612/615] build(deps-dev): Bump com.gradle:develocity-maven-extension Bumps com.gradle:develocity-maven-extension from 2.4.2 to 2.5.0. --- updated-dependencies: - dependency-name: com.gradle:develocity-maven-extension dependency-version: 2.5.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .mvn/extensions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index 827961c116..2ce7b7f8ab 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -19,7 +19,7 @@ com.gradle develocity-maven-extension - 2.4.2 + 2.5.0 com.gradle From 00567950adf3e67ccf438c712f4d63572cc8833a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 05:12:19 +0000 Subject: [PATCH 613/615] build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.38.0 to 3.39.0. - [Release notes](https://github.com/openrewrite/rewrite-migrate-java/releases) - [Commits](https://github.com/openrewrite/rewrite-migrate-java/compare/v3.38.0...v3.39.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-migrate-java dependency-version: 3.39.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bbd4006377..44a09f9bcf 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ 4.0.0 6.42.0 3.40.0 - 3.38.0 + 3.39.0 0.26.1 1.0 From f10e817bcc038c2b47830e227fe2653ac256a60e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 05:13:22 +0000 Subject: [PATCH 614/615] build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin Bumps [org.openrewrite.maven:rewrite-maven-plugin](https://github.com/openrewrite/rewrite-maven-plugin) from 6.42.0 to 6.43.0. - [Release notes](https://github.com/openrewrite/rewrite-maven-plugin/releases) - [Commits](https://github.com/openrewrite/rewrite-maven-plugin/compare/v6.42.0...v6.43.0) --- updated-dependencies: - dependency-name: org.openrewrite.maven:rewrite-maven-plugin dependency-version: 6.43.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bbd4006377..d98194b901 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,7 @@ 3.2.0 1.2.8 4.0.0 - 6.42.0 + 6.43.0 3.40.0 3.38.0 0.26.1 From 935954a5fbf8e29507744fc9d2ca5c1fd6ad2534 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 05:24:42 +0000 Subject: [PATCH 615/615] build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks Bumps [org.openrewrite.recipe:rewrite-testing-frameworks](https://github.com/openrewrite/rewrite-testing-frameworks) from 3.40.0 to 3.41.0. - [Release notes](https://github.com/openrewrite/rewrite-testing-frameworks/releases) - [Commits](https://github.com/openrewrite/rewrite-testing-frameworks/compare/v3.40.0...v3.41.0) --- updated-dependencies: - dependency-name: org.openrewrite.recipe:rewrite-testing-frameworks dependency-version: 3.41.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1091737f53..f10551e8fa 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ 1.2.8 4.0.0 6.43.0 - 3.40.0 + 3.41.0 3.39.0 0.26.1 1.0