1

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

Tomas Bartalos
  • 1,256
  • 12
  • 29

1 Answers1

3

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).

  • 1
    Thank you, it works. One disadvantage is that I need to declare the implicit from the client which calls the loading - adding it to my wrapper class did not work. So I've added the implicit def to Object and I'm importing it from the client code. Intellij marks this import as unused so I can't use optimize imports feature (same as with pureconfig.generic.auto._). – Tomas Bartalos May 31 '19 at 16:30
  • @TomasBartalos For the unused import take a look to [this](https://stackoverflow.com/questions/56351793/scala-implicit-parameters-are-marked-as-unused-by-the-compiler?noredirect=1#comment99336812_56351793). For the first part, I did not understand it well. Can you edit your question with an example, maybe there is a simpler way. I think you said that you are creating another library, which an user will call, can you explain _(in the question)_ how will your client call you, what will he/she provide and what would you need to do. – Luis Miguel Mejía Suárez May 31 '19 at 16:37
  • I've edited the question and put some more explanation to the problem – Tomas Bartalos May 31 '19 at 22:59
  • @TomasBartalos sorry, been trying for a while to solve your issue, but not lucky. You may try asking in the `pureconfig` **gitter** channel. – Luis Miguel Mejía Suárez Jun 03 '19 at 22:40
  • 1
    You've been a great help anyway, thank you. Btw, I've found another way how to force camelCase: `implicit def productHint[T] = ProductHint[T](ConfigFieldMapping(CamelCase, CamelCase))` – Tomas Bartalos Jun 06 '19 at 11:51