mirror of
https://github.com/lightbend/config.git
synced 2025-03-23 07:40:25 +08:00
Add ConfigFactory.load variants that let you supply a ClassLoader
This commit is contained in:
parent
9733578ebb
commit
30bdac884b
@ -40,6 +40,12 @@ public final class ConfigFactory {
|
||||
* {@link Class#getResource}).
|
||||
*
|
||||
* <p>
|
||||
* Resources are loaded from the current thread's
|
||||
* {@link Thread#getContextClassLoader()}. In general, a library needs its
|
||||
* configuration to come from the class loader used to load that library, so
|
||||
* the proper "reference.conf" are present.
|
||||
*
|
||||
* <p>
|
||||
* The loaded object will already be resolved (substitutions have already
|
||||
* been processed). As a result, if you add more fallbacks then they won't
|
||||
* be seen by substitutions. Substitutions are the "${foo.bar}" syntax. If
|
||||
@ -48,16 +54,29 @@ public final class ConfigFactory {
|
||||
*
|
||||
* @param resourceBasename
|
||||
* name (optionally without extension) of a resource on classpath
|
||||
* @return configuration for an application
|
||||
* @return configuration for an application relative to context class loader
|
||||
*/
|
||||
public static Config load(String resourceBasename) {
|
||||
return load(resourceBasename, ConfigParseOptions.defaults(),
|
||||
return load(Thread.currentThread().getContextClassLoader(), resourceBasename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #load(String)} but uses the supplied class loader instead of
|
||||
* the current thread's context class loader.
|
||||
*
|
||||
* @param loader
|
||||
* @param resourceBasename
|
||||
* @return configuration for an application relative to given class loader
|
||||
*/
|
||||
public static Config load(ClassLoader loader, String resourceBasename) {
|
||||
return load(loader, resourceBasename, ConfigParseOptions.defaults(),
|
||||
ConfigResolveOptions.defaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #load(String)} but allows you to specify parse and resolve
|
||||
* options.
|
||||
*
|
||||
* @param resourceBasename
|
||||
* the classpath resource name with optional extension
|
||||
* @param parseOptions
|
||||
@ -68,9 +87,29 @@ public final class ConfigFactory {
|
||||
*/
|
||||
public static Config load(String resourceBasename, ConfigParseOptions parseOptions,
|
||||
ConfigResolveOptions resolveOptions) {
|
||||
Config appConfig = ConfigFactory.parseResourcesAnySyntax(ConfigFactory.class, "/"
|
||||
+ resourceBasename, parseOptions);
|
||||
return load(appConfig, resolveOptions);
|
||||
return load(Thread.currentThread().getContextClassLoader(), resourceBasename, parseOptions,
|
||||
resolveOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #load(String,ConfigParseOptions,ConfigResolveOptions)} but
|
||||
* allows you to specify a class loader
|
||||
*
|
||||
* @param loader
|
||||
* class loader in which to find resources
|
||||
* @param resourceBasename
|
||||
* the classpath resource name with optional extension
|
||||
* @param parseOptions
|
||||
* options to use when parsing the resource
|
||||
* @param resolveOptions
|
||||
* options to use when resolving the stack
|
||||
* @return configuration for an application
|
||||
*/
|
||||
public static Config load(ClassLoader loader, String resourceBasename,
|
||||
ConfigParseOptions parseOptions, ConfigResolveOptions resolveOptions) {
|
||||
Config appConfig = ConfigFactory.parseResourcesAnySyntax(loader, resourceBasename,
|
||||
parseOptions);
|
||||
return load(loader, appConfig, resolveOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,7 +123,11 @@ public final class ConfigFactory {
|
||||
* @return resolved configuration with overrides and fallbacks added
|
||||
*/
|
||||
public static Config load(Config config) {
|
||||
return load(config, ConfigResolveOptions.defaults());
|
||||
return load(Thread.currentThread().getContextClassLoader(), config);
|
||||
}
|
||||
|
||||
public static Config load(ClassLoader loader, Config config) {
|
||||
return load(loader, config, ConfigResolveOptions.defaults());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,11 +141,28 @@ public final class ConfigFactory {
|
||||
* @return resolved configuration with overrides and fallbacks added
|
||||
*/
|
||||
public static Config load(Config config, ConfigResolveOptions resolveOptions) {
|
||||
return defaultOverrides().withFallback(config).withFallback(defaultReference())
|
||||
return load(Thread.currentThread().getContextClassLoader(), config, resolveOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #load(Config,ConfigResolveOptions)} but allows you to specify
|
||||
* a class loader other than the context class loader.
|
||||
*
|
||||
* @param loader
|
||||
* class loader to use when looking up override and reference
|
||||
* configs
|
||||
* @param config
|
||||
* the application's portion of the configuration
|
||||
* @param resolveOptions
|
||||
* options for resolving the assembled config stack
|
||||
* @return resolved configuration with overrides and fallbacks added
|
||||
*/
|
||||
public static Config load(ClassLoader loader, Config config, ConfigResolveOptions resolveOptions) {
|
||||
return defaultOverrides(loader).withFallback(config).withFallback(defaultReference(loader))
|
||||
.resolve(resolveOptions);
|
||||
}
|
||||
|
||||
private static Config loadDefaultConfig() {
|
||||
private static Config loadDefaultConfig(ClassLoader loader) {
|
||||
int specified = 0;
|
||||
|
||||
// override application.conf with config.file, config.resource,
|
||||
@ -118,7 +178,7 @@ public final class ConfigFactory {
|
||||
specified += 1;
|
||||
|
||||
if (specified == 0) {
|
||||
return load("application");
|
||||
return load(loader, "application");
|
||||
} else if (specified > 1) {
|
||||
throw new ConfigException.Generic("You set more than one of config.file='" + file
|
||||
+ "', config.url='" + url + "', config.resource='" + resource
|
||||
@ -127,12 +187,12 @@ public final class ConfigFactory {
|
||||
if (resource != null) {
|
||||
// this deliberately does not parseResourcesAnySyntax; if
|
||||
// people want that they can use an include statement.
|
||||
return load(parseResources(ConfigFactory.class, resource));
|
||||
return load(loader, parseResources(loader, resource));
|
||||
} else if (file != null) {
|
||||
return load(parseFile(new File(file)));
|
||||
return load(loader, parseFile(new File(file)));
|
||||
} else {
|
||||
try {
|
||||
return load(parseURL(new URL(url)));
|
||||
return load(loader, parseURL(new URL(url)));
|
||||
} catch (MalformedURLException e) {
|
||||
throw new ConfigException.Generic("Bad URL in config.url system property: '"
|
||||
+ url + "': " + e.getMessage(), e);
|
||||
@ -169,7 +229,19 @@ public final class ConfigFactory {
|
||||
* @return configuration for an application
|
||||
*/
|
||||
public static Config load() {
|
||||
return loadDefaultConfig();
|
||||
return load(Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #load()} but allows specifying a class loader other than the
|
||||
* thread's current context class loader.
|
||||
*
|
||||
* @param loader
|
||||
* class loader for finding resources
|
||||
* @return configuration for an application
|
||||
*/
|
||||
public static Config load(ClassLoader loader) {
|
||||
return loadDefaultConfig(loader);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,6 +255,13 @@ public final class ConfigFactory {
|
||||
* jar.
|
||||
*
|
||||
* <p>
|
||||
* The reference config must be looked up in the class loader that contains
|
||||
* the libraries that you want to use with this config, so the
|
||||
* "reference.conf" for each library can be found. Use
|
||||
* {@link #defaultReference(ClassLoader)} if the context class loader is not
|
||||
* suitable.
|
||||
*
|
||||
* <p>
|
||||
* The {@link #load()} methods merge this configuration for you
|
||||
* automatically.
|
||||
*
|
||||
@ -191,10 +270,21 @@ public final class ConfigFactory {
|
||||
* is not guaranteed that this method <em>only</em> looks at
|
||||
* "reference.conf".
|
||||
*
|
||||
* @return the default reference config
|
||||
* @return the default reference config for context class loader
|
||||
*/
|
||||
public static Config defaultReference() {
|
||||
return ConfigImpl.defaultReference();
|
||||
return defaultReference(Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #defaultReference()} but allows you to specify a class loader
|
||||
* to use rather than the current context class loader.
|
||||
*
|
||||
* @param loader
|
||||
* @return the default reference config for this class loader
|
||||
*/
|
||||
public static Config defaultReference(ClassLoader loader) {
|
||||
return ConfigImpl.defaultReference(loader);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,6 +306,17 @@ public final class ConfigFactory {
|
||||
return systemProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #defaultOverrides()} but allows you to specify a class loader
|
||||
* to use rather than the current context class loader.
|
||||
*
|
||||
* @param loader
|
||||
* @return the default override configuration
|
||||
*/
|
||||
public static Config defaultOverrides(ClassLoader loader) {
|
||||
return systemProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an empty configuration. See also {@link #empty(String)} to create an
|
||||
* empty configuration with a description, which may improve user-visible
|
||||
@ -454,6 +555,106 @@ public final class ConfigFactory {
|
||||
return parseResourcesAnySyntax(klass, resourceBasename, ConfigParseOptions.defaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses all resources on the classpath with the given name and merges them
|
||||
* into a single <code>Config</code>.
|
||||
*
|
||||
* <p>
|
||||
* This works like {@link java.lang.ClassLoader#getResource}, not like
|
||||
* {@link java.lang.Class#getResource}, so the name never begins with a
|
||||
* slash.
|
||||
*
|
||||
* <p>
|
||||
* See {@link #parseResources(Class,String,ConfigParseOptions)} for full
|
||||
* details.
|
||||
*
|
||||
* @param loader
|
||||
* will be used to load resources
|
||||
* @param resource
|
||||
* resource to look up
|
||||
* @param options
|
||||
* parse options
|
||||
* @return the parsed configuration
|
||||
*/
|
||||
public static Config parseResources(ClassLoader loader, String resource,
|
||||
ConfigParseOptions options) {
|
||||
return Parseable.newResources(loader, resource, options).parse().toConfig();
|
||||
}
|
||||
|
||||
public static Config parseResources(ClassLoader loader, String resource) {
|
||||
return parseResources(loader, resource, ConfigParseOptions.defaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses classpath resources with a flexible extension. In general, this
|
||||
* method has the same behavior as
|
||||
* {@link #parseFileAnySyntax(File,ConfigParseOptions)} but for classpath
|
||||
* resources instead, as in
|
||||
* {@link #parseResources(ClassLoader,String,ConfigParseOptions)}.
|
||||
*
|
||||
* <p>
|
||||
* {@link #parseResourcesAnySyntax(Class,String,ConfigParseOptions)} differs
|
||||
* in the syntax for the resource name, but otherwise see
|
||||
* {@link #parseResourcesAnySyntax(Class,String,ConfigParseOptions)} for
|
||||
* some details and caveats on this method.
|
||||
*
|
||||
* @param loader
|
||||
* class loader to look up resources in
|
||||
* @param resourceBasename
|
||||
* a resource name as in
|
||||
* {@link java.lang.ClassLoader#getResource}, with or without
|
||||
* extension
|
||||
* @param options
|
||||
* parse options
|
||||
* @return the parsed configuration
|
||||
*/
|
||||
public static Config parseResourcesAnySyntax(ClassLoader loader, String resourceBasename,
|
||||
ConfigParseOptions options) {
|
||||
return ConfigImpl.parseResourcesAnySyntax(loader, resourceBasename, options).toConfig();
|
||||
}
|
||||
|
||||
public static Config parseResourcesAnySyntax(ClassLoader loader, String resourceBasename) {
|
||||
return parseResourcesAnySyntax(loader, resourceBasename, ConfigParseOptions.defaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #parseResources(ClassLoader,String,ConfigParseOptions)} but
|
||||
* uses thread's current context class loader.
|
||||
*/
|
||||
public static Config parseResources(String resource, ConfigParseOptions options) {
|
||||
return Parseable
|
||||
.newResources(Thread.currentThread().getContextClassLoader(), resource, options)
|
||||
.parse().toConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #parseResources(ClassLoader,String)} but uses thread's
|
||||
* current context class loader.
|
||||
*/
|
||||
public static Config parseResources(String resource) {
|
||||
return parseResources(Thread.currentThread().getContextClassLoader(), resource,
|
||||
ConfigParseOptions.defaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Like
|
||||
* {@link #parseResourcesAnySyntax(ClassLoader,String,ConfigParseOptions)}
|
||||
* but uses thread's current context class loader.
|
||||
*/
|
||||
public static Config parseResourcesAnySyntax(String resourceBasename, ConfigParseOptions options) {
|
||||
return ConfigImpl.parseResourcesAnySyntax(Thread.currentThread().getContextClassLoader(),
|
||||
resourceBasename, options).toConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #parseResourcesAnySyntax(ClassLoader,String)} but uses
|
||||
* thread's current context class loader.
|
||||
*/
|
||||
public static Config parseResourcesAnySyntax(String resourceBasename) {
|
||||
return parseResourcesAnySyntax(Thread.currentThread().getContextClassLoader(),
|
||||
resourceBasename, ConfigParseOptions.defaults());
|
||||
}
|
||||
|
||||
public static Config parseString(String s, ConfigParseOptions options) {
|
||||
return Parseable.newString(s, options).parse().toConfig();
|
||||
}
|
||||
|
@ -118,6 +118,18 @@ public class ConfigImpl {
|
||||
return fromBasename(source, resourceBasename, baseOptions);
|
||||
}
|
||||
|
||||
/** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */
|
||||
public static ConfigObject parseResourcesAnySyntax(final ClassLoader loader,
|
||||
String resourceBasename, final ConfigParseOptions baseOptions) {
|
||||
NameSource source = new NameSource() {
|
||||
@Override
|
||||
public ConfigParseable nameToParseable(String name) {
|
||||
return Parseable.newResources(loader, name, baseOptions);
|
||||
}
|
||||
};
|
||||
return fromBasename(source, resourceBasename, baseOptions);
|
||||
}
|
||||
|
||||
/** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */
|
||||
public static ConfigObject parseFileAnySyntax(final File basename,
|
||||
final ConfigParseOptions baseOptions) {
|
||||
@ -398,10 +410,10 @@ public class ConfigImpl {
|
||||
}
|
||||
|
||||
/** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */
|
||||
public static Config defaultReference() {
|
||||
public static Config defaultReference(ClassLoader loader) {
|
||||
Config unresolvedResources = Parseable
|
||||
.newResources(Thread.currentThread().getContextClassLoader(), "reference.conf",
|
||||
ConfigParseOptions.defaults()).parse().toConfig();
|
||||
.newResources(loader, "reference.conf", ConfigParseOptions.defaults()).parse()
|
||||
.toConfig();
|
||||
return systemPropertiesAsConfig().withFallback(unresolvedResources).resolve();
|
||||
}
|
||||
|
||||
|
@ -488,4 +488,57 @@ class PublicApiTest extends TestUtils {
|
||||
assertFalse("no a", configPlain.hasPath("a"))
|
||||
assertFalse("no b", configPlain.hasPath("b"))
|
||||
}
|
||||
|
||||
@Test
|
||||
def usesSuppliedClassLoader() {
|
||||
val loaderA1 = new TestClassLoader(this.getClass().getClassLoader(),
|
||||
Map("reference.conf" -> resourceFile("a_1.conf").toURI.toURL()))
|
||||
val loaderB2 = new TestClassLoader(this.getClass().getClassLoader(),
|
||||
Map("reference.conf" -> resourceFile("b_2.conf").toURI.toURL()))
|
||||
|
||||
val configA1 = ConfigFactory.load(loaderA1)
|
||||
|
||||
assertEquals(1, configA1.getInt("a"))
|
||||
assertFalse("no b", configA1.hasPath("b"))
|
||||
|
||||
val configB2 = ConfigFactory.load(loaderB2)
|
||||
|
||||
assertEquals(2, configB2.getInt("b"))
|
||||
assertFalse("no a", configB2.hasPath("a"))
|
||||
|
||||
val configPlain = ConfigFactory.load()
|
||||
assertFalse("no a", configPlain.hasPath("a"))
|
||||
assertFalse("no b", configPlain.hasPath("b"))
|
||||
|
||||
// check the various overloads that take a loader parameter
|
||||
for (
|
||||
c <- Seq(ConfigFactory.parseResources(loaderA1, "reference.conf"),
|
||||
ConfigFactory.parseResourcesAnySyntax(loaderA1, "reference"),
|
||||
ConfigFactory.parseResources(loaderA1, "reference.conf", ConfigParseOptions.defaults()),
|
||||
ConfigFactory.parseResourcesAnySyntax(loaderA1, "reference", ConfigParseOptions.defaults()),
|
||||
ConfigFactory.load(loaderA1, "application"),
|
||||
ConfigFactory.load(loaderA1, "application", ConfigParseOptions.defaults(), ConfigResolveOptions.defaults()),
|
||||
ConfigFactory.load(loaderA1, ConfigFactory.parseString("")),
|
||||
ConfigFactory.load(loaderA1, ConfigFactory.parseString(""), ConfigResolveOptions.defaults()),
|
||||
ConfigFactory.defaultReference(loaderA1))
|
||||
) {
|
||||
assertEquals(1, c.getInt("a"))
|
||||
assertFalse("no b", c.hasPath("b"))
|
||||
}
|
||||
|
||||
for (
|
||||
c <- Seq(ConfigFactory.parseResources("reference.conf"),
|
||||
ConfigFactory.parseResourcesAnySyntax("reference"),
|
||||
ConfigFactory.parseResources("reference.conf", ConfigParseOptions.defaults()),
|
||||
ConfigFactory.parseResourcesAnySyntax("reference", ConfigParseOptions.defaults()),
|
||||
ConfigFactory.load("application"),
|
||||
ConfigFactory.load("application", ConfigParseOptions.defaults(), ConfigResolveOptions.defaults()),
|
||||
ConfigFactory.load(ConfigFactory.parseString("")),
|
||||
ConfigFactory.load(ConfigFactory.parseString(""), ConfigResolveOptions.defaults()),
|
||||
ConfigFactory.defaultReference())
|
||||
) {
|
||||
assertFalse("no a", c.hasPath("a"))
|
||||
assertFalse("no b", c.hasPath("b"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user