WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit e7dffaf

Browse files
committed
Add a converter for Jackson 3
This mostly copies the existing Jackson (2) converter and does the necessary migration [1]. Note that Jackson 3 requires Java 17. [1]: https://github.com/FasterXML/jackson/blob/main/jackson3/MIGRATING_TO_JACKSON_3.md
1 parent 137e892 commit e7dffaf

File tree

13 files changed

+613
-0
lines changed

13 files changed

+613
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Add explicit keep rules for RxJava `Result` types to prevent their generic information from being removed.
99
- Add `allowoptimization` flags for most kept types.
1010
- Add `Invocation.annotationUrl` which returns the original URL from the method annotation.
11+
- Add a converter for Jackson 3.
1112

1213
**Changed**
1314

gradle/libs.versions.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ autoService = "1.1.1"
2222
incap = "1.0.0"
2323
jackson = "2.20.1"
2424
jacksonAnnotations = "2.20"
25+
jackson3 = "3.0.1"
2526

2627
[libraries]
2728
androidPlugin = { module = "com.android.tools.build:gradle", version = "8.13.0" }
@@ -73,6 +74,8 @@ gson = { module = "com.google.code.gson:gson", version = "2.13.2" }
7374
jacksonAnnotations = { module = "com.fasterxml.jackson.core:jackson-annotations", version.ref = "jacksonAnnotations" }
7475
jacksonDatabind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
7576
jacksonDataformatCbor = { module = "com.fasterxml.jackson.dataformat:jackson-dataformat-cbor", version.ref = "jackson" }
77+
jackson3Databind = { module = "tools.jackson.core:jackson-databind", version.ref = "jackson3" }
78+
jackson3DataformatCbor = { module = "tools.jackson.dataformat:jackson-dataformat-cbor", version.ref = "jackson3" }
7679
jaxbApi = { module = "javax.xml.bind:jaxb-api", version = "2.3.1" }
7780
jaxbImpl = { module = "org.glassfish.jaxb:jaxb-runtime", version = "4.0.6" }
7881
jaxb3Api = { module = "jakarta.xml.bind:jakarta.xml.bind-api", version = "3.0.1" }
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Jackson Converter
2+
=================
3+
4+
A `Converter` which uses [Jackson][1] 3 for serialization to and from JSON.
5+
6+
A default `ObjectMapper` instance will be created or one can be configured and passed to the
7+
`JacksonConverterFactory` construction to further control the serialization.
8+
9+
10+
Download
11+
--------
12+
13+
Download [the latest JAR][2] or grab via [Maven][3]:
14+
```xml
15+
<dependency>
16+
<groupId>com.squareup.retrofit2</groupId>
17+
<artifactId>converter-jackson3</artifactId>
18+
<version>latest.version</version>
19+
</dependency>
20+
```
21+
or [Gradle][3]:
22+
```groovy
23+
implementation 'com.squareup.retrofit2:converter-jackson3:latest.version'
24+
```
25+
26+
Snapshots of the development version are available in [Sonatype's `snapshots` repository][snap].
27+
28+
29+
30+
[1]: https://github.com/FasterXML/jackson
31+
[2]: https://search.maven.org/remote_content?g=com.squareup.retrofit2&a=converter-jackson3&v=LATEST
32+
[3]: http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.squareup.retrofit2%22%20a%3A%22converter-jackson3%22
33+
[snap]: https://s01.oss.sonatype.org/content/repositories/snapshots/
34+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
apply plugin: 'java-library'
2+
apply plugin: 'com.vanniktech.maven.publish'
3+
4+
dependencies {
5+
api projects.retrofit
6+
api libs.jackson3Databind
7+
compileOnly libs.findBugsAnnotations
8+
9+
testImplementation libs.junit
10+
testImplementation libs.truth
11+
testImplementation libs.okhttp.mockwebserver
12+
testImplementation libs.testParameterInjector
13+
testImplementation libs.jacksonAnnotations
14+
testImplementation libs.jackson3DataformatCbor
15+
}
16+
17+
jar {
18+
manifest {
19+
attributes 'Automatic-Module-Name': 'retrofit2.converter.jackson3'
20+
}
21+
}
22+
23+
java {
24+
toolchain {
25+
languageVersion = JavaLanguageVersion.of(17)
26+
}
27+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
POM_ARTIFACT_ID=converter-jackson3
2+
POM_NAME=Converter: Jackson3
3+
POM_DESCRIPTION=A Retrofit Converter which uses Jackson 3 for serialization.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright (C) 2015 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package retrofit2.converter.jackson3;
17+
18+
import tools.jackson.databind.JavaType;
19+
import tools.jackson.databind.ObjectMapper;
20+
import tools.jackson.databind.ObjectReader;
21+
import tools.jackson.databind.ObjectWriter;
22+
import java.lang.annotation.Annotation;
23+
import java.lang.reflect.Type;
24+
import okhttp3.MediaType;
25+
import okhttp3.RequestBody;
26+
import okhttp3.ResponseBody;
27+
import retrofit2.Call;
28+
import retrofit2.Converter;
29+
import retrofit2.Retrofit;
30+
31+
/**
32+
* A {@linkplain Converter.Factory converter} which uses Jackson.
33+
*
34+
* <p>Because Jackson is so flexible in the types it supports, this converter assumes that it can
35+
* handle all types. If you are mixing JSON serialization with something else (such as protocol
36+
* buffers), you must {@linkplain Retrofit.Builder#addConverterFactory(Converter.Factory) add this
37+
* instance} last to allow the other converters a chance to see their types.
38+
*/
39+
public final class JacksonConverterFactory extends Converter.Factory {
40+
private static final MediaType DEFAULT_MEDIA_TYPE =
41+
MediaType.get("application/json; charset=UTF-8");
42+
43+
/** Create an instance using a default {@link ObjectMapper} instance for conversion. */
44+
public static JacksonConverterFactory create() {
45+
return new JacksonConverterFactory(new ObjectMapper(), DEFAULT_MEDIA_TYPE, false);
46+
}
47+
48+
/** Create an instance using {@code mapper} for conversion. */
49+
public static JacksonConverterFactory create(ObjectMapper mapper) {
50+
return create(mapper, DEFAULT_MEDIA_TYPE);
51+
}
52+
53+
/** Create an instance using {@code mapper} and {@code mediaType} for conversion. */
54+
@SuppressWarnings("ConstantConditions") // Guarding public API nullability.
55+
public static JacksonConverterFactory create(ObjectMapper mapper, MediaType mediaType) {
56+
if (mapper == null) throw new NullPointerException("mapper == null");
57+
if (mediaType == null) throw new NullPointerException("mediaType == null");
58+
return new JacksonConverterFactory(mapper, mediaType, false);
59+
}
60+
61+
private final ObjectMapper mapper;
62+
private final MediaType mediaType;
63+
private final boolean streaming;
64+
65+
private JacksonConverterFactory(ObjectMapper mapper, MediaType mediaType, boolean streaming) {
66+
this.mapper = mapper;
67+
this.mediaType = mediaType;
68+
this.streaming = streaming;
69+
}
70+
71+
/**
72+
* Return a new factory which streams serialization of request messages to bytes on the HTTP thread
73+
* This is either the calling thread for {@link Call#execute()}, or one of OkHttp's background
74+
* threads for {@link Call#enqueue}. Response bytes are always converted to message instances on
75+
* one of OkHttp's background threads.
76+
*/
77+
public JacksonConverterFactory withStreaming() {
78+
return new JacksonConverterFactory(mapper, mediaType, true);
79+
}
80+
81+
@Override
82+
public Converter<ResponseBody, ?> responseBodyConverter(
83+
Type type, Annotation[] annotations, Retrofit retrofit) {
84+
JavaType javaType = mapper.getTypeFactory().constructType(type);
85+
ObjectReader reader = mapper.readerFor(javaType);
86+
return new JacksonResponseBodyConverter<>(reader);
87+
}
88+
89+
@Override
90+
public Converter<?, RequestBody> requestBodyConverter(
91+
Type type,
92+
Annotation[] parameterAnnotations,
93+
Annotation[] methodAnnotations,
94+
Retrofit retrofit) {
95+
JavaType javaType = mapper.getTypeFactory().constructType(type);
96+
ObjectWriter writer = mapper.writerFor(javaType);
97+
return new JacksonRequestBodyConverter<>(writer, mediaType, streaming);
98+
}
99+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (C) 2015 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package retrofit2.converter.jackson3;
17+
18+
import tools.jackson.databind.ObjectWriter;
19+
import java.io.IOException;
20+
import okhttp3.MediaType;
21+
import okhttp3.RequestBody;
22+
import retrofit2.Converter;
23+
24+
final class JacksonRequestBodyConverter<T> implements Converter<T, RequestBody> {
25+
private final ObjectWriter adapter;
26+
private final MediaType mediaType;
27+
private final boolean streaming;
28+
29+
JacksonRequestBodyConverter(ObjectWriter adapter, MediaType mediaType, boolean streaming) {
30+
this.adapter = adapter;
31+
this.mediaType = mediaType;
32+
this.streaming = streaming;
33+
}
34+
35+
@Override
36+
public RequestBody convert(T value) throws IOException {
37+
if (streaming) {
38+
return new JacksonStreamingRequestBody(adapter, value, mediaType);
39+
}
40+
41+
byte[] bytes = adapter.writeValueAsBytes(value);
42+
return RequestBody.create(mediaType, bytes);
43+
}
44+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (C) 2015 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package retrofit2.converter.jackson3;
17+
18+
import tools.jackson.databind.ObjectReader;
19+
import java.io.IOException;
20+
import okhttp3.ResponseBody;
21+
import retrofit2.Converter;
22+
23+
final class JacksonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
24+
private final ObjectReader adapter;
25+
26+
JacksonResponseBodyConverter(ObjectReader adapter) {
27+
this.adapter = adapter;
28+
}
29+
30+
@Override
31+
public T convert(ResponseBody value) throws IOException {
32+
try {
33+
return adapter.readValue(value.byteStream());
34+
} finally {
35+
value.close();
36+
}
37+
}
38+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (C) 2025 Square, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package retrofit2.converter.jackson3;
17+
18+
import tools.jackson.databind.ObjectWriter;
19+
import java.io.IOException;
20+
import okhttp3.MediaType;
21+
import okhttp3.RequestBody;
22+
import okio.BufferedSink;
23+
24+
final class JacksonStreamingRequestBody extends RequestBody {
25+
private final ObjectWriter adapter;
26+
private final Object value;
27+
private final MediaType mediaType;
28+
29+
public JacksonStreamingRequestBody(ObjectWriter adapter, Object value, MediaType mediaType) {
30+
this.adapter = adapter;
31+
this.value = value;
32+
this.mediaType = mediaType;
33+
}
34+
35+
@Override
36+
public MediaType contentType() {
37+
return mediaType;
38+
}
39+
40+
@Override
41+
public void writeTo(BufferedSink sink) throws IOException {
42+
adapter.writeValue(sink.outputStream(), value);
43+
}
44+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@retrofit2.internal.EverythingIsNonNull
2+
package retrofit2.converter.jackson3;

0 commit comments

Comments
 (0)