Skip to content

Commit 18141c6

Browse files
authored
feat: Add Configuration.Builder load() method to load a file or resource (#131)
This then allows programmatic creation of Configuration which include the loading of files or resources like: var fileSource = new File("./src/test/resources/yaml/minimal.yaml"); var configuration = Configuration.builder() .put("myExtraOne", "baz") .load(fileSource) // load from a file .load("hi.properties") // load from a resource .build(); With the file extension of .properties or .yaml/.yml used to determine which parser to use to parse and load the content for the file or resource.
1 parent 6679d66 commit 18141c6

File tree

7 files changed

+89
-14
lines changed

7 files changed

+89
-14
lines changed

avaje-config/src/main/java/io/avaje/config/Configuration.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.avaje.lang.NonNullApi;
44
import io.avaje.lang.Nullable;
55

6+
import java.io.File;
67
import java.math.BigDecimal;
78
import java.net.URI;
89
import java.time.Duration;
@@ -734,6 +735,24 @@ interface Builder {
734735
*/
735736
Builder putAll(Properties source);
736737

738+
/**
739+
* Load the resource using the extension to determine the parser to use.
740+
* <p>
741+
* By default, resources with {@code .properties} and {@code .yaml} extensions are supported.
742+
*
743+
* @param resource The resource with configuration content
744+
*/
745+
Builder load(String resource);
746+
747+
/**
748+
* Load the file using the file extension to determine the parser to use.
749+
* <p>
750+
* By default, files with {@code .properties} and {@code .yaml} extensions are supported.
751+
*
752+
* @param file The file with configuration content
753+
*/
754+
Builder load(File file);
755+
737756
/**
738757
* Optionally set the event runner to use . If not specified a foreground runner will be used.
739758
*/

avaje-config/src/main/java/io/avaje/config/CoreConfigurationBuilder.java

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
package io.avaje.config;
22

3-
import java.util.*;
3+
import java.io.File;
4+
import java.io.FileReader;
5+
import java.io.IOException;
6+
import java.io.UncheckedIOException;
7+
import java.util.LinkedHashMap;
8+
import java.util.Map;
9+
import java.util.Properties;
10+
import java.util.ServiceLoader;
411
import java.util.stream.Collectors;
512

613
import static java.util.Objects.requireNonNull;
714

815
final class CoreConfigurationBuilder implements Configuration.Builder {
916

17+
private final Parsers parsers = new Parsers();
1018
private final Map<String, String> sourceMap = new LinkedHashMap<>();
19+
private ResourceLoader resourceLoader = initialiseResourceLoader();
1120
private ModificationEventRunner eventRunner;
1221
private ConfigurationLog configurationLog;
13-
private ResourceLoader resourceLoader;
14-
1522
private boolean includeResourceLoading;
1623
private InitialLoader initialLoader;
1724

@@ -63,6 +70,45 @@ public Configuration.Builder putAll(Properties source) {
6370
return this;
6471
}
6572

73+
@Override
74+
public Configuration.Builder load(String resource) {
75+
final var configParser = parser(resource);
76+
try {
77+
try (var inputStream = resourceLoader.getResourceAsStream(resource)) {
78+
putAll(configParser.load(inputStream));
79+
return this;
80+
}
81+
} catch (IOException e) {
82+
throw new UncheckedIOException(e);
83+
}
84+
}
85+
86+
@Override
87+
public Configuration.Builder load(File file) {
88+
final var configParser = parser(file.getName());
89+
try {
90+
try (var reader = new FileReader(file)) {
91+
putAll(configParser.load(reader));
92+
return this;
93+
}
94+
} catch (IOException e) {
95+
throw new UncheckedIOException(e);
96+
}
97+
}
98+
99+
private ConfigParser parser(String name) {
100+
int pos = name.lastIndexOf('.');
101+
if (pos == -1) {
102+
throw new IllegalArgumentException("Unable to determine the extension for " + name);
103+
}
104+
var extension = name.substring(pos + 1);
105+
ConfigParser configParser = parsers.get(extension);
106+
if (configParser == null) {
107+
throw new IllegalArgumentException("No parser registered for extension " + extension);
108+
}
109+
return configParser;
110+
}
111+
66112
@Override
67113
public Configuration.Builder includeResourceLoading() {
68114
this.includeResourceLoading = true;
@@ -73,7 +119,6 @@ public Configuration.Builder includeResourceLoading() {
73119
public Configuration build() {
74120
final var runner = initRunner();
75121
final var log = initLog();
76-
final var parsers = new Parsers();
77122
final var sources = ServiceLoader.load(ConfigurationSource.class).stream()
78123
.map(ServiceLoader.Provider::get)
79124
.collect(Collectors.toList());
@@ -84,7 +129,7 @@ public Configuration build() {
84129
var components = new CoreComponents(runner, log, parsers, sources, plugins);
85130
if (includeResourceLoading) {
86131
log.preInitialisation();
87-
initialLoader = new InitialLoader(components, initResourceLoader());
132+
initialLoader = new InitialLoader(components, resourceLoader);
88133
}
89134
return new CoreConfiguration(components, initEntries()).postLoad(initialLoader);
90135
}
@@ -99,13 +144,10 @@ private CoreEntry.CoreMap initEntryMap() {
99144
return initialLoader == null ? CoreEntry.newMap() : initialLoader.load();
100145
}
101146

102-
private ResourceLoader initResourceLoader() {
103-
if (resourceLoader == null) {
104-
resourceLoader = ServiceLoader.load(ResourceLoader.class)
105-
.findFirst()
106-
.orElseGet(DefaultResourceLoader::new);
107-
}
108-
return resourceLoader;
147+
private static ResourceLoader initialiseResourceLoader() {
148+
return ServiceLoader.load(ResourceLoader.class)
149+
.findFirst()
150+
.orElseGet(DefaultResourceLoader::new);
109151
}
110152

111153
private ConfigurationLog initLog() {

avaje-config/src/main/java/io/avaje/config/CoreEntry.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ private CoreEntry(String value, String source) {
7070
this.source = source;
7171
}
7272

73+
@Override
74+
public String toString() {
75+
return '{' + value + " source:" + source + '}';
76+
}
77+
7378
boolean needsEvaluation() {
7479
return value != null && value.contains("${");
7580
}

avaje-config/src/main/java/io/avaje/config/Parsers.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@ Set<Map.Entry<String, ConfigParser>> entrySet() {
5353
* Return the ConfigParser for the given extension.
5454
*/
5555
ConfigParser get(String extension) {
56-
return parserMap.get(extension);
56+
return parserMap.get(extension.toLowerCase());
5757
}
5858

5959
/**
6060
* Return true if the extension has a matching parser.
6161
*/
6262
boolean supportsExtension(String extension) {
63-
return parserMap.containsKey(extension);
63+
return parserMap.containsKey(extension.toLowerCase());
6464
}
6565

6666
/**

avaje-config/src/test/java/io/avaje/config/CoreConfigurationTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.example.MyExternalLoader;
55
import org.junit.jupiter.api.Test;
66

7+
import java.io.File;
78
import java.io.StringReader;
89
import java.util.*;
910
import java.util.concurrent.atomic.AtomicBoolean;
@@ -147,17 +148,22 @@ void toEnvKey() {
147148

148149
@Test
149150
void builder() {
151+
var fileSource = new File("./src/test/resources/yaml/minimal.yaml");
150152
var conf = Configuration.builder()
151153
.putAll(properties())
152154
.putAll(Map.of("myExtraMap", "foo", "myExtraMap.b", "bar"))
153155
.put("myExtraOne", "baz")
156+
.load(fileSource)
157+
.load("hi.properties")
154158
.build();
155159

156160
assertEquals(conf.get("a"), "1");
157161
assertEquals(conf.get("doesNotExist", "something"), "something");
158162
assertEquals(conf.get("myExtraMap"), "foo");
159163
assertEquals(conf.get("myExtraMap.b"), "bar");
160164
assertEquals(conf.get("myExtraOne"), "baz");
165+
assertEquals(conf.get("my.name"), "Nom");
166+
assertEquals(conf.get("hi.iAmInProps"), "There it is");
161167

162168
String userHome = System.getProperty("user.home");
163169
assertEquals(conf.get("myHome"), "my/" + userHome + "/home");
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hi.iAmInProps=There it is
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
my:
2+
name: Nom

0 commit comments

Comments
 (0)