我使用Jackson测试了Scala案例类的序列化。
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 } """
}
当我运行上面的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)-serial化Scala案例类?
答案 0 :(得分:16)
杰克逊希望你的类成为一个JavaBean,这意味着它希望这个类对每个属性都有一个getX()和/或setX()。
选项1
您可以使用注释BeanProperty在Scala中创建JavaBean类。
实施例
case class Person(
@BeanProperty val name: String,
@BeanProperty val age: Int,
@BeanProperty val hobbies: Option[String]
)
在这种情况下,val将仅表示定义了一个getter。如果需要用于反序列化的setter,则将属性定义为var。
选项2
虽然选项1可行,但如果你真的想使用Jackson,那么有一些包装器可以处理像FasterXML's scala module这样的Scala类,这可能是一种更好的方法。我没有使用它,因为我刚刚使用内置的Json库来玩。
答案 1 :(得分:13)
找到一个适用于jackson和scala案例类的解决方案。
我使用了一个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"
)
我必须使用@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。
答案 2 :(得分:2)
根据Priyank Desai的回答,我创建了一个将json string
转换为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
答案 3 :(得分:0)
我创建了一个通用函数来转换JSON String to Case Class/Object
和Case Class/Object to JSON String
。
请找到我使用泛型here提供的有效且详细的答案。
答案 4 :(得分:0)
使用 upickle 反序列化对象比使用 Jackson 容易得多。举个例子:
var toc = (TableOfEntries)document.GetChildElements(true, ElementType.TableOfEntries).First();
toc.Update();
document.GetPaginator(new PaginatorOptions() { UpdateFields = true });
Jackson 解决方案更加冗长。请参阅此 post 以了解有关此方法的更多信息。
答案 5 :(得分:0)
如果您使用的是 Spring MVC,请使用如下配置:
import java.util.List
@Configuration
@EnableWebMvc
class WebConfig extends WebMvcConfigurer {
override def configureMessageConverters(converters: List[HttpMessageConverter[_]]): Unit = {
val conv = new MappingJackson2HttpMessageConverter();
val mapper = JsonMapper.builder()
.addModule(DefaultScalaModule)
.build();
conv.setObjectMapper(mapper);
converters.add(conv);
}
}
然后序列化/反序列化普通案例类和集合类型将按预期工作。