#java #scala #casting #autoboxing
#java #scala #Кастинг #автоматическая блокировка
Вопрос:
Мне нужно разобрать Json в структуру Map[String,String] . Json может содержать числовые и строковые типы в качестве значений.
Итак, чтобы сохранить его как строку, я применил метод toString, и он выдает ClassCastException . Однако, если применяется String.valueOf(), все в порядке.
- Почему так?
- Если есть лучший способ сделать такое приведение?
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import scala.collection.Map
import scala.util.parsing.json.JSON
val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)
val str = "[ { "name": "VehicleType", "value": 11 }, { "name": "VehicleWeight", "value": "12000" } ]"
val customfields = JSON.parseFull(str) match {
case Some(map: List[Map[String, String]]) =>
// map.map(map => {map("name") -> map("value").toString}).toMap
// that throws:
// java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String
// at #worksheet#.$anonfun$customfields$1.apply(scratch.scala2:14)
// at #worksheet#.$anonfun$customfields$1.apply(scratch.scala2:14)
// at scala.collection.immutable.List.map(scratch.scala2:269)
// at #worksheet#.customfields$lzycompute(scratch.scala2:14)
// that works fine
map.map(map => {map("name") -> String.valueOf(map("value"))}).toMap
case _ => Map.empty[String, String]
}
Комментарии:
1. Я полагаю, что здесь произошло следующее: в первом
match
случае результат синтаксическогоList[Map[String, String]]
анализа преобразуется в, хотя это не то, что есть; из-за частичного стирания типа приведениеList
не завершается ошибкой. На этом этапе у вас есть загрязнение кучи : естьDouble
значения со статическим типомString
, что приводит к aClassCastException
при попытке разыменования одного из них.
Ответ №1:
Поскольку сопоставление шаблонов соответствует типу списка, но не распространяется на все типы внутри карты, вот почему вы вводите Some
предложение.
Итак, вместо case Some(map: List[Map[String, String]]) =>
Попробуйте сделать это:
case Some(map: List[Map[String, _]]) =>
map.map(map => {map("name") ->
map("value") match {
case s: String => s
case i: java.lang.Number => i
case unexpectedType => throw Exception(s"Unexpected type $unexpectedType")
}.toString}).toMap
Вот как вы можете безопасно обрабатывать каждое значение в вашей карте.