René's URL Explorer Experiment


Title: Apply review feedback to the multi-encoder and multi-decoder surface by velo · Pull Request #3534 · OpenFeign/feign · GitHub

Open Graph Title: Apply review feedback to the multi-encoder and multi-decoder surface by velo · Pull Request #3534 · OpenFeign/feign

X Title: Apply review feedback to the multi-encoder and multi-decoder surface by velo · Pull Request #3534 · OpenFeign/feign

Description: @trumpetinc's review of #3527, applied to both sides of the codec surface. Everything here is still @Experimental, so this is the moment to move it. Taken A multi-codec is itself predicated. MultiEncoder implements PredicatedEncoder and MultiDecoder implements PredicatedDecoder, accepting whatever any of their delegates accepts, so one nests inside another. That is the composition you asked for — a library can ship a set as a single unit: Feign.builder().encoders(StreamingFeign.encoders(), new JacksonEncoder()); The winning delegate's canEncode is evaluated twice, once by the outer anyMatch and once by the inner loop. Predicates are already documented as cheap and free of side effects, so that is acceptable, but it is worth saying out loud. Nested sets are unfolded in the failure message, so contributing a bundle does not turn it into one opaque line: Encoders tried, in order: - JacksonEncoder - MultiEncoder: - StreamingStringEncoder when the return type is a Stream - StreamingBytesEncoder when Content-Type is application/octet-stream DefaultEncoder and DefaultDecoder declare themselves. You were right and I was wrong: the predicate is not a yes-man, it is exactly what encode/decode handles. This makes raw passthrough composable, which is genuinely useful — a String body reaching Jackson comes out quoted, so putting the default first fixes that: Feign.builder().encoders(new DefaultEncoder(), new JacksonEncoder()); One correction to the predicate you proposed: DefaultEncoder.encode also accepts a null body, which it sends as no body at all. Dropping that case would break @RequestLine("POST /orders") void create(Order order); client.create(null); so the predicate is bodyType == String.class || bodyType == byte[].class || object == null. DefaultDecoder gets the same treatment, including 404/204 and a null body, which it handles for any type. An empty builder fails at wiring time, IllegalStateException from build(), rather than producing a codec that can only ever throw on the first request. encoders()/decoders() with no arguments fail the same way. Builder.narrow(predicate, codec), so the replace/AND pair sits side by side where the difference is visible, and the javadoc on of and narrowing now says which is which in one line. More on that below. The formRequests() javadoc wording, and a note on the FormEncoder(Encoder) constructor that chaining belongs in encoders(...) and the delegate is expected to be deprecated once this surface stops being experimental. Pushed back on narrowing is not redundant with add(predicate, encoder). PredicatedEncoder.of replaces whatever the encoder declares — deliberately, so you can point a GsonEncoder at a vendor content type it would otherwise refuse. narrowing is the AND. Both are needed. That said, the fact that it read as redundant is the finding: the names were not carrying the difference. Hence the builder narrow and the sharper javadoc rather than a rename, since the statics are already published. The failure message reports Content-Type and Accept, not every header. EncodeException messages land in logs and the header map routinely holds Authorization. The detail is not lost — every predicate carries a description and is printed alongside the codec it guards, so a predicate keyed on an unusual header says so itself: .add(EncoderPredicate.describedAs("X-Acme-Format is protobuf", ...), protoEncoder) Unable to encode com.acme.Order (Content-Type: text/plain, Accept: application/json) for POST /orders. Encoders tried, in order: - JacksonEncoder - ProtobufEncoder when X-Acme-Format is protobuf Register an encoder that accepts it, or add a catch-all (EncoderPredicate.any()) last. The hint wording is softened too, since .any() is an implementation detail for anyone who came in through encoders(...). On the decode side the second header is the request's Accept, which is what the caller asked for. Not done DefaultEncoder as a MultiEncoder — you flagged it as an observation rather than a proposal, and I agree it is one. It trades a ten-line class for a list allocation and makes the failure message worse. Centralizing content-type parsing on the parser in #3494 — agreed in principle, but that PR is still open. The Util helpers are @Experimental, so whichever lands second swaps the internals; no need to couple them now. mvn clean install passes.

Open Graph Description: @trumpetinc's review of #3527, applied to both sides of the codec surface. Everything here is still @Experimental, so this is the moment to move it. Taken A multi-codec is itself predicated. Mu...

X Description: @trumpetinc's review of #3527, applied to both sides of the codec surface. Everything here is still @Experimental, so this is the moment to move it. Taken A multi-codec is itself predicated...

Opengraph URL: https://github.com/OpenFeign/feign/pull/3534

X: @github

direct link

Domain: github.com

react-profiling0
react-import-mapreact,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@d5750093facf
route-pattern/:user_id/:repository/pull/:id/files(.:format)
route-controllerpull_requests
route-actionfiles
fetch-noncev2:6f787bd3-8715-f2cc-6329-2a2faa9f48b3
current-catalog-service-hashae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b
request-id89B8:22CA14:120E115:179C981:6AED68B3
html-safe-nonce4563a34aa55d600c9b1a85626635f9fd7fb2c273c09a9856fa3a7cd81369105b
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4OUI4OjIyQ0ExNDoxMjBFMTE1OjE3OUM5ODE6NkFFRDY4QjMiLCJ2aXNpdG9yX2lkIjoiNTMzNDI1MjUwNjE0MzYxNTE1NSIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9
visitor-hmace9a94f21e96d0c418b04978f19d506666c043105eacb0b732ad7fa2e522f5ec7
hovercard-subject-tagpull_request:4333613328
github-keyboard-shortcutsrepository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///pull_requests/show/files
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/OpenFeign/feign/pull/3534/files
twitter:imagehttps://avatars.githubusercontent.com/u/136590?s=400&v=4
twitter:cardsummary_large_image
og:imagehttps://avatars.githubusercontent.com/u/136590?s=400&v=4
og:image:alt@trumpetinc's review of #3527, applied to both sides of the codec surface. Everything here is still @Experimental, so this is the moment to move it. Taken A multi-codec is itself predicated. Mu...
og:site_nameGitHub
og:typeobject
hostnamegithub.com
expected-hostnamegithub.com
None56fb42677ae87ed3e64410323d67980aa65d0485568a7858f874e7edfc6d1c11
turbo-cache-controlno-preview
diff-viewunified
go-importgithub.com/OpenFeign/feign git https://github.com/OpenFeign/feign.git
octolytics-dimension-user_id20077752
octolytics-dimension-user_loginOpenFeign
octolytics-dimension-repository_id10981994
octolytics-dimension-repository_nwoOpenFeign/feign
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id10981994
octolytics-dimension-repository_network_root_nwoOpenFeign/feign
turbo-body-classeslogged-out env-production page-responsive full-width
disable-turbotrue
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release9c9a37e2423ed382cf39f70b5aa4b4858b40a3b0
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://github.com/OpenFeign/feign/pull/3534/files#start-of-content
https://github.com/
Sign inhttps://github.com/login?return_to=https%3A%2F%2Fgithub.com%2FOpenFeign%2Ffeign%2Fpull%2F3534%2Ffiles
GitHubRepository hosting, code review, and collaborationhttps://github.com/platform
CopilotAI coding agent for tasks, projects, and automated workhttps://github.com/features/copilot
ActionsCI/CD and automationhttps://github.com/features/actions
Code QualityQuality analysis, fixes, and enforcementhttps://github.com/features/code-quality
CodespacesCloud development environmentshttps://github.com/features/codespaces
Code SecurityVulnerability detection and remediationhttps://github.com/security/advanced-security/code-security
Secret ProtectionSecret scanning and leak preventionhttps://github.com/security/advanced-security/secret-protection
All Featureshttps://github.com/features
Documentationhttps://docs.github.com/en
Traininghttps://learn.github.com/skills
Certificationshttps://learn.github.com/credentials
Build with Copilothttps://github.com/features/ai
Customize Copilothttps://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/customize-copilot-overview
Integrationshttps://github.com/marketplace
Trending reposhttps://github.com/trending
GitHub Sponsorshttps://github.com/open-source/sponsors
Developer articleshttps://github.com/resources/articles
ChangelogYour source for the latest features, improvements, and fixes across GitHub products, all in one place.https://github.blog/changelog/
Enterpriseshttps://github.com/enterprise
Teamhttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
See all industrieshttps://github.com/solutions/industry
Why GitHubhttps://github.com/why-github
Customer Storieshttps://github.com/customer-stories
Business insightshttps://github.com/solutions/executive-insights
Trust Centerhttps://github.com/trust-center
GitHub Advanced SecurityEnterprise-grade code securityhttps://github.com/security/advanced-security
Copilot for businessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/enterprise/premium-support
Documentationhttps://docs.github.com/en
Resource centerhttps://github.com/resources
Bloghttps://github.blog/
Events & webinarshttps://github.com/resources/events
Community Forumhttps://github.com/orgs/community/discussions
Customer Storieshttps://github.com/customer-stories
Integrationshttps://github.com/marketplace
Customer supporthttps://help.github.com/
Traininghttps://learn.github.com/skills
GitHub Statushttps://www.githubstatus.com/
Abouthttps://github.com/about
Partnershttps://github.com/partners
Changeloghttps://github.blog/changelog/
GitHub UniverseThe event for developers, by developers — talks, workshops, and what’s next for GitHub.https://githubuniverse.com/
Pricinghttps://github.com/pricing
Sign inhttps://github.com/login?return_to=https%3A%2F%2Fgithub.com%2FOpenFeign%2Ffeign%2Fpull%2F3534%2Ffiles
Sign uphttps://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fpull_requests%2Fshow%2Ffiles&source=header-repo&source_repo=OpenFeign%2Ffeign
Reloadhttps://github.com/OpenFeign/feign/pull/3534/files
Reloadhttps://github.com/OpenFeign/feign/pull/3534/files
Reloadhttps://github.com/OpenFeign/feign/pull/3534/files
OpenFeignhttps://github.com/OpenFeign
feignhttps://github.com/OpenFeign/feign
Codehttps://github.com/OpenFeign/feign
Issues209 (209)https://github.com/OpenFeign/feign/issues
Pull requests26 (26)https://github.com/OpenFeign/feign/pulls
Actionshttps://github.com/OpenFeign/feign/actions
Projectshttps://github.com/OpenFeign/feign/projects
Wikihttps://github.com/OpenFeign/feign/wiki
Security and qualityhttps://github.com/OpenFeign/feign/security
Insightshttps://github.com/OpenFeign/feign/pulse
Sign up for GitHub https://github.com/signup?return_to=%2FOpenFeign%2Ffeign%2Fissues%2Fnew%2Fchoose
terms of servicehttps://docs.github.com/terms
privacy statementhttps://docs.github.com/privacy
Sign inhttps://github.com/login?return_to=%2FOpenFeign%2Ffeign%2Fissues%2Fnew%2Fchoose
velohttps://github.com/velo
masterhttps://github.com/OpenFeign/feign/tree/master
feat/multi-codec-review-followuphttps://github.com/OpenFeign/feign/tree/feat/multi-codec-review-followup
Conversation 10 https://github.com/OpenFeign/feign/pull/3534
Commits 2 https://github.com/OpenFeign/feign/pull/3534/commits
Checks 1 https://github.com/OpenFeign/feign/pull/3534/checks
Files changed https://github.com/OpenFeign/feign/pull/3534/files
Please reload this pagehttps://github.com/OpenFeign/feign/pull/3534/files
Apply review feedback to the multi-encoder and multi-decoder surface https://github.com/OpenFeign/feign/pull/3534/files#top
Show all changes 2 commits https://github.com/OpenFeign/feign/pull/3534/files
0440cc3 Apply review feedback to the multi-encoder and multi-decoder surface velo Aug 21, 2026 https://github.com/OpenFeign/feign/pull/3534/commits/0440cc3bf280facd11432432a0f2e40c6bcedc9d
ff0352f Make StringDecoder predicated and clarify the multi-codec docs velo Aug 25, 2026 https://github.com/OpenFeign/feign/pull/3534/commits/ff0352fba08eee703a753f580edbeefa63260790
Clear filters https://github.com/OpenFeign/feign/pull/3534/files
Please reload this pagehttps://github.com/OpenFeign/feign/pull/3534/files
Please reload this pagehttps://github.com/OpenFeign/feign/pull/3534/files
Util.java https://github.com/OpenFeign/feign/pull/3534/files#diff-9bc6e3a76f6bf178a35e883f72bf2492ef18cac9a1ff48973533469cbda9247a
DefaultDecoder.java https://github.com/OpenFeign/feign/pull/3534/files#diff-0142600050b7f9e7485450d8420cd611f09832c0deadf60e3a18dcc8960f5b5c
DefaultEncoder.java https://github.com/OpenFeign/feign/pull/3534/files#diff-03f1282371bb6b2c8d577eb3e9f95d37dc0f86e3845d0e9be84241341e450dcc
MultiDecoder.java https://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
MultiEncoder.java https://github.com/OpenFeign/feign/pull/3534/files#diff-e9facb5268144332a339ac5dc17cbd0749f5c131179b3cee1b3dd99eba379eaa
PredicatedDecoder.java https://github.com/OpenFeign/feign/pull/3534/files#diff-a6e04c469344c3d422f34cec5663bbedfb6114c0853572238ed3aa1df90d2e17
PredicatedEncoder.java https://github.com/OpenFeign/feign/pull/3534/files#diff-286625d26c809bf05e2a49c2b15eb237836937a9beb2daea4acab4ca7e73f6c7
StringDecoder.java https://github.com/OpenFeign/feign/pull/3534/files#diff-6f66094ceed36379c4a03299fc933e478e7a4dca1c7a78ffb7021116bf94b329
DefaultDecoderTest.java https://github.com/OpenFeign/feign/pull/3534/files#diff-9956c00a2a17fcc5e6536f39f59dd04f4112a0164859162ae5a910594c88f4db
DefaultEncoderTest.java https://github.com/OpenFeign/feign/pull/3534/files#diff-5b4902055d72f5fa55b36cdc0712c59406597cdb4e77776ff55f96ce841ca404
MultiDecoderTest.java https://github.com/OpenFeign/feign/pull/3534/files#diff-bcedbc9ff5a0885cbfd704ba297166ad7d46eab567fc7d7424dfd7b69ac71cd6
MultiEncoderTest.java https://github.com/OpenFeign/feign/pull/3534/files#diff-af9c88bfddced0f79bed0e2cfc6e0cc91b4be64b47c56fa8f4c83400ccb9d75b
StringDecoderTest.java https://github.com/OpenFeign/feign/pull/3534/files#diff-e7bb4b0e456e85c2b14be74200e3df46b7b04cd1a1c023441294dccdeadfea1d
FormEncoder.java https://github.com/OpenFeign/feign/pull/3534/files#diff-0e727b6918b005f464e0d3d10f5f31267952a4c78974d171022409e8df5af2fb
core/src/main/java/feign/Util.javahttps://github.com/OpenFeign/feign/pull/3534/files#diff-9bc6e3a76f6bf178a35e883f72bf2492ef18cac9a1ff48973533469cbda9247a
View file https://github.com/OpenFeign/feign/blob/ff0352fba08eee703a753f580edbeefa63260790/core/src/main/java/feign/Util.java
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/OpenFeign/feign/pull/3534/{{ revealButtonHref }}
https://github.com/OpenFeign/feign/pull/3534/files#diff-9bc6e3a76f6bf178a35e883f72bf2492ef18cac9a1ff48973533469cbda9247a
https://github.com/OpenFeign/feign/pull/3534/files#diff-9bc6e3a76f6bf178a35e883f72bf2492ef18cac9a1ff48973533469cbda9247a
core/src/main/java/feign/codec/DefaultDecoder.javahttps://github.com/OpenFeign/feign/pull/3534/files#diff-0142600050b7f9e7485450d8420cd611f09832c0deadf60e3a18dcc8960f5b5c
View file https://github.com/OpenFeign/feign/blob/ff0352fba08eee703a753f580edbeefa63260790/core/src/main/java/feign/codec/DefaultDecoder.java
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/OpenFeign/feign/pull/3534/{{ revealButtonHref }}
https://github.com/OpenFeign/feign/pull/3534/files#diff-0142600050b7f9e7485450d8420cd611f09832c0deadf60e3a18dcc8960f5b5c
https://github.com/OpenFeign/feign/pull/3534/files#diff-0142600050b7f9e7485450d8420cd611f09832c0deadf60e3a18dcc8960f5b5c
core/src/main/java/feign/codec/DefaultEncoder.javahttps://github.com/OpenFeign/feign/pull/3534/files#diff-03f1282371bb6b2c8d577eb3e9f95d37dc0f86e3845d0e9be84241341e450dcc
View file https://github.com/OpenFeign/feign/blob/ff0352fba08eee703a753f580edbeefa63260790/core/src/main/java/feign/codec/DefaultEncoder.java
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/OpenFeign/feign/pull/3534/{{ revealButtonHref }}
https://github.com/OpenFeign/feign/pull/3534/files#diff-03f1282371bb6b2c8d577eb3e9f95d37dc0f86e3845d0e9be84241341e450dcc
https://github.com/OpenFeign/feign/pull/3534/files#diff-03f1282371bb6b2c8d577eb3e9f95d37dc0f86e3845d0e9be84241341e450dcc
core/src/main/java/feign/codec/MultiDecoder.javahttps://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
View file https://github.com/OpenFeign/feign/blob/ff0352fba08eee703a753f580edbeefa63260790/core/src/main/java/feign/codec/MultiDecoder.java
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/OpenFeign/feign/pull/3534/{{ revealButtonHref }}
https://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
https://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
https://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
https://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
https://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
trumpetinchttps://github.com/trumpetinc
Aug 25, 2026https://github.com/OpenFeign/feign/pull/3534/files#r3854205437
Learn morehttps://docs.github.com/articles/managing-disruptive-comments/#hiding-a-comment
Please reload this pagehttps://github.com/OpenFeign/feign/pull/3534/files
https://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
https://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
https://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
https://github.com/OpenFeign/feign/pull/3534/files#diff-613e7c77bdfd3fc8da7d93084952dea31a198f4b9e17a48c58c013e93bca1ce2
core/src/main/java/feign/codec/MultiEncoder.javahttps://github.com/OpenFeign/feign/pull/3534/files#diff-e9facb5268144332a339ac5dc17cbd0749f5c131179b3cee1b3dd99eba379eaa
View file https://github.com/OpenFeign/feign/blob/ff0352fba08eee703a753f580edbeefa63260790/core/src/main/java/feign/codec/MultiEncoder.java
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/OpenFeign/feign/pull/3534/{{ revealButtonHref }}
https://github.com/OpenFeign/feign/pull/3534/files#diff-e9facb5268144332a339ac5dc17cbd0749f5c131179b3cee1b3dd99eba379eaa
https://github.com/OpenFeign/feign/pull/3534/files#diff-e9facb5268144332a339ac5dc17cbd0749f5c131179b3cee1b3dd99eba379eaa
https://github.com/OpenFeign/feign/pull/3534/files#diff-e9facb5268144332a339ac5dc17cbd0749f5c131179b3cee1b3dd99eba379eaa
https://github.com/OpenFeign/feign/pull/3534/files#diff-e9facb5268144332a339ac5dc17cbd0749f5c131179b3cee1b3dd99eba379eaa
https://github.com/OpenFeign/feign/pull/3534/files#diff-e9facb5268144332a339ac5dc17cbd0749f5c131179b3cee1b3dd99eba379eaa
https://github.com/OpenFeign/feign/pull/3534/files#diff-e9facb5268144332a339ac5dc17cbd0749f5c131179b3cee1b3dd99eba379eaa
trumpetinchttps://github.com/trumpetinc
Aug 25, 2026https://github.com/OpenFeign/feign/pull/3534/files#r3855363409
Please reload this pagehttps://github.com/OpenFeign/feign/pull/3534/files
Learn morehttps://docs.github.com/articles/managing-disruptive-comments/#hiding-a-comment
Please reload this pagehttps://github.com/OpenFeign/feign/pull/3534/files
https://github.com/OpenFeign/feign/pull/3534/files#diff-e9facb5268144332a339ac5dc17cbd0749f5c131179b3cee1b3dd99eba379eaa
Please reload this pagehttps://github.com/OpenFeign/feign/pull/3534/files
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.