QuentinAmbard / configs

Scala wrapper for Typesafe config

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

configs

Build Status Maven Central Scaladoc

configs is Scala wrapper for Typesafe config.

Usage

Add the following line to your build file:

libraryDependencies += "com.github.kxbmap" %% "configs" % "0.4.3"

configs version 0.4+ only support Java 8. If you need to Java 7, please check 0.3.x.

Quick Start

import com.typesafe.config.ConfigFactory
import configs.Configs

Result type of get a value from config is configs.Result. If get successfully, returns configs.Result.Success, if not configs.Result.Failure:

val config = ConfigFactory.parseString("foo = 42")
scala> val result = Configs[Int].get(config, "foo")
result: configs.Result[Int] = Success(42)

scala> result.valueOrElse(0)
res0: Int = 42

scala> val result = Configs[Int].get(config, "missing")
result: configs.Result[Int] = Failure(ConfigError(Exceptional(com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'missing',List(missing)),Vector()))

scala> result.valueOrElse(0)
res1: Int = 0

Import configs.syntax._ provides extension methods for Config:

import configs.syntax._
scala> config.get[Int]("foo")
res2: configs.Result[Int] = Success(42)

get[Option[A]] will return success with value None if path is not exists:

scala> config.get[Option[Int]]("missing")
res3: configs.Result[Option[Int]] = Success(None)

scala> config.getOrElse("missing", 0) // Alias for config.get[Option[Int]]("missing").map(_.getOrElse(0))
res4: configs.Result[Int] = Success(0)

You can get a case class value out of the box:

import scala.concurrent.duration.FiniteDuration

case class MyConfig(foo: String, bar: Int, baz: List[FiniteDuration])
val config = ConfigFactory.parseString("""
  my-config {
    foo = My config value
    bar = 123456
    baz = [1h, 2m, 3s]
  }
  """)
scala> config.get[MyConfig]("my-config")
res6: configs.Result[MyConfig] = Success(MyConfig(My config value,123456,List(1 hour, 2 minutes, 3 seconds)))

If failed, Result accumulates error messages:

val config = ConfigFactory.parseString("""
  my-config {
    bar = 2147483648
    baz = [aaa, bbb, ccc]
  }
  """)
scala> val result = config.get[MyConfig]("my-config")
result: configs.Result[MyConfig] = Failure(ConfigError(Exceptional(com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'foo',List(my-config, foo)),Vector(Exceptional(com.typesafe.config.ConfigException$WrongType: String: 2: bar has type out-of-range value 2147483648 rather than int (32-bit integer),List(my-config, bar)), Exceptional(com.typesafe.config.ConfigException$BadValue: String: 4: Invalid value at '0': No number in duration value 'aaa',List(my-config, baz, 0)), Exceptional(com.typesafe.config.ConfigException$BadValue: String: 4: Invalid value at '1': No number in duration value 'bbb',List(my-config, baz, 1)), Exceptional(com.typesafe.config.ConfigException$BadValue: String: 4: Invalid value at '2': No number in duration v...

scala> result.valueOr { error =>
     |   error.messages.foreach(println)
     |   MyConfig("", 0, Nil)
     | }
[my-config.foo] No configuration setting found for key 'foo'
[my-config.bar] String: 2: bar has type out-of-range value 2147483648 rather than int (32-bit integer)
[my-config.baz.0] String: 4: Invalid value at '0': No number in duration value 'aaa'
[my-config.baz.1] String: 4: Invalid value at '1': No number in duration value 'bbb'
[my-config.baz.2] String: 4: Invalid value at '2': No number in duration value 'ccc'
res7: MyConfig = MyConfig(,0,List())

You can get a value without key using extract:

val config = ConfigFactory.parseString("""
  foo = My config value
  bar = 123456
  baz = [1h, 2m, 3s]
  """)
scala> config.extract[MyConfig]
res8: configs.Result[MyConfig] = Success(MyConfig(My config value,123456,List(1 hour, 2 minutes, 3 seconds)))

Supported types

configs can get many type values from config. It is provided by type class Configs.

There are a number of built-in Configs instances:

  • Primitive/Wrapper types
    • Long, Int, Short, Byte, Double, Float, Char, Boolean
    • java.lang.{Long, Integer, Short, Byte, Double, Float, Character, Boolean}
  • Big number types
    • BigInt, BigDecimal
    • java.math.{BigInteger, BigDecimal}
  • String representation types
    • String
    • Symbol, java.util.{UUID, Locale}
    • java.io.File, java.nio.file.Path
    • java.net.{URI, InetAddress}
  • Duration types
    • java.time.Duration
    • scala.concurrent.duration.{Duration, FiniteDuration}
  • Config types
    • com.typesafe.config.{Config, ConfigValue, ConfigList, ConfigObject, ConfigMemorySize}
    • configs.Bytes
  • Enum types
    • Java enum types
    • Scala Enumeration types
  • Collection types
    • F[A] (using CanBuildFrom[Nothing, A, F[A]], e.g. List[String], Seq[Int])
    • M[S, A] (using CanBuildFrom[Nothing, (S, A), M[S, A]], e.g. Map[String, Int], TreeMap[UUID, Config])
    • java.util.{List[A], Map[S, A], Set[A], Collection[A]}, java.lang.Iterable[A]
    • java.util.Properties
  • Optional types
    • Option[A]
    • java.util.{Optional[A], OptionalLong, OptionalInt, OptionalDouble}
  • case classes
  • classes that have public constructors
  • ADTs (sealed trait + classes/objects). See ADTs support
  • Java Beans. See Java Beans support

In this list, A means any type that is Configs instance. And S means any type that is FromString instance.

ADTs support

If there is such an ADT:

sealed trait Tree
case class Branch(value: Int, left: Tree, right: Tree) extends Tree
case object Leaf extends Tree

You can get an ADT value from config:

val config = ConfigFactory.parseString("""
  tree = {
    type = Branch
    value = 42
    left = Leaf
    right {
      type = Branch
      value = 123
      left = Leaf
      right = { type = Leaf }
    }
  }
  """)
scala> config.get[Tree]("tree")
res9: configs.Result[Tree] = Success(Branch(42,Leaf,Branch(123,Leaf,Leaf)))

Java Beans support

If there is Java Beans class like the follows:

@lombok.Data
public class MyBean {
    private int intValue;
    private java.util.List<String> stringList;
    private java.util.Map<java.util.Locale, java.time.Duration> localeToDuration;
}

Then you define Configs instance using deriveBean macro:

implicit val myBeanConfigs: Configs[MyBean] =
  Configs.deriveBean[MyBean]

And then you can get Java Beans value:

val config = ConfigFactory.parseString("""
  int-value = 42
  string-list = [foo, bar, baz]
  locale-to-duration {
    ja_JP = 42ms
    en_US = 123s
  }
  """)
scala> config.extract[MyBean]
res10: configs.Result[MyBean] = Success(MyBean(intValue=42, stringList=[foo, bar, baz], localeToDuration={en_US=PT2M3S, ja_JP=PT0.042S}))

License

Copyright 2013-2016 Tsukasa Kitachi

Apache License, Version 2.0

About

Scala wrapper for Typesafe config

License:Apache License 2.0


Languages

Language:Scala 93.9%Language:Java 6.1%