Skip to content

Instantly share code, notes, and snippets.

@havocp
Created May 28, 2012 15:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save havocp/2819638 to your computer and use it in GitHub Desktop.
Save havocp/2819638 to your computer and use it in GitHub Desktop.
sketchy config scala wrapper
package scala.config
import scala.config._
import com.typesafe.{ config => j }
sealed trait ConfigMergeable {
def asJava: j.ConfigMergeable
def withFallback(mergeable: ConfigMergeable): ConfigMergeable
}
sealed trait ConfigValue extends ConfigMergeable {
private[config] def underlying: j.ConfigValue
def asJava: j.ConfigValue = underlying
def origin = underlying.origin
def unwrapped: Any = underlying.unwrapped
def render() = underlying.render
def render(options: ConfigRenderOptions) = underlying.render(options)
override def withFallback(mergeable: ConfigMergeable) = underlying.withFallback(mergeable.asJava).asScala
}
/**
* This class is an implementation detail for sharing code among concrete ConfigValue
*/
sealed abstract class GenericConfigValue[U <: j.ConfigValue](private[config] override val underlying: U) extends ConfigValue {
override def asJava: U = underlying
protected def unwrappedAsScala(v: Any): Any = {
import scala.collection.JavaConverters._
v match {
case null =>
null
case m: java.util.Map[_, _] =>
m.asScala.toMap.asInstanceOf[Map[String, Any]].map({ kv => (kv._1, unwrappedAsScala(kv._2)) })
case l: java.util.List[_] =>
l.asScala.toSeq.asInstanceOf[Seq[Any]].map({ v => unwrappedAsScala(v) })
case n: java.lang.Number =>
n
case b: java.lang.Boolean =>
b
case s: String =>
s
}
}
// FIXME equals and hashCode
}
final class ConfigObject private[config] (underlying: j.ConfigObject) extends GenericConfigValue[j.ConfigObject](underlying) {
def toConfig = underlying.toConfig.asScala
override def unwrapped: Map[String, Any] = unwrappedAsScala(underlying.unwrapped).asInstanceOf[Map[String, Any]]
}
final class ConfigNumber private[config] (underlying: j.ConfigValue) extends GenericConfigValue[j.ConfigValue](underlying) {
require(underlying.valueType == j.ConfigValueType.NUMBER)
override def unwrapped: Number = underlying.unwrapped.asInstanceOf[Number]
}
final class ConfigString private[config] (underlying: j.ConfigValue) extends GenericConfigValue[j.ConfigValue](underlying) {
require(underlying.valueType == j.ConfigValueType.STRING)
override def unwrapped: String = underlying.unwrapped.asInstanceOf[String]
}
final class ConfigBoolean private[config] (underlying: j.ConfigValue) extends GenericConfigValue[j.ConfigValue](underlying) {
require(underlying.valueType == j.ConfigValueType.BOOLEAN)
override def unwrapped: Boolean = underlying.unwrapped.asInstanceOf[Boolean]
}
final class ConfigList private[config] (underlying: j.ConfigValue) extends GenericConfigValue[j.ConfigValue](underlying) {
import scala.collection.JavaConverters._
require(underlying.valueType == j.ConfigValueType.LIST)
override def unwrapped: Seq[Any] = unwrappedAsScala(underlying.unwrapped).asInstanceOf[Seq[Any]]
}
final class ConfigNull private[config] (underlying: j.ConfigValue) extends GenericConfigValue[j.ConfigValue](underlying) {
require(underlying.valueType == j.ConfigValueType.NULL)
override def unwrapped: Null = null
}
final class ConfigUnresolved private[config] (underlying: j.ConfigValue) extends GenericConfigValue[j.ConfigValue](underlying) {
override def unwrapped: Unit = underlying.unwrapped() // this should throw
}
final class Config private[config] (private[config] val underlying: j.Config) extends ConfigMergeable {
override def asJava: j.Config = underlying
override def withFallback(mergeable: ConfigMergeable) = underlying.withFallback(mergeable.asJava).asScala
// FIXME equals and hashCode
}
object Config {
def defaultRenderOptions = j.ConfigRenderOptions.defaults
def defaultParseOptions = j.ConfigParseOptions.defaults
def defaultResolveOptions = j.ConfigResolveOptions.defaults
}
///////////////////////// package.scala
package scala
package object config {
import com.typesafe.{ config => j }
import scala.config._
type ConfigOrigin = j.ConfigOrigin
type ConfigRenderOptions = j.ConfigRenderOptions
type ConfigParseOptions = j.ConfigParseOptions
type ConfigResolveOptions = j.ConfigResolveOptions
type ConfigException = j.ConfigException
/**
* Convert an underlying Java config to a Scala equivalent
*/
def configAsScalaConfig(config: j.Config): Config = new Config(config)
/**
* Enrich Java config with asScala method.
* FIXME convert to Scala 2.10 implicit class
*/
final class RichJavaConfig(config: j.Config) {
def asScala = configAsScalaConfig(config)
}
implicit def asRichJavaConfig(config: j.Config): RichJavaConfig = new RichJavaConfig(config)
/**
* Convert an underlying Java config value to a Scala equivalent
*/
def configValueAsScalaConfigValue(v: j.ConfigValue): ConfigValue = v match {
// ConfigObject is pulled out separately because if it's
// unresolved we still want to make a ConfigObject not a
// ConfigUnresolved
case o: j.ConfigObject =>
new ConfigObject(o)
case _ =>
try {
v.valueType() match {
case j.ConfigValueType.BOOLEAN =>
new ConfigBoolean(v)
case j.ConfigValueType.LIST =>
new ConfigList(v)
case j.ConfigValueType.NULL =>
new ConfigNull(v)
case j.ConfigValueType.NUMBER =>
new ConfigNumber(v)
case j.ConfigValueType.STRING =>
new ConfigString(v)
case j.ConfigValueType.OBJECT =>
// should have been handled already earlier
throw new j.ConfigException.BugOrBroken("should have handled object earlier")
}
} catch {
case e: j.ConfigException.NotResolved =>
new ConfigUnresolved(v)
}
}
/**
* Enrich Java config with asScala method.
* FIXME convert to Scala 2.10 implicit class
*/
final class RichJavaConfigValue(v: j.ConfigValue) {
def asScala = configValueAsScalaConfigValue(v)
}
implicit def asRichJavaConfigValue(v: j.ConfigValue): RichJavaConfigValue = new RichJavaConfigValue(v)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment