2016-05-07 22 views
5

Tôi muốn đọc cấu hình sau từ tệp HOCON (Typesafe Config) vào Kotlin.Đọc và xử lý HOCON ở 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 } } 
    ] 
} 

Thực tế, tôi muốn trích xuất (các) cột chính. Tôi đã thử những điều sau đây cho đến nay.

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

Nhưng không thành công với lỗi sau.

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 

Rõ ràng Kotlin không thể hiểu loại dữ liệu của trường "giá trị" trong Bản đồ. Làm thế nào để tôi tuyên bố nó hoặc để Kotlin biết?

Ngoài ra không có các loại khác nhau và các phím tùy chọn trong Bản đồ này.

PS: Tôi biết rằng có một vài trình bao bọc có sẵn cho Kotlin như Konfig và Klutter. Tôi đã hy vọng rằng nếu điều này là dễ dàng để viết tôi có thể tránh một thư viện.

UPDATE 1:

Tôi đã thử những điều sau đây.

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

để nhận lỗi trình biên dịch sau.

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 

Và đây

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

với sản lượng

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:

Nhìn vào cách nó được xử lý ở những nơi khác, tôi đoán tôi có lẽ cần phải sử dụng phản ánh. Đang thử nó với tiếp xúc hạn chế của tôi. Không may mắn cho đến nay.

+0

Tôi có thể không cần phải tháo đối tượng cấu hình. Nhưng đối phó với nó như là không mang lại bất kỳ kết quả và đây là gần nhất tôi có thể mang lại cho nó để "in" một cái gì đó. –

Trả lời

7

xem xét mã của bạn, deconstructed dưới đây:

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 
     } 

Từ trên vấn đề cần được rõ ràng. Bạn cần phải hỗ trợ các trình biên dịch với các thông tin mà firstValue giữ một Map như vậy:

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

Cảm ơn! Nó đã làm việc. –

+0

Tôi cũng phải chặn cảnh báo UNCHECKED_CAST. –

2

Mặc dù bạn không sử dụng Klutter, tôi tạo ra một bản cập nhật cho nó để tạo ConfigObjectConfig hành thống nhất như vậy. Từ phiên bản Klutter 1.17.1 trở đi (đẩy tới trung tâm Maven ngày hôm nay) bạn có thể làm những gì được thể hiện trong bài kiểm tra đơn vị sau dựa trên câu hỏi của bạn.

Chức năng tìm kiếm các cột chính:

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() 
} 

Đây là thử nghiệm đầy đủ đơn vị cho việc này:

// 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()) 
} 

Bạn có thể trả về một Map như trên, hoặc một danh sách các Pair cho tên cột để ánh xạ cài đặt vì tên cột không nằm trong cài đặt của nó.

Thiết kế của tệp cấu hình cũng có thể được thay đổi để làm cho việc xử lý cấu hình đơn giản hơn (tức là tên của bảng bên trong đối tượng cấu hình của nó, chứ không phải là khóa bên trái. vào đối tượng và không phải là khóa bên trái.)

Các vấn đề liên quan