Kotlin - общая функция, успешно сохраняющая неверный тип на карте - PullRequest
0 голосов
/ 25 апреля 2019

Рассмотрим следующий код:

val myarray = arrayListOf("hello", "world")
println(myarray)
println(myarray::class.java.name)

val arrayString = mapper.writeValueAsString(myarray)
println(arrayString)
println(arrayString::class.java.name)

val myMap = HashMap<String, String?>()
myMap["key"] = JsonPath.read<String>(arrayString, "$")

println(myMap["key"])
println(myMap["key"]!!::class.java.name)

Этот код создает ArrayList, содержащий значения «hello» и «world», преобразует список в строку json, считывает корневой элемент json (который является универсальной функцией, для которой требуется вернуть строку) и сохраняет его в HashMap

Этот код компилируется и выполняется без ошибок и выдает следующий вывод:

[hello, world]
java.util.ArrayList
["hello", "world"]
java.lang.String
["hello","world"]
net.minidev.json.JSONArray

Как myMap["key"] возвращает JSONArray? (напомним, что myMap был объявлен как <String, String?>)

Kotlin проверяет его тип во время компиляции, но поскольку универсальная функция JsonPath.read сообщает, что она возвращает String, компиляция происходит нормально.

Тогда, похоже, JsonPath.read нарушает свой контракт и возвращает JSONArray вместо String. Kotlin, похоже, не проверяет тип и позволяет хранить JSONArray в пределах Map<String, String?>.

Нет ошибок, если я не попытаюсь использовать myMap["key"] как String

Примечание

Эту проблему можно решить, изменив строку, которая читает json:

myMap["key"] = ObjectMapper().writeValueAsString(JsonPath.read<String>(arrayString, "$"))

EDIT

Пример кода без использования JSON Madness:

fun <T> myFun(): T {
  return 7 as T
}

fun test() {
  val map = HashMap<String, String?>()
  map["key"] = myFun<String>()
  println(map["key"])
  println(map["key"]!!::class.java.name)
}

returns:
7
java.lang.Integer

Ответы [ 2 ]

1 голос
/ 25 апреля 2019

Информация общего типа стирается во время выполнения .

Так что, в основном, просто берём обновленный пример и переводим его в то, что будет во время выполнения (упрощенно):

fun myFun(): Any = 7

fun test() {
  val map = HashMap<Any, Any?>()
  map["key"] = myFun()
  println(map["key"])
  println(map["key"]!!::class.java.name) // of course: Integer!
}

Обратите также внимание, что вы использовали неконтролируемое приведение здесь (и, скорее всего, JsonPath.read использует его), что в основном является причиной того, почему у компилятора нет реальной возможности уловить проблему. Или, другими словами, используя unchecked cast (7 as T), вы в основном говорите компилятору «эй ... я знаю, что делаю, не беспокойтесь» ... и так не беспокоит; -)

0 голосов
/ 25 апреля 2019

Подобная проблема отслеживается как https://youtrack.jetbrains.com/issue/KT-12451.

В настоящее время Kotlin не проверяет результат вызова универсального метода перед передачей его другому универсальному методу, даже если на сайте вызова он знаетуточненный тип параметра универсального типа.Это поведение такое же, как в Java, хотя могут быть некоторые возможности для улучшения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...