Kotlin使用Typesafe加载HOCON为实体类

一.背景


在上一片文章讲解了typesafe加载HOCON为实体类,那么为什么还要单独写一篇Kotlin加载的事例呢?java和kotlin不是都是依赖jvm么?是的理论上来说java能用的kotlin也是没有问题的,关键是我们在kotlin中使用实体类的方式和java中有所不同,而且typesafe转换实体类的接口并没有兼容kotlin的方式,也没有提供类似的接口,看下面我们同样使用java一样的方式转换实体类的时候的情况:

data class AppConfigKotlin (
    val demo: Demo
) {
    companion object {
        fun loadConfKotlin01() {
            val config = ConfigFactory.parseFile(File("./config/app.conf"))

            val appConfig = ConfigBeanFactory.create(config, AppConfigKotlin::class.java)
            val name = appConfig.demo.name
            println("Name:$name")
        }
    }
}

data class Demo(
    val name: String,
    val age: Int,
    val men: Boolean,
    val address: List<String>,
    val family: Map<String, Any>
)

结果报了如下异样:

com.typesafe.config.ConfigException$BadBean: AppConfigKotlin needs a public no-args constructor to be used as a bean

下面我们来看源码:

public static <T> T createInternal(Config config, Class<T> clazz) {
    // ......
    // Fill in the bean instance
            T bean = clazz.newInstance();
            for (PropertyDescriptor beanProp : beanProps) {
                Method setter = beanProp.getWriteMethod();
                Type parameterType = setter.getGenericParameterTypes()[0];
                Class<?> parameterClass = setter.getParameterTypes()[0];
                String configPropName = originalNames.get(beanProp.getName());
                // Is the property key missing in the config?
                if (configPropName == null) {
                    // If so, continue if the field is marked as @{link Optional}
                    if (isOptionalProperty(clazz, beanProp)) {
                        continue;
                    }
                    // Otherwise, raise a {@link Missing} exception right here
                    throw new ConfigException.Missing(beanProp.getName());
                }
                Object unwrapped = getValue(clazz, parameterType, parameterClass, config, configPropName);
                setter.invoke(bean, unwrapped);
            }
            return bean;
    //......
}

在我们调用ConfigBeanFactory.create(config, AppConfigKotlin::class.java)将config转换为AppConfigKotlin数据类的时候,最后会执行到如上的代码,需要根据传入的.Class参数调用clazz.newInstance()实例化一个对象,然而我们kotlin是使用的data class,没有默认的那个构造函数,所以报出了这样的异常。看来直接使用与java相同的方式是不行了,那么有没有什么解决方案呢?下面来看看解决方案。


二.使用


1.引入Config4k.jar

Config4k是Kotlin的轻量级Typesafe Config包装器,提供了简单的扩展功能Config.extract<T>以及Any.toConfigConfigKotlin对象之间进行转换。当然之前的typesafe.jar也是需要的,这里是要新加的一个jar包。


maven

<dependency>
    <groupId>io.github.config4k</groupId>
    <artifactId>config4k</artifactId>
    <version>0.4.2</version>
</dependency>

Gradle

compile group: 'io.github.config4k', name: 'config4k', version: '0.4.2'

2.实例代码


config file

在项目根路径新建config文件夹用来放我们的配置文件app.conf("./config/app.conf")

demo {
  name = "Jerry"
  age = 21
  men = false
  // list类型
  address = [
    "address4"
    "address5"
    "address6"
  ]
  // map类型
  family {
    mather = "sister"
    father = "brother"
  }
}

加载为data class

data class AppConfigKotlin (
    val demo: Demo
) {
    companion object {
        fun loadConfKotlin01() {
            val config = ConfigFactory.parseFile(File("./config/app.conf"))

            // 将config转换为data class
            val appConfig = config.extract<AppConfigKotlin>()
            val name = appConfig.demo.name
            println("Name:$name")
        }
    }
}

data class Demo(
    val name: String,
    val age: Int,
    val men: Boolean,
    val address: List<String>,
    val family: Map<String, Any>
)

结果:

Name:Jerry

BUILD SUCCESSFUL in 44s

其他功能

config4k还有其他的很多功能,比如支持enum,序列化等,更多的内容可以看config4k文档或者源码

enum class Size {
    SMALL,
    MEDIUM,
    LARGE
}

val config = ConfigFactory.parseString("""key = SMALL""")
val small = config.extract<Size>("key")
println(small == Size.SMALL) // true
data class Person(val name: String, val age: Int)
val person = Person("foo", 20).toConfig("person")
println(person.root().render())

完整代码

Github中的typesafe-test项目

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值