1717 */
1818package org .apache .beam .sdk .util ;
1919
20+ import com .fasterxml .jackson .core .JsonFactory ;
2021import com .fasterxml .jackson .core .JsonParseException ;
2122import com .fasterxml .jackson .core .JsonProcessingException ;
2223import 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