Skip to content

Commit 30bdbaf

Browse files
authored
feat: Improve YamlUtils.dumpAsMap error handling (#37468)
* feat: Improve YamlUtils.dumpAsMap error handling by identifying non-serializable keys that cause YAML serialization failures. * style: Reformat YamlUtilsTest for improved readability by adjusting line breaks and spacing.
1 parent 51eec3c commit 30bdbaf

2 files changed

Lines changed: 62 additions & 1 deletion

File tree

sdks/java/core/src/main/java/org/apache/beam/sdk/schemas/utils/YamlUtils.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import java.io.InputStream;
2323
import java.math.BigDecimal;
24+
import java.util.ArrayList;
2425
import java.util.Collections;
2526
import java.util.List;
2627
import java.util.Map;
@@ -36,6 +37,7 @@
3637
import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.io.BaseEncoding;
3738
import org.checkerframework.checker.nullness.qual.Nullable;
3839
import org.yaml.snakeyaml.Yaml;
40+
import org.yaml.snakeyaml.error.YAMLException;
3941

4042
public class YamlUtils {
4143
private static final Map<Schema.TypeName, Function<String, @Nullable Object>> YAML_VALUE_PARSERS =
@@ -181,7 +183,36 @@ public static String yamlStringFromMap(@Nullable Map<String, Object> map) {
181183
if (map == null || map.isEmpty()) {
182184
return "";
183185
}
184-
return new Yaml().dumpAsMap(map);
186+
try {
187+
return new Yaml().dumpAsMap(map);
188+
} catch (YAMLException e) {
189+
List<String> problematicKeys = findNonSerializableKeys(map);
190+
throw new IllegalArgumentException(
191+
String.format(
192+
"Failed to convert configuration map to YAML. "
193+
+ "The following keys contain values that cannot be serialized: %s. "
194+
+ "Please ensure all configuration values are simple types (String, Number, Boolean) "
195+
+ "or properly structured Maps and Lists. Original error: %s",
196+
problematicKeys, e.getMessage()),
197+
e);
198+
}
199+
}
200+
201+
private static List<String> findNonSerializableKeys(Map<String, Object> map) {
202+
List<String> problematicKeys = new ArrayList<>();
203+
Yaml yaml = new Yaml();
204+
for (Map.Entry<String, Object> entry : map.entrySet()) {
205+
try {
206+
yaml.dump(entry.getValue());
207+
} catch (YAMLException e) {
208+
problematicKeys.add(
209+
String.format(
210+
"%s (type: %s)",
211+
entry.getKey(),
212+
entry.getValue() != null ? entry.getValue().getClass().getName() : "null"));
213+
}
214+
}
215+
return problematicKeys;
185216
}
186217

187218
public static Map<String, Object> yamlStringToMap(@Nullable String yaml) {

sdks/java/core/src/test/java/org/apache/beam/sdk/util/YamlUtilsTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,34 @@ public void testSnakeCaseMapToCamelCaseRow() {
258258

259259
assertEquals(expectedRow, convertedRow);
260260
}
261+
262+
@Test
263+
public void testYamlStringFromMapWithNonSerializableObject() {
264+
// Create a map with ImmutableMap.Builder which cannot be serialized
265+
Map<String, Object> configWithBuilder = new java.util.HashMap<>();
266+
configWithBuilder.put("good_key", "valid_value");
267+
configWithBuilder.put(
268+
"bad_key",
269+
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableMap
270+
.builder()); // Not yet built!
271+
272+
// We expect an IllegalArgumentException with a helpful message
273+
thrown.expect(IllegalArgumentException.class);
274+
thrown.expectMessage("Failed to convert configuration map to YAML");
275+
thrown.expectMessage("bad_key");
276+
thrown.expectMessage("ImmutableMap$Builder");
277+
278+
YamlUtils.yamlStringFromMap(configWithBuilder);
279+
}
280+
281+
@Test
282+
public void testYamlStringFromMapWithValidMap() {
283+
Map<String, Object> config =
284+
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableMap.of(
285+
"string_key", "value", "int_key", 123, "boolean_key", true);
286+
287+
String yaml = YamlUtils.yamlStringFromMap(config);
288+
org.junit.Assert.assertNotNull(yaml);
289+
org.junit.Assert.assertTrue(yaml.contains("string_key"));
290+
}
261291
}

0 commit comments

Comments
 (0)