Использование 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