From 67a70eb7aef5f36f57602320994181ce03c59c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Fri, 17 Apr 2026 13:10:48 +0200 Subject: [PATCH 1/6] fix handling empty yaml config file with a comment only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../loader/provider/YamlConfigProvider.java | 3 +++ .../provider/YamlConfigProviderTest.java | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java index d631496d59..69cf0b4dab 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java @@ -103,6 +103,9 @@ private static Map load(Path path) { try (InputStream in = Files.newInputStream(path)) { Map result = MAPPER.readValue(in, Map.class); return result != null ? result : Map.of(); + } catch (com.fasterxml.jackson.databind.exc.MismatchedInputException e) { + log.warn("{} contains no configuration data", path); + return Map.of(); } catch (IOException e) { throw new UncheckedIOException("Failed to load config YAML from " + path, e); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java index 2362b85ea4..22df345751 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java @@ -132,6 +132,27 @@ void loadsFromFile(@TempDir Path dir) throws IOException { assertThat(provider.getValue("josdk.test.integer", Integer.class)).hasValue(7); } + @Test + void returnsEmptyForEmptyFile(@TempDir Path dir) throws IOException { + Path file = dir.resolve("empty.yaml"); + Files.writeString(file, ""); + + var provider = new YamlConfigProvider(file); + assertThat(provider.getValue("any.key", String.class)).isEmpty(); + } + + @Test + void fileWithCommentOnly(@TempDir Path dir) throws IOException { + Path file = dir.resolve("empty.yaml"); + Files.writeString( + file, + """ + # sample comment + """); + var provider = new YamlConfigProvider(file); + assertThat(provider.getValue("any.key", String.class)).isEmpty(); + } + @Test void returnsEmptyForNonExistingFile(@TempDir Path dir) { Path missing = dir.resolve("does-not-exist.yaml"); From ce83169dbddd66e2263d007cb1d0c9cc8adbbd56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 20 Apr 2026 12:03:59 +0200 Subject: [PATCH 2/6] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/config/loader/provider/YamlConfigProviderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java index 22df345751..feed702064 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java @@ -133,7 +133,7 @@ void loadsFromFile(@TempDir Path dir) throws IOException { } @Test - void returnsEmptyForEmptyFile(@TempDir Path dir) throws IOException { + void emptyFile(@TempDir Path dir) throws IOException { Path file = dir.resolve("empty.yaml"); Files.writeString(file, ""); From 1732ee4cc0aa17956a24c9ca8ae7ff9f82582a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 Apr 2026 14:41:10 +0200 Subject: [PATCH 3/6] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/config/loader/provider/YamlConfigProvider.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java index 69cf0b4dab..22fae9d913 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java @@ -104,7 +104,11 @@ private static Map load(Path path) { Map result = MAPPER.readValue(in, Map.class); return result != null ? result : Map.of(); } catch (com.fasterxml.jackson.databind.exc.MismatchedInputException e) { - log.warn("{} contains no configuration data", path); + log.warn( + "There was issue with parsing configuration data from file. " + + "Will skip loading properties from it. Path: {}", + path, + e); return Map.of(); } catch (IOException e) { throw new UncheckedIOException("Failed to load config YAML from " + path, e); From 5be54d149097eded294e2d4fbbe142e59a1f0fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 Apr 2026 14:47:37 +0200 Subject: [PATCH 4/6] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../loader/provider/YamlConfigProvider.java | 18 +++++++---- .../provider/YamlConfigProviderTest.java | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java index 22fae9d913..7dc758524f 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java @@ -104,12 +104,18 @@ private static Map load(Path path) { Map result = MAPPER.readValue(in, Map.class); return result != null ? result : Map.of(); } catch (com.fasterxml.jackson.databind.exc.MismatchedInputException e) { - log.warn( - "There was issue with parsing configuration data from file. " - + "Will skip loading properties from it. Path: {}", - path, - e); - return Map.of(); + // A comment-only or empty YAML file produces no tokens, which Jackson reports + // as "No content to map due to end-of-input". Treat this as an empty config. + if (e.getMessage() != null + && e.getMessage().startsWith("No content to map due to end-of-input")) { + log.debug( + "YAML file contains no mappings (possibly empty or comments only). " + + "Returning empty config. Path: {}", + path); + return Map.of(); + } + throw new UncheckedIOException( + "Failed to parse config YAML from " + path + ": " + e.getMessage(), e); } catch (IOException e) { throw new UncheckedIOException("Failed to load config YAML from " + path, e); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java index feed702064..5321000a66 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java @@ -16,6 +16,7 @@ package io.javaoperatorsdk.operator.config.loader.provider; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; @@ -26,6 +27,7 @@ import org.junit.jupiter.api.io.TempDir; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; class YamlConfigProviderTest { @@ -159,4 +161,33 @@ void returnsEmptyForNonExistingFile(@TempDir Path dir) { var provider = new YamlConfigProvider(missing); assertThat(provider.getValue("any.key", String.class)).isEmpty(); } + + @Test + void throwsForMalformedYaml(@TempDir Path dir) throws IOException { + Path file = dir.resolve("bad.yaml"); + // YAML list where a map is expected + Files.writeString( + file, + """ + - item1 + - item2 + """); + assertThatExceptionOfType(UncheckedIOException.class) + .isThrownBy(() -> new YamlConfigProvider(file)); + } + + @Test + void commentWithProperDocument(@TempDir Path dir) throws IOException { + Path file = dir.resolve("filewithcomment.yaml"); + // YAML list where a map is expected + Files.writeString( + file, + """ + # comment + key: + subkey: val + """); + var provider = new YamlConfigProvider(file); + assertThat(provider.getValue("key.subkey", String.class)).contains("val"); + } } From 14a63249845d14c0f2189bc645cb9446ec14775f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 Apr 2026 16:20:12 +0200 Subject: [PATCH 5/6] Update operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../operator/config/loader/provider/YamlConfigProviderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java index 5321000a66..328ac6d83f 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProviderTest.java @@ -179,7 +179,7 @@ void throwsForMalformedYaml(@TempDir Path dir) throws IOException { @Test void commentWithProperDocument(@TempDir Path dir) throws IOException { Path file = dir.resolve("filewithcomment.yaml"); - // YAML list where a map is expected + // YAML comment followed by a proper mapping document Files.writeString( file, """ From bfc8b5afa1c981f1efffd1f9449be1da77e6984c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 Apr 2026 16:20:48 +0200 Subject: [PATCH 6/6] Update operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../loader/provider/YamlConfigProvider.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java index 7dc758524f..fc80e46a43 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/provider/YamlConfigProvider.java @@ -100,22 +100,17 @@ private static Map load(Path path) { return Map.of(); } - try (InputStream in = Files.newInputStream(path)) { - Map result = MAPPER.readValue(in, Map.class); - return result != null ? result : Map.of(); - } catch (com.fasterxml.jackson.databind.exc.MismatchedInputException e) { - // A comment-only or empty YAML file produces no tokens, which Jackson reports - // as "No content to map due to end-of-input". Treat this as an empty config. - if (e.getMessage() != null - && e.getMessage().startsWith("No content to map due to end-of-input")) { + try (InputStream in = Files.newInputStream(path); + com.fasterxml.jackson.core.JsonParser parser = MAPPER.getFactory().createParser(in)) { + if (parser.nextToken() == null) { log.debug( "YAML file contains no mappings (possibly empty or comments only). " + "Returning empty config. Path: {}", path); return Map.of(); } - throw new UncheckedIOException( - "Failed to parse config YAML from " + path + ": " + e.getMessage(), e); + Map result = MAPPER.readValue(parser, Map.class); + return result != null ? result : Map.of(); } catch (IOException e) { throw new UncheckedIOException("Failed to load config YAML from " + path, e); }