Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resolveOptions are ignored when loading reference.conf files #164

Closed
jletroui opened this issue May 13, 2014 · 4 comments
Closed

resolveOptions are ignored when loading reference.conf files #164

jletroui opened this issue May 13, 2014 · 4 comments

Comments

@jletroui
Copy link

This is preventing to load unresolved properties from libraries.

The problem lies in the following code:

public static Config load(ClassLoader loader, Config config, ConfigResolveOptions resolveOptions) {
    return defaultOverrides(loader).withFallback(config).withFallback(defaultReference(loader))
            .resolve(resolveOptions);
}

resolveOptions is not passed to defaultReference().

Primary use case is to be able to use fallbacks for substitutions by doing something like:

val mainConfig = ConfigFactory
  .load(Thread.currentThread.getContextClassLoader, ConfigResolveOptions.defaults().setAllowUnresolved(true))
  .withFallback(ConfigFactory.parseFile("some system properties file path")
val resolvedConfig = mainConfig.resolveWith(mainConfig)

This is working fine for application.conf files, but not reference.conf ones.

@havocp
Copy link
Collaborator

havocp commented May 13, 2014

In the general case this can't work for reference.conf, because plain ConfigFactory.load() with no arguments will load all reference.conf on the classpath, but won't have your special fallback code. So you would break any other library on the classpath, because those other libraries won't have your special config-loading code that adds the fallback. That's why the defaultReference() method doesn't have an overload with resolve options -- per-class-loader, the default reference config has to be the same thing for all pieces of code which load it. Also, defaultReference() calls resolve() - which would throw an exception even if you had the setAllowUnresolved option set.

In general the reference conf cannot depend on the application or runtime conf because of this. It would be convenient sometimes but it just isn't how it works.

However there may be various solutions, depending on your constraints (do you know that file path in advance? are you using any third-party libs that use typesafe config?)

@jletroui
Copy link
Author

Thanks for the very quick answer. I completely understand the general case, and for public libraries, this is the way to go.

For internal libraries though, one might want to not have to redefine private credentials (for a database or some other systems) on each developer machine. The use case would be to point to the config file where those credentials are located in the library, so wherever it is used, the correct credentials might be loaded.

Here are my constraints:

  • I do know the file path in advance, but it is relative to current user's home (something like ~/.userconfig.properties). I though of using an include, but include syntax to not support substitutions. This is preventing things like include "${user.home}/.userconfig.properties".
  • I am using Akka. I am passing my custom constructed config to the actor system factory method, so this is fine.

@havocp
Copy link
Collaborator

havocp commented May 14, 2014

If you're not worried about interop with other libraries, you could always do your own parseResourcesAnySyntax("reference", options) -- ConfigFactory.load() and ConfigFactory.defaultReference() are purely convenience methods that do a "standard" or "recommended" sequence of parses and resolves. Nothing magic about them. If the default-defined way of doing things in ConfigFactory.load() doesn't match your environment you can always ignore it and define your own way. This is why the examples show that libs should accept a Config and why akka lets you pass a Config in.

Other options:

  • you might put an application.conf instead of or in addition to a reference.conf in the library - conceptually an internal library is maybe part of a specific app anyhow, but whether it's conceptually clean or not, the application.conf does get loaded/resolved with the full app conf including any resolve options. All application.conf on classpath should get loaded.
  • you might arrange somewhere to load .userconfig.properties into system properties prior to using the config lib
  • to get the effect of an include with user.home in it, see this answer: http://stackoverflow.com/a/21057202/277156 which links to Feature request: dynamic includes #122 (comment)

@jletroui
Copy link
Author

Great suggestions! I am just starting to grasps the full power if the library. I ended up using your first suggestion, in order to be able to keep the usual application / reference fallbacks.

Many thanks for your hard work a great support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants