diff --git a/flink-core/src/main/java/org/apache/flink/configuration/ConfigurationUtils.java b/flink-core/src/main/java/org/apache/flink/configuration/ConfigurationUtils.java
index 58cbd620edec4..66f92fe44c49c 100755
--- a/flink-core/src/main/java/org/apache/flink/configuration/ConfigurationUtils.java
+++ b/flink-core/src/main/java/org/apache/flink/configuration/ConfigurationUtils.java
@@ -28,6 +28,7 @@
import java.io.File;
import java.time.Duration;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -200,6 +201,62 @@ public static String[] splitPaths(@Nonnull String separatedPaths) {
: EMPTY;
}
+ /**
+ * Converts the provided configuration data into a format suitable for writing to a file, based
+ * on the {@code flattenYaml} flag and the {@code standardYaml} attribute of the configuration
+ * object.
+ *
+ *
Only when {@code flattenYaml} is set to {@code false} and the configuration object is
+ * standard yaml, a nested YAML format is used. Otherwise, a flat key-value pair format is
+ * output.
+ *
+ *
Each entry in the returned list represents a single line that can be written directly to a
+ * file.
+ *
+ *
Example input (flat map configuration data):
+ *
+ *
{@code
+ * {
+ * "parent.child": "value1",
+ * "parent.child2": "value2"
+ * }
+ * }
+ *
+ * Example output when {@code flattenYaml} is {@code false} and the configuration object is
+ * standard yaml:
+ *
+ *
{@code
+ * parent:
+ * child: value1
+ * child2: value2
+ * }
+ *
+ * Otherwise, the Example output is:
+ *
+ *
{@code
+ * parent.child: value1
+ * parent.child2: value2
+ * }
+ *
+ * @param configuration The configuration to be converted.
+ * @param flattenYaml A boolean flag indicating if the configuration data should be output in a
+ * flattened format.
+ * @return A list of strings, where each string represents a line of the file-writable data in
+ * the chosen format.
+ */
+ public static List convertConfigToWritableLines(
+ Configuration configuration, boolean flattenYaml) {
+ if (configuration.standardYaml && !flattenYaml) {
+ return YamlParserUtils.convertAndDumpYamlFromFlatMap(
+ Collections.unmodifiableMap(configuration.confData));
+ } else {
+ Map fileWritableMap = configuration.toFileWritableMap();
+ return fileWritableMap.entrySet().stream()
+ .map(entry -> entry.getKey() + ": " + entry.getValue())
+ .collect(Collectors.toList());
+ }
+ }
+
/**
* Creates a dynamic parameter list {@code String} of the passed configuration map.
*
diff --git a/flink-core/src/main/java/org/apache/flink/configuration/YamlParserUtils.java b/flink-core/src/main/java/org/apache/flink/configuration/YamlParserUtils.java
index c4388c61d7165..ae9280b3a8646 100644
--- a/flink-core/src/main/java/org/apache/flink/configuration/YamlParserUtils.java
+++ b/flink-core/src/main/java/org/apache/flink/configuration/YamlParserUtils.java
@@ -42,7 +42,10 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.Duration;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -131,6 +134,39 @@ public static synchronized String toYAMLString(Object value) {
}
}
+ /**
+ * Converts a flat map into a nested map structure and outputs the result as a list of
+ * YAML-formatted strings. Each item in the list represents a single line of the YAML data. The
+ * method is synchronized and thus thread-safe.
+ *
+ * @param flattenMap A map containing flattened keys (e.g., "parent.child.key") associated with
+ * their values.
+ * @return A list of strings that represents the YAML data, where each item corresponds to a
+ * line of the data.
+ */
+ @SuppressWarnings("unchecked")
+ public static synchronized List convertAndDumpYamlFromFlatMap(
+ Map flattenMap) {
+ try {
+ Map nestedMap = new LinkedHashMap<>();
+ for (Map.Entry entry : flattenMap.entrySet()) {
+ String[] keys = entry.getKey().split("\\.");
+ Map currentMap = nestedMap;
+ for (int i = 0; i < keys.length - 1; i++) {
+ currentMap =
+ (Map)
+ currentMap.computeIfAbsent(keys[i], k -> new LinkedHashMap<>());
+ }
+ currentMap.put(keys[keys.length - 1], entry.getValue());
+ }
+ String data = yaml.dumpAsMap(nestedMap);
+ String linebreak = dumperOptions.getLineBreak().getString();
+ return Arrays.asList(data.split(linebreak));
+ } catch (MarkedYAMLException exception) {
+ throw wrapExceptionToHiddenSensitiveData(exception);
+ }
+ }
+
public static synchronized T convertToObject(String value, Class type) {
try {
return yaml.loadAs(value, type);
diff --git a/flink-core/src/test/java/org/apache/flink/configuration/ConfigurationUtilsTest.java b/flink-core/src/test/java/org/apache/flink/configuration/ConfigurationUtilsTest.java
index c94bd69745450..757bf9e953c6b 100644
--- a/flink-core/src/test/java/org/apache/flink/configuration/ConfigurationUtilsTest.java
+++ b/flink-core/src/test/java/org/apache/flink/configuration/ConfigurationUtilsTest.java
@@ -21,6 +21,7 @@
import org.apache.flink.testutils.junit.extensions.parameterized.Parameter;
import org.apache.flink.testutils.junit.extensions.parameterized.ParameterizedTestExtension;
import org.apache.flink.testutils.junit.extensions.parameterized.Parameters;
+import org.apache.flink.util.TimeUtils;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestTemplate;
@@ -96,6 +97,92 @@ void testStandardYamlSupportLegacyPattern() {
.isEqualTo(expectedMap);
}
+ @TestTemplate
+ void testConvertConfigToWritableLinesAndFlattenYaml() {
+ testConvertConfigToWritableLines(true);
+ }
+
+ @TestTemplate
+ void testConvertConfigToWritableLinesAndNoFlattenYaml() {
+ testConvertConfigToWritableLines(false);
+ }
+
+ private void testConvertConfigToWritableLines(boolean flattenYaml) {
+ final Configuration configuration = new Configuration(standardYaml);
+ ConfigOption> nestedListOption =
+ ConfigOptions.key("nested.test-list-key").stringType().asList().noDefaultValue();
+ final String listValues = "value1;value2;value3";
+ final String yamlListValues = "[value1, value2, value3]";
+ configuration.set(nestedListOption, Arrays.asList(listValues.split(";")));
+
+ ConfigOption