scalapureconfig

Can pureconfig use camel case config


I'm using pureconfig pureconfig lib with pureconfig-yaml module. Everything works like a charm, my only problem is that I have to convert the property names from camel case to kebab case.

Painful examples from real world:

case class Config(log4JPath: String, registryURL: String, HOUR_FORMAT: String)

Yaml:
log-4-j-path: /conf/log4j.properties
registry-url: http://foo.com
hour-_-format: dd-mm-yy

I don't want to maintain 2 different case types and think about how to convert from one to the other, I would love to have pure copy&paste scala class -> yaml config solution. Is there a chance I could achieve camel case on both sides ?

Edit:

I've created a wrapper around pureconfig lib, which does some config overriding by environment variables. Client should use the wrapper in following manner:

val conf: Config = ConfigLoader(file).load[Config]

However this is not sufficient and the client needs to provide 2 imports:

// to find implicit reader
import pureconfig.generic.auto._
// to use Camelcase - as suggested from the answer
import ConfigLoader.productHint

It would be great if the wrapper (ConfigLoader) could deal with the imports and they would not be left on client's responsibility. Moreover the imports are identified as "Unused" by IntelliJ IDE and when "optimize imports" is triggered or "Optimize imports on the fly" is enabled the imports are auto-erased. According to this thread (accepted answer is not working for me), we can solve this with "Mark import as always used...", however this is not an ideal solution because other team members will have to do the same for every project or we should commit .idea to VCS (which I'd like to avoid).

I'm attaching screenshot of my test (dependency pureconfig.generic.auto._ have already been marked as allways used): enter image description here


Solution

  • Yes you can. Take a look to the documentation - field-mappings.

    import pureconfig._
    import pureconfig.generic.auto._
    import pureconfig.generic.ProductHint
    
    // Case classes should be final ;)
    final case class Config(log4JPath: String, registryURL: String, HOUR_FORMAT: String)
    
    val yaml =
      """log4JPath: /conf/log4j.properties
        |registryURL: http://foo.com
        |HOUR_FORMAT: dd-mm-yy""".stripMargin
    
    implicit val indentityHint: ProductHint[Conf] =
      ProductHint[Conf](new ConfigFieldMapping {
        def apply(fieldName: String) = fieldName // Basically the identity.
      }) 
    
    loadYaml[Config](yaml)
    // res: ConfigReader.Result[Config] = Right(Config("/conf/log4j.properties", "http://foo.com", "dd-mm-yy"))
    

    (Note, this was tested in ammonite, using pureconfig 0.11.0).