Using Jackson to (De) serialize a Scala Case Class

I tested case serialization of the Scala class using 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()); } } 

Foo.scala

 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 } """ } 

When I ran above the main Java class, an exception was thrown:

 [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) ) 

How can I (de) serialize Scala class classes?

+6
source share
3 answers

Jackson expects your class to be a JavaBean, which means that it expects the class to have getX () and / or setX () for each property.

Option 1

You can create JavaBean classes in Scala using the BeanProperty annotation.

Example

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

In this case, the value val will mean that only getter is defined. If you want setters for deserialization, you define properties as var.

Option 2

While option 1 will work if you really want to use Jackson, there are wrappers that allow it to deal with Scala classes, such as the FasterXML Scala module , which may be the best approach. I did not use it since I just used the Json library built into the game.

+10
source

Found a solution that works with the Jackson and scala classes.

I used the scala module for 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" ) 

I needed to annotate the fields in the case class using @JsonProperty.

This class of my case is as follows:

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

And this is how I deserialize:

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

Serialization is easier:

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

I want to clarify what I use

 com.fasterxml.jackson.databind.ObjectMapper 

In the question, it seems he uses

 org.codehaus.jackson.map.ObjectMapper 

which will not work with ScalaObjectMapper.

+8
source

Based on Priyank Desai answer, I created a generic function to convert 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) } 

Using:

 case class Person(@JsonProperty("name") Name:String, @JsonProperty("age") Age:Int) val personName = jsonToType[Person](jsonString).name 
+1
source

Source: https://habr.com/ru/post/981850/


All Articles