2016-05-07 12 views
5

次の設定をHOCON(Typesafe Config)ファイルからKotlinに読み込みたいと思います。KotlinでのHOCONの読み込みと処理

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 } } 
    ] 
} 

実際にキー列を抽出したいと思います。私はこれまでに以下のことを試みました。

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

ただし、次のエラーで失敗します。

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 

Kotlinが地図に「値」フィールドのデータ型を理解することができないことは明らかです。それを宣言するか、コトリンに知らせるには?

また、このマップには異なるタイプとオプションのキーがあります。

PS:私は、KonfigやKlutterのようなKotlinに利用可能ないくつかのラッパーがあることを知っています。私はこれが書くのが簡単ならば別の図書館を避けることができると期待していました。

UPDATE 1:

私は次のことを試してみました。

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

次のコンパイラエラーが発生します。出力

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 

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 

そしてこの

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

UPDATE 2:それは別の場所で処理される方法を見てみると

、私はおそらく使用する必要があると思います反射。私の限られた露出でそれを試してみてください。今まで運がない。明らかである問題以上から

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 
     } 

+0

おそらく設定オブジェクトのラップを解除する必要はありません。しかし、それをそのまま扱うと結果は得られませんでしたが、これは私が何かを "プリント"するためにもっとも近いものでした。 –

答えて

7

は下の解体、あなたのコードを考えてみましょう。あなたはfirstValueがそうのようなMapを保持していることの情報をコンパイラを支援する必要があります。それはConfigObjectConfig行為一様に同じにするために

val firstValueMap = firstValue as Map<String,Any?> 
firstValueMap["key"] == true 
+0

ありがとう!出来た。 –

+0

UNCHECKED_CAST警告も抑制する必要がありました。 –

2

あなたがKlutterを使用していないにもかかわらず、私が更新を作成しました。 Klutterのバージョン1.17.1以降(今日のMavenの中心に)、あなたの質問に基づいて、次の単体テストで表現されていることができます。

キー列見出し機能:ここで

fun findKeyColumns(cfg: Config, tableName: String): Map<String, ConfigObject> { 
    return cfg.nested(tableName).value("columns").asObjectList() 
      .map { it.keys.single() to it.value(it.keys.single()).asObject() } 
      .filter { 
       it.second.value("key").asBoolean(false) 
      } 
      .toMap() 
} 

は、このために、完全なユニットテストです:

// from http://stackoverflow.com/questions/37092808/reading-and-processing-hocon-in-kotlin 
@Test fun testFromSo37092808() { 
    // === mocked configuration file 

    val cfg = loadConfig(StringAsConfig(""" 
      products: { 
       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 } } 
       ] 
      } 
      """)) 

    // === function to find which columns are key columns 

    fun findKeyColumns(cfg: Config, tableName: String): Map<String, ConfigObject> { 
     return cfg.nested(tableName).value("columns").asObjectList() 
       .map { it.keys.single() to it.value(it.keys.single()).asObject() } 
       .filter { 
        it.second.value("key").asBoolean(false) 
       } 
       .toMap() 
    } 

    // === sample usage 

    val productKeys = findKeyColumns(cfg, "products") 

    // we only have 1 in the test data, so grab the name and the values 
    val onlyColumnName = productKeys.entries.first().key 
    val onlyColumnObj = productKeys.entries.first().value 

    assertEquals ("item", onlyColumnName) 
    assertEquals (true, onlyColumnObj.value("key").asBoolean()) 
    assertEquals ("integer", onlyColumnObj.value("type").asString()) 
    assertEquals (false, onlyColumnObj.value("null").asBoolean()) 
} 

あなたは、上記のようにMapを返す、またはのためのPairのリストができ列名が設定内にないため、列名と設定のマッピングを変更する必要があります。

コンフィギュレーションファイルのデザインを変更することで、コンフィギュレーションの処理をよりシンプルにすることもできます(左側のキーではなく、設定オブジェクト内のテーブルの名前)。左側のキーではなくオブジェクトに移動してください)。

関連する問題