Skip to content

Commit

Permalink
Handles special case of an unquoted string containing an unresolved v…
Browse files Browse the repository at this point in the history
…ariable reference next to some text. The rendering call from the parser will wrap the string in double quotes if it contains special characters. Since we resolve references at a later time in Helidon config, we need to drop the quotes to avoid altering the config value. See issue 9254.
  • Loading branch information
spericas committed Sep 19, 2024
1 parent df2c26e commit 2be6b01
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 4 deletions.
1 change: 1 addition & 0 deletions config/hocon/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<environmentVariables>
<VAR1>foo</VAR1>
<HOCON_TEST_PROPERTY>This Is My ENV VARS Value.</HOCON_TEST_PROPERTY>
</environmentVariables>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2022 Oracle and/or its affiliates.
* Copyright (c) 2020, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -37,7 +37,9 @@
import com.typesafe.config.ConfigList;
import com.typesafe.config.ConfigObject;
import com.typesafe.config.ConfigParseOptions;
import com.typesafe.config.ConfigRenderOptions;
import com.typesafe.config.ConfigResolveOptions;
import com.typesafe.config.ConfigValue;

/**
* Typesafe (Lightbend) Config (HOCON) {@link ConfigParser} implementation that supports following media types:
Expand Down Expand Up @@ -70,10 +72,13 @@ public class HoconConfigParser implements ConfigParser {
* Priority of the parser used if registered by {@link io.helidon.config.Config.Builder} automatically.
*/
public static final int PRIORITY = ConfigParser.PRIORITY + 100;

private static final List<String> SUPPORTED_SUFFIXES = List.of("json", "conf");
private static final ConfigRenderOptions CONFIG_RENDER_OPTIONS = ConfigRenderOptions.defaults().setJson(false);
private static final Set<String> SUPPORTED_MEDIA_TYPES =
Set.of(MEDIA_TYPE_APPLICATION_HOCON, MEDIA_TYPE_APPLICATION_JSON);


private final boolean resolvingEnabled;
private final ConfigResolveOptions resolveOptions;
private final ConfigParseOptions parseOptions;
Expand Down Expand Up @@ -176,7 +181,7 @@ private static ObjectNode fromConfig(ConfigObject config) {
// An unresolved ConfigReference resolved later in config module since
// Helidon and Hocon use the same reference syntax and resolving here
// would be too early for resolution across sources
builder.addValue(key, value.render());
builder.addValue(key, renderUnresolvedValue(value));
}
}
});
Expand All @@ -202,11 +207,32 @@ private static ListNode fromList(ConfigList list) {
// An unresolved ConfigReference resolved later in config module since
// Helidon and Hocon use the same reference syntax and resolving here
// would be too early for resolution across sources
builder.addValue(value.render());
builder.addValue(renderUnresolvedValue(value));
}
}
});
return builder.build();
}

/**
* <p>Special rendering for a non-structured, unquoted string value that includes
* one or more unresolved variable references such as {@code ${var}}. If an unresolved variable
* is either preceded and/or followed by a string containing non-alphabetic characters,
* it will be rendered in double quotes. For example, {@code ${var}/foo} will be
* rendered as {@code ${var}"/foo"} instead of {@code ${var}/foo}.
*
* <p>Note that if the original string was already in double quotes (not unquoted in
* HOCON terms) it will never throw {@link com.typesafe.config.ConfigException.NotResolved}
* since variable references in quotes are never resolved. This method will never be
* called as a result.
*
* @param unresolved string containing one or more unresolved references, typically a
* concatenation node with a combination of strings and unresolved
* references.
* @return a rendering, possibly with double quotes removed
*/
private static String renderUnresolvedValue(ConfigValue unresolved) {
String rendering = unresolved.render(CONFIG_RENDER_OPTIONS);
return rendering.contains("\"") ? rendering.replace("\"", "") : rendering;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,9 +19,12 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;

import io.helidon.config.ClasspathConfigSource;
import io.helidon.config.Config;
import io.helidon.config.ConfigSources;

import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -55,4 +58,18 @@ void testSubstitution() {
assertThat(list, Matchers.<Collection<String>> allOf(
hasSize(2), hasItem(is("Hello"))));
}

@Test
void testHoconExpansion() {
Config config = Config.create(
ConfigSources.create("foo: ${VAR1}/bar", "application/hocon"));
assertThat(config.get("foo").asString().orElseThrow(NoSuchElementException::new), is("foo/bar"));
}

@Test
void testHoconExpansionQuotes() {
Config config = Config.create(
ConfigSources.create("foo: \"${VAR1}/bar\"", "application/hocon"));
assertThat(config.get("foo").asString().orElseThrow(NoSuchElementException::new), is("foo/bar"));
}
}

0 comments on commit 2be6b01

Please sign in to comment.