From 7589a9c4e7cf6d013cd705e31c70cc30487bd785 Mon Sep 17 00:00:00 2001 From: hdavidh Date: Thu, 25 Sep 2025 11:14:22 -0700 Subject: [PATCH] Optimizations for EnhancedDocument.toJson() --- ...-AmazonDynamoDBEnhancedClient-18f50d7.json | 6 ++ .../document/JsonStringFormatHelper.java | 88 ++++++++++++------- 2 files changed, 64 insertions(+), 30 deletions(-) create mode 100644 .changes/next-release/bugfix-AmazonDynamoDBEnhancedClient-18f50d7.json diff --git a/.changes/next-release/bugfix-AmazonDynamoDBEnhancedClient-18f50d7.json b/.changes/next-release/bugfix-AmazonDynamoDBEnhancedClient-18f50d7.json new file mode 100644 index 000000000000..09ab79defe42 --- /dev/null +++ b/.changes/next-release/bugfix-AmazonDynamoDBEnhancedClient-18f50d7.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "Amazon DynamoDB Enhanced Client", + "contributor": "", + "description": "Optimizations for DDB EnhancedDocument.toJson()" +} diff --git a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/document/JsonStringFormatHelper.java b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/document/JsonStringFormatHelper.java index 327653a9eb04..2381f1943d4d 100644 --- a/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/document/JsonStringFormatHelper.java +++ b/services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/document/JsonStringFormatHelper.java @@ -46,44 +46,72 @@ public static String stringValue(JsonNode jsonNode) { } /** - * Escapes characters for a give given string + * Escapes characters for a given string * * @param input Input string * @return String with escaped characters. */ public static String addEscapeCharacters(String input) { - StringBuilder output = new StringBuilder(); - for (int i = 0; i < input.length(); i++) { + StringBuilder output = null; + int len = input.length(); + + for (int i = 0; i < len; i++) { char ch = input.charAt(i); - switch (ch) { - case '\\': - output.append("\\\\"); // escape backslash with a backslash - break; - case '\n': - output.append("\\n"); // newline character - break; - case '\r': - output.append("\\r"); // carriage return character - break; - case '\t': - output.append("\\t"); // tab character - break; - case '\f': - output.append("\\f"); // form feed - break; - case '\"': - output.append("\\\""); // double-quote character - break; - default: - if (Character.isISOControl(ch)) { - output.append(String.format("\\u%04X", (int) ch)); - } else { - output.append(ch); - } - break; + if (needsEscaping(ch)) { + if (output == null) { + output = initializeStringBuilder(input, i); + } + appendEscapeChar(output, ch); + } else if (output != null) { + output.append(ch); } } - return output.toString(); + + return output == null ? input : output.toString(); + } + + private static boolean needsEscaping(char ch) { + return Character.isISOControl(ch) || ch == '"' || ch == '\\'; + } + + /** + * Initialize StringBuilder with the unescaped portion of the input. + */ + private static StringBuilder initializeStringBuilder(String input, int position) { + // Arbitrary buffer of 16 + StringBuilder builder = new StringBuilder(input.length() + 16); + builder.append(input, 0, position); + return builder; + } + + private static void appendEscapeChar(StringBuilder output, char ch) { + switch (ch) { + case '\\': + output.append("\\\\"); // escape backslash with a backslash + break; + case '\n': + output.append("\\n"); // newline character + break; + case '\r': + output.append("\\r"); // carriage return character + break; + case '\t': + output.append("\\t"); // tab character + break; + case '\f': + output.append("\\f"); // form feed + break; + case '\"': + output.append("\\\""); // double-quote character + break; + default: + if (Character.isISOControl(ch)) { + output.append(String.format("\\u%04X", (int) ch)); + } else { + output.append(ch); + } + break; + } } private static String mapToString(JsonNode jsonNode) {