11/*
2- * Copyright (c) 2022, 2024 Oracle and/or its affiliates.
2+ * Copyright (c) 2022, 2025 Oracle and/or its affiliates.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1616
1717package io .helidon .config ;
1818
19+ import java .time .Instant ;
1920import java .util .ArrayList ;
2021import java .util .List ;
22+ import java .util .Map ;
2123import java .util .Optional ;
2224import java .util .Set ;
25+ import java .util .function .Consumer ;
26+ import java .util .function .Function ;
27+ import java .util .function .Predicate ;
2328import java .util .function .Supplier ;
2429import java .util .stream .Collectors ;
30+ import java .util .stream .Stream ;
2531
26- import io .helidon .common .config .Config ;
32+ import io .helidon .common .GenericType ;
33+ import io .helidon .common .Weight ;
34+ import io .helidon .common .Weighted ;
2735import io .helidon .config .spi .ConfigFilter ;
36+ import io .helidon .config .spi .ConfigMapper ;
2837import io .helidon .config .spi .ConfigMapperProvider ;
2938import io .helidon .config .spi .ConfigParser ;
3039import io .helidon .config .spi .ConfigSource ;
3140import io .helidon .service .registry .Service ;
3241
3342@ Service .Singleton
43+ @ Weight (Weighted .DEFAULT_WEIGHT - 10 ) // less than default, so it can be easily overridden
3444class ConfigProvider implements Supplier <Config > {
3545 private final Config config ;
3646
@@ -42,11 +52,11 @@ class ConfigProvider implements Supplier<Config> {
4252 Supplier <List <ConfigFilter >> configFilters ,
4353 Supplier <List <ConfigMapperProvider >> configMappers ) {
4454 if (io .helidon .common .config .GlobalConfig .configured ()) {
45- config = io .helidon .common .config .GlobalConfig .config ();
55+ config = wrapCommon ( io .helidon .common .config .GlobalConfig .config () );
4656 } else {
47- config = io . helidon . config . Config .builder ()
57+ config = Config .builder ()
4858 .update (it -> metaConfig .get ().ifPresent (metaConfigInstance ->
49- it .config (metaConfigInstance .metaConfiguration ())))
59+ it .config (metaConfigInstance .metaConfiguration ())))
5060 .update (it -> configSources .get ()
5161 .forEach (it ::addSource ))
5262 .update (it -> defaultConfigSources (it , configParsers ))
@@ -71,6 +81,13 @@ public Config get() {
7181 return config ;
7282 }
7383
84+ private Config wrapCommon (io .helidon .common .config .Config config ) {
85+ if (config instanceof Config cfg ) {
86+ return cfg ;
87+ }
88+ return new CommonConfigWrapper (Config .empty (), config );
89+ }
90+
7491 private void defaultConfigSources (io .helidon .config .Config .Builder configBuilder ,
7592 Supplier <List <ConfigParser >> configParsers ) {
7693
@@ -87,6 +104,225 @@ private void defaultConfigSources(io.helidon.config.Config.Builder configBuilder
87104 // default config source(s)
88105 MetaConfigFinder .configSources (new ArrayList <>(supportedSuffixes ))
89106 .forEach (configBuilder ::addSource );
107+ }
108+
109+ private static class CommonConfigWrapper implements Config {
110+ private final Config emptyConfig ;
111+ private final Instant timestamp ;
112+ private final io .helidon .common .config .Config delegate ;
113+
114+ private CommonConfigWrapper (Config realConfig , io .helidon .common .config .Config delegate ) {
115+ this (realConfig , Instant .now (), delegate );
116+ }
117+
118+ private CommonConfigWrapper (Config realConfig ,
119+ Instant timestamp ,
120+ io .helidon .common .config .Config delegate ) {
121+ this .emptyConfig = realConfig ;
122+ this .delegate = delegate ;
123+ this .timestamp = timestamp ;
124+ }
125+
126+ @ Override
127+ public Instant timestamp () {
128+ return timestamp ;
129+ }
130+
131+ @ Override
132+ public Key key () {
133+ return new CommonKeyWrapper (delegate .key ());
134+ }
135+
136+ @ Override
137+ public String name () {
138+ return delegate .name ();
139+ }
140+
141+ @ Override
142+ public Config get (String key ) {
143+ return new CommonConfigWrapper (emptyConfig , timestamp , delegate .get (key ));
144+ }
145+
146+ @ Override
147+ public Config root () {
148+ return new CommonConfigWrapper (emptyConfig , timestamp , delegate .root ());
149+ }
150+
151+ @ Override
152+ public Config get (Key key ) {
153+ return new CommonConfigWrapper (emptyConfig , timestamp , delegate .get (key ));
154+ }
155+
156+ @ Override
157+ public Config detach () {
158+ return new CommonConfigWrapper (emptyConfig , timestamp , delegate .detach ());
159+ }
160+
161+ @ Override
162+ public Type type () {
163+ if (delegate .isList ()) {
164+ return Type .LIST ;
165+ }
166+ if (delegate .isObject ()) {
167+ return Type .OBJECT ;
168+ }
169+ if (delegate .exists ()) {
170+ return Type .VALUE ;
171+ }
172+ return Type .MISSING ;
173+ }
174+
175+ @ Override
176+ public boolean exists () {
177+ return delegate .exists ();
178+ }
179+
180+ @ Override
181+ public boolean isLeaf () {
182+ return delegate .isLeaf ();
183+ }
184+
185+ @ Override
186+ public boolean isObject () {
187+ return delegate .isObject ();
188+ }
189+
190+ @ Override
191+ public boolean isList () {
192+ return delegate .isList ();
193+ }
194+
195+ @ Override
196+ public boolean hasValue () {
197+ return delegate .hasValue ();
198+ }
199+
200+ @ Override
201+ public void ifExists (Consumer <Config > action ) {
202+ if (delegate .exists ()) {
203+ action .accept (this );
204+ }
205+ }
206+
207+ @ Override
208+ public Stream <Config > traverse () {
209+ return delegate .asList (io .helidon .common .config .Config .class )
210+ .stream ()
211+ .flatMap (List ::stream )
212+ .map (it -> new CommonConfigWrapper (emptyConfig , timestamp , it ));
213+ }
214+
215+ @ Override
216+ public Stream <Config > traverse (Predicate <Config > predicate ) {
217+ return traverse ()
218+ .filter (predicate );
219+ }
90220
221+ @ Override
222+ public <T > T convert (Class <T > type , String value ) throws ConfigMappingException {
223+ return emptyConfig .convert (type , value );
224+ }
225+
226+ @ Override
227+ public ConfigMapper mapper () {
228+ return emptyConfig .mapper ();
229+ }
230+
231+ @ SuppressWarnings ("unchecked" )
232+ @ Override
233+ public <T > ConfigValue <T > as (GenericType <T > genericType ) {
234+ if (genericType .isClass ()) {
235+ return (ConfigValue <T >) as (genericType .rawType ());
236+ }
237+ return ConfigValues .create (this , genericType , mapper ());
238+ }
239+
240+ @ Override
241+ public <T > ConfigValue <T > as (Class <T > type ) {
242+ return ConfigValues .create (this , type , mapper ());
243+ }
244+
245+ @ Override
246+ public <T > ConfigValue <T > as (Function <Config , T > mapper ) {
247+ return ConfigValues .create (this , mapper );
248+ }
249+
250+ @ Override
251+ public <T > ConfigValue <List <T >> asList (Class <T > type ) throws ConfigMappingException {
252+ return ConfigValues .createList (this , cfg -> cfg .as (type ), cfg -> cfg .asList (type ));
253+ }
254+
255+ @ Override
256+ public <T > ConfigValue <List <T >> asList (Function <Config , T > mapper ) throws ConfigMappingException {
257+ return ConfigValues .createList (this , cfg -> cfg .as (mapper ), cfg -> cfg .asList (mapper ));
258+ }
259+
260+ @ Override
261+ public ConfigValue <List <Config >> asNodeList () throws ConfigMappingException {
262+ return asList (Config .class );
263+ }
264+
265+ @ Override
266+ public ConfigValue <Map <String , String >> asMap () throws MissingValueException {
267+ return ConfigValues .createMap (this , mapper ());
268+ }
269+
270+ @ Override
271+ public io .helidon .common .config .Config get (io .helidon .common .config .Config .Key key ) {
272+ return delegate .get (key );
273+ }
274+
275+ @ Override
276+ public boolean equals (Object obj ) {
277+ return delegate .equals (obj );
278+ }
279+
280+ @ Override
281+ public int hashCode () {
282+ return delegate .hashCode ();
283+ }
284+ }
285+
286+ private static class CommonKeyWrapper implements Config .Key {
287+ private final io .helidon .common .config .Config .Key delegate ;
288+
289+ private CommonKeyWrapper (io .helidon .common .config .Config .Key key ) {
290+ this .delegate = key ;
291+ }
292+
293+ @ Override
294+ public Config .Key parent () {
295+ return new CommonKeyWrapper (delegate .parent ());
296+ }
297+
298+ @ Override
299+ public Config .Key child (io .helidon .common .config .Config .Key key ) {
300+ return new CommonKeyWrapper (delegate .child (key ));
301+ }
302+
303+ @ Override
304+ public boolean isRoot () {
305+ return delegate .isRoot ();
306+ }
307+
308+ @ Override
309+ public String name () {
310+ return delegate .name ();
311+ }
312+
313+ @ Override
314+ public boolean equals (Object obj ) {
315+ return delegate .equals (obj );
316+ }
317+
318+ @ Override
319+ public int hashCode () {
320+ return delegate .hashCode ();
321+ }
322+
323+ @ Override
324+ public int compareTo (io .helidon .common .config .Config .Key o ) {
325+ return delegate .compareTo (o );
326+ }
91327 }
92328}
0 commit comments