diff --git a/README.md b/README.md
index 6a54f0baa..cb6b97a4f 100644
--- a/README.md
+++ b/README.md
@@ -474,6 +474,23 @@ public class Example {
NB: you may also need to add `SOAPErrorDecoder` if SOAP Faults are returned in response with error http codes (4xx, 5xx, ...)
+#### Fastjson2
+
+[fastjson2](./fastjson2) includes an encoder and decoder you can use with a JSON API.
+
+Add `Fastjson2Encoder` and/or `Fastjson2Decoder` to your `Feign.Builder` like so:
+
+```java
+public class Example {
+ public static void main(String[] args) {
+ GitHub github = Feign.builder()
+ .encoder(new Fastjson2Encoder())
+ .decoder(new Fastjson2Decoder())
+ .target(GitHub.class, "https://api.github.com");
+ }
+}
+```
+
### Contract
#### JAX-RS
diff --git a/fastjson2/README.md b/fastjson2/README.md
new file mode 100644
index 000000000..8d283ea30
--- /dev/null
+++ b/fastjson2/README.md
@@ -0,0 +1,22 @@
+Fastjson2 Codec
+===================
+
+This module adds support for encoding and decoding JSON via Fastjson2.
+
+Add `Fastjson2Encoder` and/or `Fastjson2Decoder` to your `Feign.Builder` like so:
+
+```java
+GitHub github = Feign.builder()
+ .encoder(new Fastjson2Encoder())
+ .decoder(new Fastjson2Decoder())
+ .target(GitHub.class, "https://api.github.com");
+```
+
+If you want to customize, provide it to the `Fastjson2Encoder` and `Fastjson2Decoder`:
+
+```java
+GitHub github = Feign.builder()
+ .encoder(new Fastjson2Encoder(new JSONWriter.Feature[]{JSONWriter.Feature.WriteNonStringValueAsString})
+ .decoder(new Fastjson2Decoder(new JSONReader.Feature[]{JSONReader.Feature.EmptyStringAsNull}))
+ .target(GitHub.class, "https://api.github.com");
+```
diff --git a/fastjson2/pom.xml b/fastjson2/pom.xml
new file mode 100644
index 000000000..3000562f7
--- /dev/null
+++ b/fastjson2/pom.xml
@@ -0,0 +1,52 @@
+
+
+
+ 4.0.0
+
+
+ io.github.openfeign
+ parent
+ 13.3-SNAPSHOT
+
+
+ feign-fastjson2
+ Feign Fastjson2
+ Feign Fastjson2
+
+
+ ${project.basedir}/..
+
+
+
+
+ ${project.groupId}
+ feign-core
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+
+
+
+ ${project.groupId}
+ feign-core
+ test-jar
+ test
+
+
+
diff --git a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Decoder.java b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Decoder.java
new file mode 100644
index 000000000..ce9c28786
--- /dev/null
+++ b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Decoder.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012-2024 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.
+ */
+package feign.fastjson2;
+
+import static feign.Util.ensureClosed;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONException;
+import com.alibaba.fastjson2.JSONReader;
+import feign.FeignException;
+import feign.Response;
+import feign.Util;
+import feign.codec.Decoder;
+import java.io.IOException;
+import java.io.Reader;
+import java.lang.reflect.Type;
+
+/**
+ * @author changjin wei(魏昌进)
+ */
+public class Fastjson2Decoder implements Decoder {
+
+ private final JSONReader.Feature[] features;
+
+ public Fastjson2Decoder() {
+ this(new JSONReader.Feature[0]);
+ }
+
+ public Fastjson2Decoder(JSONReader.Feature[] features) {
+ this.features = features;
+ }
+
+ @Override
+ public Object decode(Response response, Type type) throws IOException, FeignException {
+ if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type);
+ if (response.body() == null) return null;
+ Reader reader = response.body().asReader(response.charset());
+ try {
+ return JSON.parseObject(reader, type, features);
+ } catch (JSONException e) {
+ if (e.getCause() != null && e.getCause() instanceof IOException) {
+ throw IOException.class.cast(e.getCause());
+ }
+ throw e;
+ } finally {
+ ensureClosed(reader);
+ }
+ }
+}
diff --git a/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java
new file mode 100644
index 000000000..2353fe394
--- /dev/null
+++ b/fastjson2/src/main/java/feign/fastjson2/Fastjson2Encoder.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012-2024 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.
+ */
+package feign.fastjson2;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+import feign.RequestTemplate;
+import feign.Util;
+import feign.codec.EncodeException;
+import feign.codec.Encoder;
+import java.lang.reflect.Type;
+
+/**
+ * @author changjin wei(魏昌进)
+ */
+public class Fastjson2Encoder implements Encoder {
+
+ private final JSONWriter.Feature[] features;
+
+ public Fastjson2Encoder() {
+ this(new JSONWriter.Feature[0]);
+ }
+
+ public Fastjson2Encoder(JSONWriter.Feature[] features) {
+ this.features = features;
+ }
+
+ @Override
+ public void encode(Object object, Type bodyType, RequestTemplate template)
+ throws EncodeException {
+ 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
new file mode 100644
index 000000000..e99fe0539
--- /dev/null
+++ b/fastjson2/src/test/java/feign/fastjson2/FastJsonCodecTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2012-2024 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.
+ */
+package feign.fastjson2;
+
+import static feign.Util.UTF_8;
+import static feign.assertj.FeignAssertions.assertThat;
+
+import com.alibaba.fastjson2.TypeReference;
+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;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author changjin wei(魏昌进)
+ */
+@SuppressWarnings("deprecation")
+class FastJsonCodecTest {
+
+ 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 Fastjson2Encoder().encode(map, map.getClass(), template);
+
+ assertThat(template)
+ .hasBody(
+ "" //
+ + "{" //
+ + "\"foo\":1" //
+ + "}");
+ }
+
+ @Test
+ void encodesFormParams() {
+ Map form = new LinkedHashMap<>();
+ form.put("foo", 1);
+ form.put("bar", Arrays.asList(2, 3));
+
+ RequestTemplate template = new RequestTemplate();
+ new Fastjson2Encoder().encode(form, new TypeReference