Skip to content

Commit fd2df6c

Browse files
committed
fix race condition
1 parent f10fbf0 commit fd2df6c

1 file changed

Lines changed: 27 additions & 17 deletions

File tree

sdks/java/core/src/main/java/org/apache/beam/sdk/util/RowJsonUtils.java

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package org.apache.beam.sdk.util;
1919

20+
import com.fasterxml.jackson.core.JsonFactory;
2021
import com.fasterxml.jackson.core.JsonParseException;
2122
import com.fasterxml.jackson.core.JsonProcessingException;
2223
import com.fasterxml.jackson.databind.JsonMappingException;
@@ -45,32 +46,41 @@ public class RowJsonUtils {
4546
* overwrite the default buffer size limit to 100 MB, and exposes this interface for higher limit.
4647
* If needed, call this method during pipeline run time, e.g. in DoFn.setup.
4748
*/
48-
public static void increaseDefaultStreamReadConstraints(int newLimit) {
49-
if (newLimit <= defaultBufferLimit) {
50-
return;
51-
}
52-
try {
53-
Class<?> unused = Class.forName("com.fasterxml.jackson.core.StreamReadConstraints");
49+
// The maximum string length for the JSON parser, set to 100 MB.
50+
private static final int MAX_STRING_LENGTH = 100 * 1024 * 1024;
5451

55-
com.fasterxml.jackson.core.StreamReadConstraints.overrideDefaultStreamReadConstraints(
52+
/**
53+
* Creates a thread-safe JsonFactory with custom stream read constraints.
54+
*
55+
* <p>This method encapsulates the logic to increase the default jackson-databind stream read
56+
* constraint to 100MB. This functionality was introduced in Jackson 2.15 causing string > 20MB
57+
* (5MB in <2.15.0) parsing failure. This has caused regressions in its dependencies including
58+
* Beam. Here we create a streamReadConstraints minimum size limit set to 100MB and exposing the
59+
* factory to higher limits. If needed, call this method during pipeline run time, e.g. in
60+
* DoFn.setup. This avoids a data race caused by modifying the global default settings.
61+
*/
62+
private static JsonFactory createJsonFactory(int sizeLimit) {
63+
sizeLimit = Math.max(sizeLimit, MAX_STRING_LENGTH);
64+
JsonFactory jsonFactory = new JsonFactory();
65+
try {
66+
// Check if StreamReadConstraints is available (Jackson 2.15+)
67+
Class.forName("com.fasterxml.jackson.core.StreamReadConstraints");
68+
com.fasterxml.jackson.core.StreamReadConstraints streamReadConstraints =
5669
com.fasterxml.jackson.core.StreamReadConstraints.builder()
57-
.maxStringLength(newLimit)
58-
.build());
70+
.maxStringLength(MAX_STRING_LENGTH)
71+
.build();
72+
jsonFactory.setStreamReadConstraints(streamReadConstraints);
5973
} catch (ClassNotFoundException e) {
60-
// <2.15, do nothing
74+
// If the class is not found (i.e., Jackson version < 2.15), do nothing.
6175
}
62-
defaultBufferLimit = newLimit;
63-
}
64-
65-
static {
66-
increaseDefaultStreamReadConstraints(100 * 1024 * 1024);
76+
return jsonFactory;
6777
}
6878

6979
public static ObjectMapper newObjectMapperWith(RowJson.RowJsonDeserializer deserializer) {
7080
SimpleModule module = new SimpleModule("rowDeserializationModule");
7181
module.addDeserializer(Row.class, deserializer);
7282

73-
ObjectMapper objectMapper = new ObjectMapper();
83+
ObjectMapper objectMapper = new ObjectMapper(createJsonFactory(MAX_STRING_LENGTH));
7484
objectMapper.registerModule(module);
7585

7686
return objectMapper;
@@ -80,7 +90,7 @@ public static ObjectMapper newObjectMapperWith(RowJson.RowJsonSerializer seriali
8090
SimpleModule module = new SimpleModule("rowSerializationModule");
8191
module.addSerializer(Row.class, serializer);
8292

83-
ObjectMapper objectMapper = new ObjectMapper();
93+
ObjectMapper objectMapper = new ObjectMapper(createJsonFactory(MAX_STRING_LENGTH));
8494
objectMapper.registerModule(module);
8595

8696
return objectMapper;

0 commit comments

Comments
 (0)