Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
cef5e55
do not unwrap checked and undeclared exceptions
gitshabh May 13, 2026
16cf312
Open observation scope and stop observation on non-FeignException err…
seonwooj0810 Jun 11, 2026
e6e3a7b
Avoid ClassLoader leak from static default async executor (#3178) (#3…
seonwooj0810 Jun 11, 2026
18fe771
Fix feign-core test compilation broken by removed Request.create over…
seonwooj0810 Jun 11, 2026
216dbf7
revert: move Request.Body streaming breaking changes off master, they…
velo Jun 11, 2026
2c55821
build(deps): Bump jackson.version from 2.21.3 to 2.22.0
dependabot[bot] Jun 11, 2026
83a98e3
build(deps): Bump org.hibernate.validator:hibernate-validator
dependabot[bot] Jun 11, 2026
0684947
build(deps): Bump org.springframework.cloud:spring-cloud-dependencies
dependabot[bot] Jun 12, 2026
ee44507
build(deps-dev): Bump jersey.version from 3.1.11 to 3.1.12 in /jaxrs3
dependabot[bot] Jun 12, 2026
a069410
Merge pull request #3412 from OpenFeign/dependabot/maven/jaxrs3/jerse…
github-actions[bot] Jun 12, 2026
3bc5e5e
Merge pull request #3410 from OpenFeign/dependabot/maven/org.springfr…
github-actions[bot] Jun 12, 2026
77342a7
build(deps-dev): Bump org.springframework.cloud:spring-cloud-starter-…
dependabot[bot] Jun 12, 2026
644478a
Merge pull request #3411 from OpenFeign/dependabot/maven/org.springfr…
github-actions[bot] Jun 12, 2026
6be0ef3
Merge pull request #3380 from OpenFeign/dependabot/maven/jackson.vers…
github-actions[bot] Jun 13, 2026
0a5a998
Keep legacy validation on Hibernate Validator 6
velo Jun 13, 2026
9a77de7
Merge pull request #3348 from OpenFeign/dependabot/maven/org.hibernat…
github-actions[bot] Jun 13, 2026
61154cb
build(deps): Bump tools.jackson:jackson-bom from 3.1.3 to 3.2.0
dependabot[bot] Jun 13, 2026
0586937
build(deps): Bump springboot.version from 4.0.6 to 4.1.0
dependabot[bot] Jun 13, 2026
8de8a69
Merge remote-tracking branch 'origin/master' into fixCheckedException…
velo Jun 13, 2026
8299296
build(deps): Bump com.squareup.okhttp3:okhttp-bom from 5.3.2 to 5.4.0
dependabot[bot] Jun 13, 2026
a4bcd85
build(deps-dev): Bump vertx.version in /vertx/feign-vertx5-test
dependabot[bot] Jun 13, 2026
b5b41dc
build(deps): Bump reactor.version from 3.8.5 to 3.8.6
dependabot[bot] Jun 13, 2026
05035c6
build(deps): Bump micrometer.version from 1.16.5 to 1.17.0
dependabot[bot] Jun 13, 2026
02e4448
guard numeric retry-after against long overflow (#3405)
alhudz Jun 13, 2026
cb5554b
Align Apache HttpClient checked-exception handling with master's #148…
velo Jun 13, 2026
7d7d8bd
Merge pull request #3338 from gitshabh/fixCheckedExceptionUnwrapping
velo Jun 13, 2026
c09a581
Merge pull request #3403 from OpenFeign/dependabot/maven/vertx/feign-…
github-actions[bot] Jun 13, 2026
1d5e94c
Merge pull request #3400 from OpenFeign/dependabot/maven/micrometer.v…
github-actions[bot] Jun 13, 2026
58fcb08
Merge pull request #3398 from OpenFeign/dependabot/maven/tools.jackso…
github-actions[bot] Jun 13, 2026
909420a
Merge pull request #3399 from OpenFeign/dependabot/maven/com.squareup…
github-actions[bot] Jun 13, 2026
4bb4ef7
Merge pull request #3401 from OpenFeign/dependabot/maven/reactor.vers…
github-actions[bot] Jun 13, 2026
865a0f6
build(deps): consolidate spring-web/spring-context into single spring…
velo Jun 13, 2026
7b1dd30
Merge remote-tracking branch 'origin/master' into dependabot/maven/sp…
velo Jun 13, 2026
2a2344d
prepare release 13.13
velo Jun 13, 2026
46a3830
[ci skip] updating versions to next development iteration 13.14-SNAPSHOT
velo Jun 13, 2026
f1e1426
build(deps): Bump org.hibernate.validator:hibernate-validator
dependabot[bot] Jun 15, 2026
4285e1e
Merge branch 'master' into dependabot/maven/springboot.version-4.1.0
velo Jun 15, 2026
c99bc9b
build(deps): import spring-boot-dependencies BOM to pin spring-boot a…
velo Jun 15, 2026
33e44f0
Merge remote-tracking branch 'origin/dependabot/maven/springboot.vers…
velo Jun 15, 2026
e47fed5
build(deps): scope spring-boot-dependencies BOM to form-spring to avo…
velo Jun 15, 2026
b16b294
Merge pull request #3408 from OpenFeign/dependabot/maven/springboot.v…
github-actions[bot] Jun 15, 2026
3dc2070
build(deps-dev): Bump org.sonatype.central:central-publishing-maven-p…
dependabot[bot] Jun 17, 2026
83f1896
build(deps): Bump com.github.jknack:handlebars from 4.5.1 to 4.5.2
dependabot[bot] Jun 17, 2026
928a1e5
Merge pull request #3420 from OpenFeign/dependabot/maven/org.sonatype…
github-actions[bot] Jun 17, 2026
62127a8
Merge pull request #3421 from OpenFeign/dependabot/maven/com.github.j…
github-actions[bot] Jun 17, 2026
47e99c1
Keep javax validation on Hibernate Validator 6
velo Jun 17, 2026
39c4f41
Honor jdk.httpclient.allowRestrictedHeaders in Http2Client (#2975) (#…
seonwooj0810 Jun 17, 2026
8694ed6
escape crlf and quotes in multipart content-disposition headers (#3417)
alhudz Jun 17, 2026
db8819c
Merge pull request #3416 from OpenFeign/dependabot/maven/org.hibernat…
github-actions[bot] Jun 17, 2026
3f233b9
build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks
dependabot[bot] Jun 18, 2026
1a47ced
build(deps): Bump org.hibernate.validator:hibernate-validator
dependabot[bot] Jun 18, 2026
d83d168
Merge pull request #3423 from OpenFeign/dependabot/maven/org.openrewr…
github-actions[bot] Jun 18, 2026
a9bf809
build(deps-dev): Bump org.openrewrite.maven:rewrite-maven-plugin
dependabot[bot] Jun 18, 2026
dc0525d
build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java
dependabot[bot] Jun 18, 2026
aa1ff8d
Merge pull request #3426 from OpenFeign/dependabot/maven/org.openrewr…
github-actions[bot] Jun 18, 2026
5dbc552
Merge pull request #3424 from OpenFeign/dependabot/maven/org.openrewr…
github-actions[bot] Jun 18, 2026
35609a1
Keep javax validation on compatible provider
velo Jun 18, 2026
93144ab
Merge pull request #3425 from OpenFeign/dependabot/maven/org.hibernat…
github-actions[bot] Jun 18, 2026
db9ae4b
build(deps): Bump org.hibernate.validator:hibernate-validator
dependabot[bot] Jun 19, 2026
9d7ffef
Keep javax validation on Hibernate Validator 6
velo Jun 19, 2026
247fb46
fall back to utf-8 for invalid content-type charset (#3427)
alhudz Jun 19, 2026
837dcd5
Make Expressions max length configurable (#3422)
seonwooj0810 Jun 19, 2026
bd7a537
Preserve delegate content type for multipart parameters (#3382)
seonwooj0810 Jun 19, 2026
bb48cea
Merge pull request #3428 from OpenFeign/dependabot/maven/org.hibernat…
github-actions[bot] Jun 19, 2026
425cc81
cap Content-Length before narrowing to int in Http2Client (#3431)
alhudz Jun 20, 2026
0a250fd
generate multipart boundary from SecureRandom (#3429)
alhudz Jun 20, 2026
265c657
strip crlf from multipart content-type header (#3432)
alhudz Jun 21, 2026
d05f71a
build(deps-dev): Bump com.gradle:develocity-maven-extension
dependabot[bot] Jun 22, 2026
d32f208
build(deps): Bump org.openrewrite.recipe:rewrite-testing-frameworks
dependabot[bot] Jun 22, 2026
5fe80b6
Merge pull request #3434 from OpenFeign/dependabot/maven/com.gradle-d…
github-actions[bot] Jun 22, 2026
a838747
Merge pull request #3435 from OpenFeign/dependabot/maven/org.openrewr…
github-actions[bot] Jun 22, 2026
711fa7a
build(deps-dev): Bump vertx.version in /vertx/feign-vertx5-test
dependabot[bot] Jun 23, 2026
b46b351
build(deps): Bump org.openrewrite.recipe:rewrite-migrate-java
dependabot[bot] Jun 23, 2026
c455a72
Merge pull request #3438 from OpenFeign/dependabot/maven/vertx/feign-…
github-actions[bot] Jun 23, 2026
6b3cc11
Merge pull request #3439 from OpenFeign/dependabot/maven/org.openrewr…
github-actions[bot] Jun 23, 2026
b547fb5
Return response body in FeignException from errorReading (#2618) (#3415)
seonwooj0810 Jun 23, 2026
5cd6f57
treat invalid expression value modifier as a literal (#3437)
alhudz Jun 23, 2026
3062e80
encode collection values in urlencoded form bodies (#3436)
alhudz Jun 23, 2026
baeba5a
encode soap request body with the configured charset (#3433)
alhudz Jun 23, 2026
e55fd16
Merge branch 'master' into 14.x
velo Jun 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion .mvn/extensions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<extension>
<groupId>com.gradle</groupId>
<artifactId>develocity-maven-extension</artifactId>
<version>2.4.1</version>
<version>2.4.2</version>
</extension>
<extension>
<groupId>com.gradle</groupId>
Expand Down
2 changes: 1 addition & 1 deletion api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-context.version}</version>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>

Expand Down
2 changes: 2 additions & 0 deletions api/src/main/java/feign/BaseBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ List<Field> 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
Expand Down
8 changes: 7 additions & 1 deletion api/src/main/java/feign/Response.java
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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;
}
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions api/src/main/java/feign/codec/ErrorDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,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;
}
}
Expand Down
49 changes: 37 additions & 12 deletions api/src/main/java/feign/template/Expressions.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,18 @@
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

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 = ";";

Expand Down Expand Up @@ -73,10 +81,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 */
Expand Down Expand Up @@ -104,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) {
Expand Down
52 changes: 52 additions & 0 deletions api/src/test/java/feign/template/ExpressionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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}");
Expand All @@ -44,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) + "}";
Expand Down
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-context.version}</version>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>

Expand Down
5 changes: 5 additions & 0 deletions core/src/test/java/feign/codec/RetryAfterDecoderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ void relativeSecondsParseDecimalIntegers() throws Exception {
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();
Expand Down
14 changes: 13 additions & 1 deletion form-spring/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@
<moditect.skip>true</moditect.skip>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
Expand All @@ -58,7 +70,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-web.version}</version>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>

Expand Down
11 changes: 10 additions & 1 deletion form/src/main/java/feign/form/FormEncoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import feign.core.codec.DefaultEncoder;
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;
Expand Down Expand Up @@ -129,6 +131,13 @@ private String getContentTypeValue(Map<String, Collection<String>> headers) {

private Charset getCharset(String contentTypeValue) {
final var 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;
}
}
}
16 changes: 15 additions & 1 deletion form/src/main/java/feign/form/MultipartFormContentProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,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;
Expand All @@ -49,6 +50,8 @@
@FieldDefaults(level = PRIVATE, makeFinal = true)
public class MultipartFormContentProcessor implements ContentProcessor {

private static final SecureRandom RANDOM = new SecureRandom();

Deque<Writer> writers;

Writer defaultPerocessor;
Expand All @@ -75,7 +78,7 @@ public MultipartFormContentProcessor(Encoder delegate) {
@Override
public void process(RequestTemplate template, Charset charset, Map<String, Object> data)
throws EncodeException {
final var boundary = Long.toHexString(System.currentTimeMillis());
final var boundary = randomBoundary();
try (final var output = new Output(charset)) {
for (var entry : data.entrySet()) {
if (entry == null || entry.getKey() == null || entry.getValue() == null) {
Expand Down Expand Up @@ -158,4 +161,15 @@ private Writer findApplicableWriter(Object value) {
}
return defaultPerocessor;
}

private static String randomBoundary() {
var token = new byte[16];
RANDOM.nextBytes(token);
var builder = new StringBuilder(token.length * 2);
for (var octet : token) {
builder.append(Character.forDigit((octet >> 4) & 0xF, 16));
builder.append(Character.forDigit(octet & 0xF, 16));
}
return builder.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import static feign.form.ContentType.URLENCODED;

import feign.CollectionFormat;
import feign.Request;
import feign.RequestTemplate;
import feign.codec.EncodeException;
import java.net.URLEncoder;
Expand Down Expand Up @@ -74,7 +73,7 @@ public void process(RequestTemplate template, Charset charset, Map<String, Objec

template.header(CONTENT_TYPE_HEADER, Collections.<String>emptyList()); // reset header
template.header(CONTENT_TYPE_HEADER, contentTypeValue);
template.body(Request.Body.of(bytes));
template.body(bytes, charset);
}

@Override
Expand Down Expand Up @@ -106,7 +105,10 @@ private CharSequence createKeyValuePair(
private CharSequence createKeyValuePair(
CollectionFormat collectionFormat, String key, Stream<?> values, Charset charset) {
final var 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);
}
}
Loading