Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading and Processing HOCON in Kotlin

I would like to read the following configuration from a HOCON (Typesafe Config) file into Kotlin.

tablename: {  
  columns: [
    { item: { type: integer, key: true, null: false } }
    { desc: { type: varchar, length: 64 } }
    { quantity: { type: integer, null: false } }
    { price: { type: decimal, precision: 14, scale: 3 } }
  ]
}

In fact I would like to extract the key column(s). I have tried the following so far.

val metadata = ConfigFactory.parseFile(metafile)
val keys = metadata.getObjectList("${tablename.toLowerCase()}.columns")
                   .filter { it.unwrapped().values.first().get("key") == true }

But it fails with the following error.

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
@kotlin.internal.InlineOnly public operator inline fun <@kotlin.internal.OnlyInputTypes K, V> kotlin.collections.Map<out kotlin.String, ???>.get(key: kotlin.String): ??? defined in kotlin.collections

It is clear that Kotlin is not able to understand the data type of the "value" field in the Map. How do I declare it or let Kotlin know?

Also not that there are different types and optional keys in this Map.

PS: I know that there are couple of wrappers available for Kotlin such as Konfig and Klutter. I was hoping that if this is easy to write I could avoid another library.

UPDATE 1:

I have tried the following.

it.unwrapped().values.first().get<String, Boolean>("key")

to get the following compiler error.

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
@kotlin.internal.InlineOnly public operator inline fun <@kotlin.internal.OnlyInputTypes K, V> kotlin.collections.Map<out kotlin.String, kotlin.Boolean>.get(key: kotlin.String): kotlin.Boolean? defined in kotlin.collections

And this

it.unwrapped().values.first().get<String, Boolean?>("key")

with output

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
@kotlin.internal.InlineOnly public operator inline fun <@kotlin.internal.OnlyInputTypes K, V> kotlin.collections.Map<out kotlin.String, kotlin.Boolean?>.get(key: kotlin.String): kotlin.Boolean? defined in kotlin.collections

UPDATE 2:

Looking at the way it is handled elsewhere, I guess I probably need to use reflection. Trying it out with my limited exposure. No luck so far.

like image 446
Geordee Naliyath Avatar asked May 07 '16 19:05

Geordee Naliyath


1 Answers

Consider your code, deconstructed below:

val keys = metadata.getObjectList("tablename.columns")
        .filter {
            val item:ConfigObject = it
            val unwrapped:Map<String,Any?> = item.unwrapped()
            val values:Collection<Any?> = unwrapped.values
            val firstValue:Any? = values.first()
            firstValue.get("key") == true // does not compile
        }

From the above the problem should be obvious. You need to aid the compiler with the information that firstValue holds a Map like so:

val firstValueMap = firstValue as Map<String,Any?>
firstValueMap["key"] == true
like image 162
Sakura Avatar answered Oct 21 '22 08:10

Sakura