Skip to content

Commit e067db2

Browse files
Save work
Services.contains(Class<?>) to implement an alternative to GlobalConfig.configured() Fix copyright Fix checktyle micronaut tests shouldn't run during the build Save work Add package private constructor for ConfigRef restore CoreServiceRegistry
1 parent 0dd9315 commit e067db2

File tree

41 files changed

+1675
-1046
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1675
-1046
lines changed

common/config/src/main/java/io/helidon/common/config/Config.java

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* @deprecated use {@code io.helidon.config.Config} instead
3030
*/
3131
@Deprecated(forRemoval = true, since = "4.3.0")
32+
@SuppressWarnings("removal")
3233
public interface Config {
3334
/**
3435
* Empty instance of {@code Config}.
@@ -47,7 +48,7 @@ static Config empty() {
4748
* @return a new configuration
4849
*/
4950
static Config create() {
50-
return GlobalConfig.create();
51+
return ConfigFactory.createDefault();
5152
}
5253

5354
/**
@@ -69,12 +70,11 @@ static Config create() {
6970
* <p>
7071
* The name of a node is the last token in its fully-qualified key.
7172
* <p>
72-
* The exact format of the name depends on the {@code Type} of the
73-
* containing node:
73+
* The exact format of the name depends on the type of the containing node:
7474
* <ul>
75-
* <li>from a Type#OBJECT node the token for a child is the
75+
* <li>from an "object" node the token for a child is the
7676
* <strong>name of the object member</strong>;</li>
77-
* <li>from a Type#LIST node the token for a child is a zero-based
77+
* <li>from a "list" node the token for a child is a zero-based
7878
* <strong>index of the element</strong>, an unsigned base-10 integer value
7979
* with no leading zeros.</li>
8080
* </ul>
@@ -206,25 +206,25 @@ default Config get(Key key) {
206206
boolean isLeaf();
207207

208208
/**
209-
* Returns {@code true} if this node exists and is Type#Object.
209+
* Returns {@code true} if this node exists and is an "object" node.
210210
*
211-
* @return {@code true} if the node exists and is Type#Object, {@code false}
211+
* @return {@code true} if the node exists and is an "object" node, {@code false}
212212
* otherwise.
213213
*/
214214
boolean isObject();
215215

216216
/**
217-
* Returns {@code true} if this node exists and is Type#List.
217+
* Returns {@code true} if this node exists and is a "list" node.
218218
*
219-
* @return {@code true} if the node exists and is Type#List, {@code false}
219+
* @return {@code true} if the node exists and is a "list" node, {@code false}
220220
* otherwise.
221221
*/
222222
boolean isList();
223223

224224
/**
225225
* Returns {@code true} if this configuration node has a direct value.
226226
* <p>
227-
* This may be a value node (e.g. a leaf) or object node or a list node
227+
* This may be a "value" node (e.g. a leaf) or "object" node or a "list" node
228228
* (e.g. a branch with value). The application can invoke methods such as
229229
* {@link #as(Class)} on nodes that have value.
230230
*
@@ -274,30 +274,30 @@ default Config get(Key key) {
274274
/**
275275
* Returns this node as a list mapping each list value using the provided mapper.
276276
*
277-
* @param mapper mapper to convert each list node into a typed value
277+
* @param mapper mapper to convert each "list" node into a typed value
278278
* @param <T> type of list elements
279279
* @return a typed list with values
280280
* @throws io.helidon.common.config.ConfigException in case the mapper fails to map the values
281281
*/
282282
<T> ConfigValue<List<T>> mapList(Function<Config, T> mapper) throws ConfigException;
283283

284284
/**
285-
* Returns a list of child {@code Config} nodes if the node is {@code Type#OBJECT}.
286-
* Returns a list of element nodes if the node is {@code Type#LIST}.
287-
* Throws {@code MissingValueException} if the node is {@code Type#MISSING}.
288-
* Otherwise, if node is {@code Type#VALUE}, it throws {@code ConfigMappingException}.
285+
* Returns a list of child {@code Config} nodes if the node is an "object" node.
286+
* Returns a list of element nodes if the node is a "list" node.
287+
* Throws {@code MissingValueException} if the node is a missing node.
288+
* Otherwise, if the node is a "value" node, it throws {@code ConfigMappingException}.
289289
*
290-
* @return a list of {@code Type#OBJECT} members or a list of {@code Type#LIST} members
290+
* @return a list of "object" node members or a list of "list" node members
291291
* @param <C> the common config derived type
292-
* @throws io.helidon.common.config.ConfigException in case the node is {@code Type#VALUE}
292+
* @throws io.helidon.common.config.ConfigException in case the node is a "value" node
293293
*/
294294
<C extends Config> ConfigValue<List<C>> asNodeList() throws ConfigException;
295295

296296
/**
297297
* Transform all leaf nodes (values) into Map instance.
298298
*
299299
* @return new Map instance that contains all config leaf node values
300-
* @throws io.helidon.common.config.ConfigException in case the node is Type#MISSING.
300+
* @throws io.helidon.common.config.ConfigException in case the node is a "missing" node.
301301
*/
302302
ConfigValue<Map<String, String>> asMap() throws ConfigException;
303303

@@ -363,8 +363,8 @@ default ConfigValue<Double> asDouble() {
363363
* Fully-qualified key is list of key tokens separated by {@code .} (dot character).
364364
* Depending on context the key token is evaluated one by one:
365365
* <ul>
366-
* <li>in Type#OBJECT node the token represents a <strong>name of object member</strong>;</li>
367-
* <li>in Type#LIST node the token represents an zero-based <strong>index of list
366+
* <li>in "object" nodes the token represents a <strong>name of object member</strong>;</li>
367+
* <li>in "list" nodes the token represents a zero-based <strong>index of list
368368
* element</strong>,
369369
* an unsigned base-10 integer value, leading zeros are not allowed.</li>
370370
* </ul>
@@ -445,9 +445,9 @@ static String unescapeName(String escapedName) {
445445
* The name of a node is the last token in fully-qualified key.
446446
* Depending on context the name is evaluated one by one:
447447
* <ul>
448-
* <li>in Type#OBJECT} node the name represents a <strong>name of object member</strong>;
448+
* <li>in "object" nodes the name represents a <strong>name of object member</strong>;
449449
* </li>
450-
* <li>in Type#LIST} node the name represents an zero-based <strong>index of list
450+
* <li>in "list" nodes the name represents a zero-based <strong>index of list
451451
* element</strong>,
452452
* an unsigned base-10 integer value, leading zeros are not allowed.</li>
453453
* </ul>
@@ -475,5 +475,4 @@ static String unescapeName(String escapedName) {
475475
Key child(Key key);
476476

477477
}
478-
479478
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
* Copyright (c) 2025 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.helidon.common.config;
17+
18+
import java.util.List;
19+
import java.util.Map;
20+
import java.util.function.Function;
21+
import java.util.function.Supplier;
22+
import java.util.stream.Stream;
23+
24+
/**
25+
* Config delegate backed by a supplier.
26+
*/
27+
@SuppressWarnings("removal")
28+
final class ConfigDelegate implements Config {
29+
30+
private final Supplier<Config> delegate;
31+
32+
ConfigDelegate(Supplier<Config> delegate) {
33+
this.delegate = delegate;
34+
}
35+
36+
@Override
37+
public Key key() {
38+
return delegate.get().key();
39+
}
40+
41+
@Override
42+
public String name() {
43+
return delegate.get().name();
44+
}
45+
46+
@Override
47+
public Config get(String key) throws ConfigException {
48+
return delegate.get().get(key);
49+
}
50+
51+
@Override
52+
public Config root() {
53+
return delegate.get().root();
54+
}
55+
56+
@Override
57+
public Config get(Key key) {
58+
return delegate.get().get(key);
59+
}
60+
61+
@Override
62+
public Config detach() throws ConfigException {
63+
return delegate.get().detach();
64+
}
65+
66+
@Override
67+
public boolean exists() {
68+
return delegate.get().exists();
69+
}
70+
71+
@Override
72+
public Stream<? extends Config> traverse() {
73+
return delegate.get().traverse();
74+
}
75+
76+
@Override
77+
public boolean isLeaf() {
78+
return delegate.get().isLeaf();
79+
}
80+
81+
@Override
82+
public boolean isObject() {
83+
return delegate.get().isObject();
84+
}
85+
86+
@Override
87+
public boolean isList() {
88+
return delegate.get().isList();
89+
}
90+
91+
@Override
92+
public boolean hasValue() {
93+
return delegate.get().hasValue();
94+
}
95+
96+
@Override
97+
public <T> ConfigValue<T> as(Class<T> type) {
98+
return delegate.get().as(type);
99+
}
100+
101+
@Override
102+
public <T> ConfigValue<T> map(Function<Config, T> mapper) {
103+
return delegate.get().map(mapper);
104+
}
105+
106+
@Override
107+
public <T> ConfigValue<List<T>> asList(Class<T> type) throws ConfigException {
108+
return delegate.get().asList(type);
109+
}
110+
111+
@Override
112+
public <T> ConfigValue<List<T>> mapList(Function<Config, T> mapper) throws ConfigException {
113+
return delegate.get().mapList(mapper);
114+
}
115+
116+
@Override
117+
public <C extends Config> ConfigValue<List<C>> asNodeList() throws ConfigException {
118+
return delegate.get().asNodeList();
119+
}
120+
121+
@Override
122+
public ConfigValue<Map<String, String>> asMap() throws ConfigException {
123+
return delegate.get().asMap();
124+
}
125+
126+
@Override
127+
public ConfigValue<? extends Config> asNode() {
128+
return delegate.get().asNode();
129+
}
130+
131+
@Override
132+
public ConfigValue<String> asString() {
133+
return delegate.get().asString();
134+
}
135+
136+
@Override
137+
public ConfigValue<Boolean> asBoolean() {
138+
return delegate.get().asBoolean();
139+
}
140+
141+
@Override
142+
public ConfigValue<Integer> asInt() {
143+
return delegate.get().asInt();
144+
}
145+
146+
@Override
147+
public ConfigValue<Long> asLong() {
148+
return delegate.get().asLong();
149+
}
150+
151+
@Override
152+
public ConfigValue<Double> asDouble() {
153+
return delegate.get().asDouble();
154+
}
155+
}

common/config/src/main/java/io/helidon/common/config/ConfigFactory.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,44 @@
1818

1919
import java.util.function.Supplier;
2020

21+
import io.helidon.common.LazyValue;
2122
import io.helidon.common.Weight;
2223
import io.helidon.common.Weighted;
2324
import io.helidon.service.registry.Service;
25+
import io.helidon.service.registry.Services;
2426

2527
/**
26-
* Default factory for configuration, that returns the current global config, or creates a new config instance.
27-
* This is to ensure we have a config instance in service registry even when there is no config implementation on classpath.
28+
* Default {@link Config} factory.
29+
* This factory exists as a fallback if there is no config implementation on classpath.
30+
* <br>
31+
* The created config instance is a delegate that honors the current "global" config.
2832
*/
29-
@SuppressWarnings("removal")
30-
@Weight(Weighted.DEFAULT_WEIGHT - 20)
3133
@Service.Singleton
34+
@Weight(Weighted.DEFAULT_WEIGHT - 20)
35+
@SuppressWarnings({"removal", "ClassCanBeRecord"})
3236
class ConfigFactory implements Supplier<Config> {
37+
38+
private final LazyValue<Config> defaultConfig;
39+
private final ConfigRef ref;
40+
41+
@Service.Inject
42+
ConfigFactory(io.helidon.common.config.spi.ConfigProvider provider, ConfigRef ref) {
43+
this.defaultConfig = LazyValue.create(provider::create);
44+
this.ref = ref;
45+
}
46+
3347
@Override
3448
public Config get() {
35-
// once GlobalConfig gets removed, we just return Config.create()
36-
return GlobalConfig.configured() ? GlobalConfig.config() : Config.create();
49+
return new ConfigDelegate(this::delegate);
50+
}
51+
52+
private Config delegate() {
53+
return ref.isSet() ? ref.get() : defaultConfig.get();
54+
}
55+
56+
static Config createDefault() {
57+
return Services.first(io.helidon.common.config.spi.ConfigProvider.class)
58+
.map(io.helidon.common.config.spi.ConfigProvider::create)
59+
.orElse(Config.empty());
3760
}
3861
}

0 commit comments

Comments
 (0)