From f99c02fc941c92ca01d45fe2ebb2dd5318f471b2 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Tue, 18 Oct 2022 13:34:37 +0200 Subject: [PATCH] Upgrade to Jackson 2.14.0-rc2 This commit upgrades Jackson to 2.14.0-rc2, and uses the new ByteBufferFeeder in Jackson2Tokenizer. Unfortunately, because of https://github.com/FasterXML/jackson-core/issues/478, we had to change the CompilerConventions to suppress class file warnings. Closes gh-29343 --- .../build/CompilerConventions.java | 3 +- framework-platform/framework-platform.gradle | 2 +- .../http/codec/json/Jackson2Tokenizer.java | 41 +++++++++++++------ 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/buildSrc/src/main/java/org/springframework/build/CompilerConventions.java b/buildSrc/src/main/java/org/springframework/build/CompilerConventions.java index 22d8ad5330b2..cc27631751e3 100644 --- a/buildSrc/src/main/java/org/springframework/build/CompilerConventions.java +++ b/buildSrc/src/main/java/org/springframework/build/CompilerConventions.java @@ -23,7 +23,6 @@ import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.plugins.JavaBasePlugin; -import org.gradle.api.plugins.JavaLibraryPlugin; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.tasks.compile.JavaCompile; @@ -42,7 +41,7 @@ public class CompilerConventions { static { List commonCompilerArgs = Arrays.asList( - "-Xlint:serial", "-Xlint:cast", "-Xlint:classfile", "-Xlint:dep-ann", + "-Xlint:serial", "-Xlint:cast", "-Xlint:-classfile", "-Xlint:dep-ann", "-Xlint:divzero", "-Xlint:empty", "-Xlint:finally", "-Xlint:overrides", "-Xlint:path", "-Xlint:processing", "-Xlint:static", "-Xlint:try", "-Xlint:-options", "-parameters" diff --git a/framework-platform/framework-platform.gradle b/framework-platform/framework-platform.gradle index af042225973b..3055c8a4cf85 100644 --- a/framework-platform/framework-platform.gradle +++ b/framework-platform/framework-platform.gradle @@ -7,7 +7,7 @@ javaPlatform { } dependencies { - api(platform("com.fasterxml.jackson:jackson-bom:2.13.4")) + api(platform("com.fasterxml.jackson:jackson-bom:2.14.0-rc2")) api(platform("io.micrometer:micrometer-bom:1.10.0-RC1")) api(platform("io.netty:netty-bom:4.1.84.Final")) api(platform("io.netty:netty5-bom:5.0.0.Alpha5")) diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2Tokenizer.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2Tokenizer.java index 73e87eb0b8bc..2a8672ca71ae 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2Tokenizer.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2Tokenizer.java @@ -17,6 +17,7 @@ package org.springframework.http.codec.json; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.function.Function; @@ -26,10 +27,13 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.async.ByteArrayFeeder; +import com.fasterxml.jackson.core.async.ByteBufferFeeder; +import com.fasterxml.jackson.core.async.NonBlockingInputFeeder; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.deser.DefaultDeserializationContext; import com.fasterxml.jackson.databind.util.TokenBuffer; +import com.fasterxml.jackson.dataformat.smile.SmileFactory; import reactor.core.Exceptions; import reactor.core.publisher.Flux; @@ -54,6 +58,8 @@ final class Jackson2Tokenizer { private final DeserializationContext deserializationContext; + private final NonBlockingInputFeeder inputFeeder; + private final boolean tokenizeArrayElements; private final boolean forceUseOfBigDecimal; @@ -69,19 +75,14 @@ final class Jackson2Tokenizer { private TokenBuffer tokenBuffer; - // TODO: change to ByteBufferFeeder when supported by Jackson - // See https://github.com/FasterXML/jackson-core/issues/478 - private final ByteArrayFeeder inputFeeder; - - private Jackson2Tokenizer(JsonParser parser, DeserializationContext deserializationContext, boolean tokenizeArrayElements, boolean forceUseOfBigDecimal, int maxInMemorySize) { this.parser = parser; this.deserializationContext = deserializationContext; + this.inputFeeder = this.parser.getNonBlockingInputFeeder(); this.tokenizeArrayElements = tokenizeArrayElements; this.forceUseOfBigDecimal = forceUseOfBigDecimal; - this.inputFeeder = (ByteArrayFeeder) this.parser.getNonBlockingInputFeeder(); this.maxInMemorySize = maxInMemorySize; this.tokenBuffer = createToken(); } @@ -89,13 +90,17 @@ private Jackson2Tokenizer(JsonParser parser, DeserializationContext deserializat private List tokenize(DataBuffer dataBuffer) { - int bufferSize = dataBuffer.readableByteCount(); - byte[] bytes = new byte[bufferSize]; - dataBuffer.read(bytes); - DataBufferUtils.release(dataBuffer); - try { - this.inputFeeder.feedInput(bytes, 0, bytes.length); + int bufferSize = dataBuffer.readableByteCount(); + if (this.inputFeeder instanceof ByteBufferFeeder byteBufferFeeder) { + ByteBuffer byteBuffer = dataBuffer.toByteBuffer(); + byteBufferFeeder.feedInput(byteBuffer); + } + else if (this.inputFeeder instanceof ByteArrayFeeder byteArrayFeeder) { + byte[] bytes = new byte[bufferSize]; + dataBuffer.read(bytes); + byteArrayFeeder.feedInput(bytes, 0, bufferSize); + } List result = parseTokenBufferFlux(); assertInMemorySize(bufferSize, result); return result; @@ -106,6 +111,9 @@ private List tokenize(DataBuffer dataBuffer) { catch (IOException ex) { throw Exceptions.propagate(ex); } + finally { + DataBufferUtils.release(dataBuffer); + } } private Flux endOfInput() { @@ -232,7 +240,14 @@ public static Flux tokenize(Flux dataBuffers, JsonFacto ObjectMapper objectMapper, boolean tokenizeArrays, boolean forceUseOfBigDecimal, int maxInMemorySize) { try { - JsonParser parser = jsonFactory.createNonBlockingByteArrayParser(); + JsonParser parser; + if (jsonFactory.getFormatName().equals(SmileFactory.FORMAT_NAME_SMILE)) { + // ByteBufferFeeder is not supported for Smile + parser = jsonFactory.createNonBlockingByteArrayParser(); + } + else { + parser = jsonFactory.createNonBlockingByteBufferParser(); + } DeserializationContext context = objectMapper.getDeserializationContext(); if (context instanceof DefaultDeserializationContext) { context = ((DefaultDeserializationContext) context).createInstance(