mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-25 08:19:01 +00:00
Add support for "application/jsonl" JSON lines
Prior to this commit, Spring web frameworks were using the "application/x-ndjson" media type for streaming JSON payloads delimited with newlines. The "application/jsonl" media type seems to gain popularity in the broader ecosystem and could supersede NDJSON in the future. This commit adds support for JSON Lines as an alternative. Closes gh-36485
This commit is contained in:
@@ -209,6 +209,19 @@ public class MediaType extends MimeType implements Serializable {
|
||||
*/
|
||||
public static final String APPLICATION_NDJSON_VALUE = "application/x-ndjson";
|
||||
|
||||
/**
|
||||
* Media type for {@code application/jsonl} (JSON Lines).
|
||||
* @since 7.1
|
||||
* @see <a href="https://jsonlines.org/">JSON Lines</a>
|
||||
*/
|
||||
public static final MediaType APPLICATION_JSONL;
|
||||
|
||||
/**
|
||||
* A String equivalent of {@link MediaType#APPLICATION_JSONL}.
|
||||
* @since 7.1
|
||||
*/
|
||||
public static final String APPLICATION_JSONL_VALUE = "application/jsonl";
|
||||
|
||||
/**
|
||||
* Media type for {@code application/xhtml+xml}.
|
||||
*/
|
||||
@@ -372,6 +385,7 @@ public class MediaType extends MimeType implements Serializable {
|
||||
APPLICATION_GRAPHQL_RESPONSE = new MediaType("application", "graphql-response+json");
|
||||
APPLICATION_JSON = new MediaType("application", "json");
|
||||
APPLICATION_NDJSON = new MediaType("application", "x-ndjson");
|
||||
APPLICATION_JSONL = new MediaType("application", "jsonl");
|
||||
APPLICATION_OCTET_STREAM = new MediaType("application", "octet-stream");
|
||||
APPLICATION_PDF = new MediaType("application", "pdf");
|
||||
APPLICATION_PROBLEM_JSON = new MediaType("application", "problem+json");
|
||||
|
||||
@@ -58,7 +58,8 @@ public class GsonEncoder extends AbstractEncoder<Object> implements HttpMessageE
|
||||
private static final MimeType[] DEFAULT_JSON_MIME_TYPES = new MimeType[] {
|
||||
MediaType.APPLICATION_JSON,
|
||||
new MediaType("application", "*+json"),
|
||||
MediaType.APPLICATION_NDJSON
|
||||
MediaType.APPLICATION_NDJSON,
|
||||
MediaType.APPLICATION_JSONL
|
||||
};
|
||||
|
||||
private final Gson gson;
|
||||
@@ -68,11 +69,12 @@ public class GsonEncoder extends AbstractEncoder<Object> implements HttpMessageE
|
||||
/**
|
||||
* Construct a new encoder using a default {@link Gson} instance
|
||||
* and the {@code "application/json"} and {@code "application/*+json"}
|
||||
* MIME types. The {@code "application/x-ndjson"} is configured for streaming.
|
||||
* MIME types. The {@code "application/jsonl"} and {@code "application/x-ndjson"}
|
||||
* are configured for streaming.
|
||||
*/
|
||||
public GsonEncoder() {
|
||||
this(new Gson(), DEFAULT_JSON_MIME_TYPES);
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON));
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON, MediaType.APPLICATION_JSONL));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -81,7 +81,8 @@ public abstract class Jackson2CodecSupport {
|
||||
private static final List<MimeType> defaultMimeTypes = List.of(
|
||||
MediaType.APPLICATION_JSON,
|
||||
new MediaType("application", "*+json"),
|
||||
MediaType.APPLICATION_NDJSON);
|
||||
MediaType.APPLICATION_NDJSON,
|
||||
MediaType.APPLICATION_JSONL);
|
||||
|
||||
|
||||
protected final Log logger = HttpLogging.forLogName(getClass());
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ public class Jackson2JsonEncoder extends AbstractJackson2Encoder {
|
||||
|
||||
public Jackson2JsonEncoder(ObjectMapper mapper, MimeType... mimeTypes) {
|
||||
super(mapper, mimeTypes);
|
||||
setStreamingMediaTypes(Arrays.asList(MediaType.APPLICATION_NDJSON));
|
||||
setStreamingMediaTypes(Arrays.asList(MediaType.APPLICATION_NDJSON, MediaType.APPLICATION_JSONL));
|
||||
this.ssePrettyPrinter = initSsePrettyPrinter();
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -55,7 +55,8 @@ public class JacksonJsonDecoder extends AbstractJacksonDecoder<JsonMapper> {
|
||||
private static final MimeType[] DEFAULT_JSON_MIME_TYPES = new MimeType[] {
|
||||
MediaType.APPLICATION_JSON,
|
||||
new MediaType("application", "*+json"),
|
||||
MediaType.APPLICATION_NDJSON
|
||||
MediaType.APPLICATION_NDJSON,
|
||||
MediaType.APPLICATION_JSONL
|
||||
};
|
||||
|
||||
|
||||
|
||||
+4
-3
@@ -55,7 +55,8 @@ public class JacksonJsonEncoder extends AbstractJacksonEncoder<JsonMapper> {
|
||||
private static final MimeType[] DEFAULT_JSON_MIME_TYPES = new MimeType[] {
|
||||
MediaType.APPLICATION_JSON,
|
||||
new MediaType("application", "*+json"),
|
||||
MediaType.APPLICATION_NDJSON
|
||||
MediaType.APPLICATION_NDJSON,
|
||||
MediaType.APPLICATION_JSONL
|
||||
};
|
||||
|
||||
|
||||
@@ -99,7 +100,7 @@ public class JacksonJsonEncoder extends AbstractJacksonEncoder<JsonMapper> {
|
||||
*/
|
||||
public JacksonJsonEncoder(JsonMapper.Builder builder, MimeType... mimeTypes) {
|
||||
super(builder.addMixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class), mimeTypes);
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON));
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON, MediaType.APPLICATION_JSONL));
|
||||
this.ssePrettyPrinter = initSsePrettyPrinter();
|
||||
}
|
||||
|
||||
@@ -110,7 +111,7 @@ public class JacksonJsonEncoder extends AbstractJacksonEncoder<JsonMapper> {
|
||||
*/
|
||||
public JacksonJsonEncoder(JsonMapper mapper, MimeType... mimeTypes) {
|
||||
super(mapper, mimeTypes);
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON));
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON, MediaType.APPLICATION_JSONL));
|
||||
this.ssePrettyPrinter = initSsePrettyPrinter();
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -56,7 +56,8 @@ public class KotlinSerializationJsonDecoder extends KotlinSerializationStringDec
|
||||
private static final MimeType[] DEFAULT_JSON_MIME_TYPES = new MimeType[] {
|
||||
MediaType.APPLICATION_JSON,
|
||||
new MediaType("application", "*+json"),
|
||||
MediaType.APPLICATION_NDJSON
|
||||
MediaType.APPLICATION_NDJSON,
|
||||
MediaType.APPLICATION_JSONL
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+5
-4
@@ -36,7 +36,7 @@ import org.springframework.util.MimeType;
|
||||
/**
|
||||
* Encode from an {@code Object} stream to a byte stream of JSON objects using
|
||||
* <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a>.
|
||||
* It supports {@code application/json}, {@code application/x-ndjson} and {@code application/*+json} with
|
||||
* It supports {@code application/json}, {@code application/x-ndjson}, {@code application/jsonl} and {@code application/*+json} with
|
||||
* various character sets, {@code UTF-8} being the default.
|
||||
*
|
||||
* <p>As of Spring Framework 7.0, by default it only encodes types annotated with
|
||||
@@ -59,7 +59,8 @@ public class KotlinSerializationJsonEncoder extends KotlinSerializationStringEnc
|
||||
private static final MimeType[] DEFAULT_JSON_MIME_TYPES = new MimeType[] {
|
||||
MediaType.APPLICATION_JSON,
|
||||
new MediaType("application", "*+json"),
|
||||
MediaType.APPLICATION_NDJSON
|
||||
MediaType.APPLICATION_NDJSON,
|
||||
MediaType.APPLICATION_JSONL
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -87,7 +88,7 @@ public class KotlinSerializationJsonEncoder extends KotlinSerializationStringEnc
|
||||
*/
|
||||
public KotlinSerializationJsonEncoder(Json json) {
|
||||
super(json, DEFAULT_JSON_MIME_TYPES);
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON));
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON, MediaType.APPLICATION_JSONL));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +98,7 @@ public class KotlinSerializationJsonEncoder extends KotlinSerializationStringEnc
|
||||
*/
|
||||
public KotlinSerializationJsonEncoder(Json json, Predicate<ResolvableType> typePredicate) {
|
||||
super(json, typePredicate, DEFAULT_JSON_MIME_TYPES);
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON));
|
||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON, MediaType.APPLICATION_JSONL));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ public class ProtobufJsonEncoder implements HttpMessageEncoder<Message> {
|
||||
|
||||
@Override
|
||||
public List<MediaType> getStreamingMediaTypes() {
|
||||
return List.of(MediaType.APPLICATION_NDJSON);
|
||||
return List.of(MediaType.APPLICATION_NDJSON, MediaType.APPLICATION_JSONL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user