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

airframe-config: Support loading JavaBean? #109

Closed
0x1997 opened this issue Oct 9, 2017 · 4 comments
Closed

airframe-config: Support loading JavaBean? #109

0x1997 opened this issue Oct 9, 2017 · 4 comments
Labels

Comments

@0x1997
Copy link
Contributor

0x1997 commented Oct 9, 2017

No description provided.

@xerial
Copy link
Member

xerial commented Oct 9, 2017

Could you give me more context?

@0x1997
Copy link
Contributor Author

0x1997 commented Oct 10, 2017

val config = Config(env = configEnv, configPaths = Seq(configPath))
      .registerFromYaml[FooConfig]("foo.yml")

This doesn't work when FooConfig is a JavaBean instead of a scala case class.
My workaround is like this

import java.io.{File, FileNotFoundException}

import scala.collection.JavaConverters._
import scala.reflect.runtime.universe._

import org.yaml.snakeyaml.{TypeDescription, Yaml}
import org.yaml.snakeyaml.constructor.Constructor
import wvlet.config.Config
import wvlet.log.LogSupport
import wvlet.log.io.IOUtil.readAsString
import wvlet.surface

object Yaml2JavaBean {
  implicit class ConfigWithJavaBeanSupport(config: Config) extends LogSupport {
    def registerJavaBeanFromYaml[T: TypeTag](yamlFile: String): Config = {
      val env = config.env
      val tpe = surface.of[T]
      val realPath = env.configPaths
        .map(p => new File(p, yamlFile))
        .find(_.exists())
        .map(_.getPath)
        .getOrElse {
          throw new FileNotFoundException(
            s"$yamlFile is not found in ${env.configPaths.mkString(":")}")
        }
      val constructor = new Constructor()
      constructor.addTypeDescription(
        new TypeDescription(
          typeTag[T].mirror.runtimeClass(typeOf[T].typeSymbol.asClass),
          "!bean"))
      val yaml = new Yaml(constructor)
      val m = yaml
        .loadAs(readAsString(realPath), classOf[java.util.Map[String, T]])
        .asScala

      val conf = m.get(env.env) match {
        case Some(x) =>
          info(s"Loading $tpe from $realPath, env:${env.env}")
          x
        case None =>
          // Load default
          debug(
            s"Configuration for ${env.env} is not found in $realPath. Load ${env.defaultEnv} configuration instead")
          m.get(env.defaultEnv) map { x =>
            info(s"Loading $tpe from $realPath, default env:${env.defaultEnv}")
            x
          } getOrElse {
            throw new IllegalArgumentException(
              s"No configuration for $tpe (${env.env} or ${env.defaultEnv}) is found")
          }
      }

      config.register[T](conf)
    }
  }
}
import Yaml2JavaBean._

val config = Config(env = configEnv, configPaths = Seq(configPath))
      .registerJavaBeanFromYaml[FooConfig]("foo.yml")

where foo.yml is like this

default: !bean
  application:
    name: foo-service
  registry:
    protocol: zookeeper
    address: 10.10.0.1:2181,10.10.0.2:2182,10.10.0.3:2183
  id: fooService
  interface: com.foo.service.FooService
  version: 1.0.0
  timeout: 100

@xerial
Copy link
Member

xerial commented Nov 24, 2017

In #110, I've changed how to map Yaml -> Objects. Yaml data is converted to MessagePack binary data, and it is read in ObjectCodec (airframe-tablet). By adding MsgPack -> JavaBeans codec, it would be possible to support this type of binding in a more generic manner.

Alternatively simply adding your workaround to airframe-config might be convenient for you.

@xerial
Copy link
Member

xerial commented Dec 2, 2018

Using mutable JavaBeans is not a good practice in Scala. I think we will not address this.

@xerial xerial closed this as completed Dec 2, 2018
@xerial xerial added the wontfix label Dec 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants