Использование Jackson для (De)-сериализации класса случая Scala

я протестировал сериализацию класса Scala case с помощью Jackson.

DeserializeTest.java

    public static void main(String[] args) throws Exception { // being lazy to catch-all

        final ObjectMapper mapper          = new ObjectMapper();
        final ByteArrayOutputStream stream = new ByteArrayOutputStream();

        mapper.writeValue(stream, p.Foo.personInstance());

        System.out.println("result:" +  stream.toString());
    }
}

Фу.скала!--8-->

object Foo {
  case class Person(name: String, age: Int, hobbies: Option[String])
  val personInstance = Person("foo", 555, Some("things"))
  val PERSON_JSON = """ { "name": "Foo", "age": 555 } """
}

когда я побежал выше main из класса Java было создано исключение:

[error] Exception in thread "main" org.codehaus.jackson.map.JsonMappingException: 
 No serializer found for class p.Foo$Person and no properties discovered 
 to create BeanSerializer (to avoid exception, 
 disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) )

как я могу (de)-сериализовать классы Scala case?

3 ответов


Джексон ожидает, что ваш класс будет JavaBean, что означает, что он ожидает, что класс будет иметь getX() и / или setX () для каждого свойства.

1

вы можете создавать классы JavaBean в Scala, используя аннотацию BeanProperty.

пример

case class Person(
   @BeanProperty val name: String, 
   @BeanProperty val age: Int, 
   @BeanProperty val hobbies: Option[String]
)

в этом случае val будет означать, что определен только геттер. Если вам нужны сеттеры для десериализации, вы определили свойства как Вар.

2

в то время как вариант 1 будет работать, если вы действительно хотите использовать Jackson, есть обертки, которые позволяют ему иметь дело с классами Scala, такими как модуль scala FasterXML что может быть лучшим подходом. Я не использовал его, поскольку я только что использовал встроенную библиотеку Json для игры.


найдено решение, которое работает с классами Джексона и Scala case.

я использовал модуль scala для jackson-jackson-module-scala.

libraryDependencies ++= Seq(
 "com.fasterxml.jackson.core" % "jackson-databind" % "2.5.3",
 "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.2.2"
)

мне пришлось аннотировать поля в моем классе case с помощью @JsonProperty.

вот как выглядит мой класс case:

case class Person(@JsonProperty("FName") FName: String, @JsonProperty("LName") LName: String)

и это, как мне десериализовать:

val objectMapper = new ObjectMapper() with ScalaObjectMapper
objectMapper.registerModule(DefaultScalaModule)
val str = """{"FName":"Mad", "LName": "Max"}"""
val name:Person = objectMapper.readValue[Person](str)

сериализация-это проще:

val out = new ByteArrayOutputStream()
objectMapper.writeValue(out, name)
val json = out.toString

хотелось бы уточнить, что я использую

com.fasterxml.jackson.databind.ObjectMapper

в вопросе, похоже, он использует

org.codehaus.jackson.map.ObjectMapper 

который не будет работать с ScalaObjectMapper.


на основе ответа Priyank Desai я создал общую функцию для преобразования json string to case class

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper

def jsonToType[T](json:String)(implicit m: Manifest[T]) :T = {
   val objectMapper = new ObjectMapper() with ScalaObjectMapper
   objectMapper.registerModule(DefaultScalaModule)
   objectMapper.readValue[T](json)
}

использование:

case class Person(@JsonProperty("name") Name:String, @JsonProperty("age") Age:Int)

val personName = jsonToType[Person](jsonString).name