2013-10-15 2 views
6

Мы все знаем, что общие типы подлежат стиранию типов под Java и Scala. Но мы столкнулись с какой-то странной проблемой в Scala, используя Jackson и модуль Scala Jackson.Странные проблемы десериализации с использованием общих типов с использованием Scala и Jackson и java.lang.Integer или scala.Int

Я создал небольшой тест, чтобы показать проблему.

import com.fasterxml.jackson.databind.ObjectMapper 
import com.fasterxml.jackson.module.scala.DefaultScalaModule 

object GenericTest { 

    case class TestWithInt(id: Option[Int]) 
    case class TestWithInteger(id: Option[Integer]) 

    def main(args: Array[String]) { 

    val mapper = new ObjectMapper() 
    mapper.registerModule(DefaultScalaModule) 

    // Test with scala's Int 
    val test = mapper.readValue[TestWithInt]("""{ "id" : 5 }""", classOf[TestWithInt]) 
    print("Test 1: ") 
    println(test.id.get + 1) 

    val test2 = mapper.readValue[TestWithInt]("""{ "id" : "5" }""", classOf[TestWithInt]) 
    print("Test 2: ") 
    try { 
     println(test2.id.get + 1) 
    } catch { 
     case e: ClassCastException => println(e.getMessage) 
    } 

    // Test with java.lang.Integer 
    val test3 = mapper.readValue[TestWithInteger]("""{ "id" : 5 }""", classOf[TestWithInteger]) 
    print("Test 3: ") 
    println(test3.id.get + 1) 

    val test4 = mapper.readValue[TestWithInteger]("""{ "id" : "5" }""", classOf[TestWithInteger]) 
    print("Test 4: ") 
    println(test4.id.get + 1) 
    } 
} 

Выход из выше:

Test 1: 6 
Test 2: java.lang.String cannot be cast to java.lang.Integer 
Test 3: 6 
Test 4: 6 

Где это другой вид поведения взялось? Generic Type Erasure, Jackson, Jackson Scala Module?

+0

Я не достаточно хорошо знаком с Scala, но я предполагаю, что у Jackson есть встроенный конвертер, который знает, как обрабатывать преобразование для типа Java, но не Scala. – chrylis

+0

Хм, может быть ... создал проблему для этого, перекрестные ссылки на этот вопрос: https://github.com/FasterXML/jackson-module-scala/issues/104 – longliveenduro

ответ

3

Это становится такой общий вопрос, который я написал FAQ для него:

[а] LL параметры примитивного типа представлены как Object к JVM. ... Модуль Scala сообщил Джексону, что Option фактически является типом контейнера, но он полагается на отражение Java, чтобы определить содержащийся тип, и приходит с Object.

Нынешним обходным путем для этого варианта использования является добавление аннотации @JsonDeserialize к целевому объекту. В частности, это аннотацию имеет набор параметров, которые могут быть использованы для различных ситуаций:

  • contentAs для коллекций или значений карты (поддерживается)
  • keyAs для ключей карты (в настоящее время не поддерживается)

Примеров как использовать эту аннотацию can be found in the tests directory.

В ЧаВо для более любознательных вопросов есть более подробная информация.

+0

Благодарим за отличное объяснение и вопросы и ответы! – longliveenduro

0

Казалось бы, потому что java.lang.Integer имеет constructor, который принимает строку, которая позволяет десериализатор использовать это для Integer тогда, что это не тот случай с Int

+0

Нет, если вы запустите программу в отладчике и установите точки останова в конструкторах java.lang.Integer с int и String нет ударов конструктора String, только на int one! – longliveenduro

Смежные вопросы