0
# Options and Customization
1
2
Options and customization provide comprehensive control over parsing, resolution, and rendering behavior. The library offers extensive configuration through option classes and extension interfaces for custom includers, resolvers, and loading strategies.
3
4
## Parse Options
5
6
### ConfigParseOptions Class
7
8
Control configuration parsing behavior with comprehensive options.
9
10
```java { .api }
11
public final class ConfigParseOptions {
12
public static ConfigParseOptions defaults();
13
public ConfigParseOptions setSyntax(ConfigSyntax syntax);
14
public ConfigParseOptions setOriginDescription(String originDescription);
15
public ConfigParseOptions setAllowMissing(boolean allowMissing);
16
public ConfigParseOptions setClassLoader(ClassLoader loader);
17
public ConfigParseOptions setIncluder(ConfigIncluder includer);
18
public ConfigSyntax getSyntax();
19
public String getOriginDescription();
20
public boolean getAllowMissing();
21
public ClassLoader getClassLoader();
22
public ConfigIncluder getIncluder();
23
}
24
```
25
26
**Usage Examples:**
27
28
```java
29
// Parse with specific syntax
30
ConfigParseOptions jsonOptions = ConfigParseOptions.defaults()
31
.setSyntax(ConfigSyntax.JSON);
32
Config config = ConfigFactory.parseString(jsonString, jsonOptions);
33
34
// Allow missing files
35
ConfigParseOptions lenientOptions = ConfigParseOptions.defaults()
36
.setAllowMissing(true);
37
Config config = ConfigFactory.parseFile(optionalFile, lenientOptions);
38
39
// Custom origin description for debugging
40
ConfigParseOptions describedOptions = ConfigParseOptions.defaults()
41
.setOriginDescription("generated config from service discovery");
42
Config config = ConfigFactory.parseString(dynamicConfig, describedOptions);
43
44
// Custom classloader for resource loading
45
ConfigParseOptions loaderOptions = ConfigParseOptions.defaults()
46
.setClassLoader(pluginClassLoader);
47
Config config = ConfigFactory.parseResources("plugin.conf", loaderOptions);
48
```
49
50
### Syntax Options
51
52
Control file format interpretation with ConfigSyntax enum.
53
54
```java { .api }
55
public enum ConfigSyntax {
56
JSON, // Strict JSON format
57
CONF, // HOCON format (Human-Optimized Config Object Notation)
58
PROPERTIES // Java Properties format
59
}
60
```
61
62
**Usage Examples:**
63
64
```java
65
// Force JSON parsing (strict)
66
Config jsonConfig = ConfigFactory.parseString(jsonString,
67
ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON));
68
69
// Force HOCON parsing (allows comments, includes, etc.)
70
Config hoconConfig = ConfigFactory.parseString(hoconString,
71
ConfigParseOptions.defaults().setSyntax(ConfigSyntax.CONF));
72
73
// Force Properties parsing
74
Config propsConfig = ConfigFactory.parseString(propsString,
75
ConfigParseOptions.defaults().setSyntax(ConfigSyntax.PROPERTIES));
76
77
// Auto-detect syntax (default behavior)
78
Config autoConfig = ConfigFactory.parseString(unknownFormat);
79
```
80
81
## Resolve Options
82
83
### ConfigResolveOptions Class
84
85
Control substitution resolution behavior.
86
87
```java { .api }
88
public final class ConfigResolveOptions {
89
public static ConfigResolveOptions defaults();
90
public static ConfigResolveOptions noSystem();
91
public ConfigResolveOptions setUseSystemEnvironment(boolean value);
92
public ConfigResolveOptions setAllowUnresolved(boolean value);
93
public ConfigResolveOptions appendResolver(ConfigResolver resolver);
94
public List<ConfigResolver> getResolvers();
95
public boolean getUseSystemEnvironment();
96
public boolean getAllowUnresolved();
97
}
98
```
99
100
**Usage Examples:**
101
102
```java
103
// Disable system environment variable resolution
104
ConfigResolveOptions noEnv = ConfigResolveOptions.defaults()
105
.setUseSystemEnvironment(false);
106
Config resolved = config.resolve(noEnv);
107
108
// Allow partial resolution (don't fail on unresolved substitutions)
109
ConfigResolveOptions partial = ConfigResolveOptions.defaults()
110
.setAllowUnresolved(true);
111
Config partiallyResolved = config.resolve(partial);
112
113
// Completely isolated resolution (no system integration)
114
ConfigResolveOptions isolated = ConfigResolveOptions.noSystem();
115
Config resolved = config.resolve(isolated);
116
117
// Add custom resolvers
118
ConfigResolver customResolver = new DatabaseConfigResolver();
119
ConfigResolveOptions withCustom = ConfigResolveOptions.defaults()
120
.appendResolver(customResolver);
121
Config resolved = config.resolve(withCustom);
122
```
123
124
## Render Options
125
126
### ConfigRenderOptions Class
127
128
Control configuration rendering to strings.
129
130
```java { .api }
131
public final class ConfigRenderOptions {
132
public static ConfigRenderOptions defaults();
133
public static ConfigRenderOptions concise();
134
public ConfigRenderOptions setComments(boolean value);
135
public ConfigRenderOptions setOriginComments(boolean value);
136
public ConfigRenderOptions setFormatted(boolean value);
137
public ConfigRenderOptions setJson(boolean value);
138
public ConfigRenderOptions setShowEnvVariableValues(boolean value);
139
public boolean getComments();
140
public boolean getOriginComments();
141
public boolean getFormatted();
142
public boolean getJson();
143
public boolean getShowEnvVariableValues();
144
}
145
```
146
147
**Usage Examples:**
148
149
```java
150
Config config = ConfigFactory.load();
151
152
// Default rendering (HOCON with comments and formatting)
153
String defaultRender = config.root().render();
154
155
// Compact JSON (no comments, minimal whitespace)
156
String json = config.root().render(ConfigRenderOptions.concise().setJson(true));
157
158
// Pretty-printed HOCON without comments
159
String clean = config.root().render(
160
ConfigRenderOptions.defaults()
161
.setComments(false)
162
.setFormatted(true)
163
);
164
165
// Include file/line origin information in comments
166
String withOrigins = config.root().render(
167
ConfigRenderOptions.defaults()
168
.setOriginComments(true)
169
);
170
171
// Hide environment variable values for security
172
String secure = config.root().render(
173
ConfigRenderOptions.defaults()
174
.setShowEnvVariableValues(false)
175
);
176
```
177
178
## Custom Includers
179
180
### ConfigIncluder Interface
181
182
Customize how `include` statements are processed in configuration files.
183
184
```java { .api }
185
public interface ConfigIncluder {
186
ConfigIncluder withFallback(ConfigIncluder fallback);
187
ConfigObject include(ConfigIncludeContext context, String what);
188
}
189
```
190
191
**Specialized Includer Interfaces:**
192
193
```java { .api }
194
public interface ConfigIncluderFile extends ConfigIncluder {
195
ConfigObject includeFile(ConfigIncludeContext context, File what);
196
}
197
198
public interface ConfigIncluderURL extends ConfigIncluder {
199
ConfigObject includeURL(ConfigIncludeContext context, URL what);
200
}
201
202
public interface ConfigIncluderClasspath extends ConfigIncluder {
203
ConfigObject includeResources(ConfigIncludeContext context, String what);
204
}
205
```
206
207
**Implementation Examples:**
208
209
```java
210
// Custom includer that loads from a database
211
public class DatabaseIncluder implements ConfigIncluder {
212
private final ConfigService configService;
213
214
public DatabaseIncluder(ConfigService service) {
215
this.configService = service;
216
}
217
218
@Override
219
public ConfigObject include(ConfigIncludeContext context, String what) {
220
try {
221
String configData = configService.getConfiguration(what);
222
if (configData != null) {
223
return ConfigFactory.parseString(configData,
224
context.parseOptions().setOriginDescription("database:" + what))
225
.root();
226
}
227
} catch (Exception e) {
228
throw new ConfigException.IO(context.parseOptions().getOriginDescription(),
229
"Failed to load from database: " + what, e);
230
}
231
return null; // Not found
232
}
233
234
@Override
235
public ConfigIncluder withFallback(ConfigIncluder fallback) {
236
return new FallbackConfigIncluder(this, fallback);
237
}
238
}
239
240
// Usage
241
ConfigIncluder dbIncluder = new DatabaseIncluder(myConfigService);
242
ConfigParseOptions options = ConfigParseOptions.defaults()
243
.setIncluder(dbIncluder);
244
245
Config config = ConfigFactory.parseString(configWithIncludes, options);
246
```
247
248
### ConfigIncludeContext Interface
249
250
Context information available during include processing.
251
252
```java { .api }
253
public interface ConfigIncludeContext {
254
ConfigIncludeContext relativeTo(String filename);
255
ConfigParseOptions parseOptions();
256
}
257
```
258
259
**Usage in Custom Includers:**
260
261
```java
262
@Override
263
public ConfigObject include(ConfigIncludeContext context, String what) {
264
// Get parse options from context
265
ConfigParseOptions options = context.parseOptions();
266
ClassLoader loader = options.getClassLoader();
267
268
// Create relative context for nested includes
269
ConfigIncludeContext relativeContext = context.relativeTo(what);
270
271
// Use context information for resolution
272
String resolvedPath = resolveRelativePath(what, context);
273
274
return loadFromPath(resolvedPath, relativeContext);
275
}
276
```
277
278
## Custom Resolvers
279
280
### ConfigResolver Interface
281
282
Provide custom substitution value sources.
283
284
```java { .api }
285
public interface ConfigResolver {
286
ConfigValue lookup(String path);
287
ConfigResolver withFallback(ConfigResolver fallback);
288
}
289
```
290
291
**Implementation Examples:**
292
293
```java
294
// Resolver that fetches values from external service
295
public class ServiceConfigResolver implements ConfigResolver {
296
private final ConfigurationService service;
297
private final Map<String, ConfigValue> cache = new ConcurrentHashMap<>();
298
299
public ServiceConfigResolver(ConfigurationService service) {
300
this.service = service;
301
}
302
303
@Override
304
public ConfigValue lookup(String path) {
305
return cache.computeIfAbsent(path, this::fetchFromService);
306
}
307
308
private ConfigValue fetchFromService(String path) {
309
try {
310
String value = service.getValue(path);
311
if (value != null) {
312
return ConfigValueFactory.fromAnyRef(value, "service:" + path);
313
}
314
} catch (Exception e) {
315
// Log but don't fail - allow fallback resolvers
316
logger.warn("Failed to resolve {} from service", path, e);
317
}
318
return null;
319
}
320
321
@Override
322
public ConfigResolver withFallback(ConfigResolver fallback) {
323
return new ChainedConfigResolver(this, fallback);
324
}
325
}
326
327
// Resolver for encrypted values
328
public class EncryptedConfigResolver implements ConfigResolver {
329
private final Cipher cipher;
330
331
@Override
332
public ConfigValue lookup(String path) {
333
// Only handle paths that start with "encrypted."
334
if (!path.startsWith("encrypted.")) {
335
return null;
336
}
337
338
try {
339
String encryptedValue = getEncryptedValue(path);
340
String decryptedValue = decrypt(encryptedValue);
341
return ConfigValueFactory.fromAnyRef(decryptedValue, "decrypted:" + path);
342
} catch (Exception e) {
343
throw new ConfigException.BadValue(path, "Failed to decrypt value", e);
344
}
345
}
346
}
347
```
348
349
## Custom Loading Strategy
350
351
### ConfigLoadingStrategy Interface
352
353
Override the default application configuration loading process.
354
355
```java { .api }
356
public interface ConfigLoadingStrategy {
357
Config parseApplicationConfig(ConfigParseOptions parseOptions);
358
}
359
```
360
361
**Implementation and Usage:**
362
363
```java
364
// Custom loading strategy that loads from multiple sources
365
public class MultiSourceLoadingStrategy implements ConfigLoadingStrategy {
366
@Override
367
public Config parseApplicationConfig(ConfigParseOptions parseOptions) {
368
Config base = ConfigFactory.parseResources("base.conf", parseOptions);
369
Config environment = loadEnvironmentConfig(parseOptions);
370
Config secrets = loadSecrets(parseOptions);
371
372
return secrets
373
.withFallback(environment)
374
.withFallback(base);
375
}
376
377
private Config loadEnvironmentConfig(ConfigParseOptions options) {
378
String env = System.getProperty("app.environment", "development");
379
return ConfigFactory.parseResources("environments/" + env + ".conf", options);
380
}
381
382
private Config loadSecrets(ConfigParseOptions options) {
383
// Load from secure storage
384
return secretsService.loadConfig(options);
385
}
386
}
387
388
// Register strategy via system property
389
System.setProperty("config.strategy",
390
"com.mycompany.config.MultiSourceLoadingStrategy");
391
392
// Strategy will be used automatically by ConfigFactory.load()
393
Config config = ConfigFactory.load();
394
```
395
396
## Extension Patterns
397
398
### Chaining Pattern
399
400
Many extension interfaces support chaining with fallback behavior.
401
402
```java
403
// Chain includers
404
ConfigIncluder primary = new DatabaseIncluder(dbService);
405
ConfigIncluder secondary = new S3Includer(s3Service);
406
ConfigIncluder fallback = ConfigIncluderFactory.newDefault();
407
408
ConfigIncluder chain = primary
409
.withFallback(secondary)
410
.withFallback(fallback);
411
412
// Chain resolvers
413
ConfigResolver encrypted = new EncryptedConfigResolver();
414
ConfigResolver service = new ServiceConfigResolver(configService);
415
ConfigResolver system = new SystemConfigResolver();
416
417
ConfigResolver resolverChain = encrypted
418
.withFallback(service)
419
.withFallback(system);
420
```
421
422
### Composite Pattern
423
424
Combine multiple extension instances into a single component.
425
426
```java
427
// Composite includer that delegates based on scheme
428
public class SchemeBasedIncluder implements ConfigIncluder {
429
private final Map<String, ConfigIncluder> includers = new HashMap<>();
430
431
public SchemeBasedIncluder() {
432
includers.put("http", new HttpIncluder());
433
includers.put("https", new HttpsIncluder());
434
includers.put("file", new FileIncluder());
435
includers.put("classpath", new ClasspathIncluder());
436
includers.put("database", new DatabaseIncluder());
437
}
438
439
@Override
440
public ConfigObject include(ConfigIncludeContext context, String what) {
441
URI uri = URI.create(what);
442
String scheme = uri.getScheme();
443
444
ConfigIncluder includer = includers.get(scheme);
445
if (includer != null) {
446
return includer.include(context, what);
447
}
448
449
throw new ConfigException.BadPath(what, "Unsupported include scheme: " + scheme);
450
}
451
}
452
```
453
454
## Option Validation
455
456
### Validation Patterns
457
458
Validate configuration after loading and resolution.
459
460
```java { .api }
461
public void checkValid(Config reference, String... restrictToPaths);
462
```
463
464
**Usage Examples:**
465
466
```java
467
// Load reference configuration (schema)
468
Config reference = ConfigFactory.parseResources("reference.conf");
469
470
// Load actual configuration
471
Config config = ConfigFactory.load().resolve();
472
473
// Validate against reference
474
try {
475
config.checkValid(reference);
476
// Configuration is valid
477
} catch (ConfigException.ValidationFailed e) {
478
// Handle validation errors
479
List<ConfigException.ValidationProblem> problems = e.problems();
480
for (ConfigException.ValidationProblem problem : problems) {
481
String path = problem.path();
482
String description = problem.problem();
483
System.err.println("Validation error at " + path + ": " + description);
484
}
485
}
486
487
// Validate only specific paths
488
config.checkValid(reference, "database", "server", "logging");
489
```
490
491
## Best Practices
492
493
1. **Use defaults as starting point**: Always start with `*.defaults()` and modify from there
494
2. **Chain extensions properly**: Use `withFallback()` to create robust fallback chains
495
3. **Handle errors gracefully**: Extension code should handle errors without failing the entire configuration loading process
496
4. **Cache expensive operations**: Cache results in custom resolvers and includers
497
5. **Provide meaningful origins**: Always include descriptive origin information for debugging
498
6. **Validate configurations**: Use `checkValid()` to catch configuration errors early
499
7. **Test extension code**: Thoroughly test custom includers and resolvers with various input scenarios
500
8. **Document custom behavior**: Clearly document any custom loading strategies or extensions for your team