Giter Site home page Giter Site logo

fasterxml / jackson-module-scala Goto Github PK

View Code? Open in Web Editor NEW
495.0 27.0 142.0 19.78 MB

Add-on module for Jackson (https://github.com/FasterXML/jackson) to support Scala-specific datatypes

License: Apache License 2.0

Scala 99.26% Java 0.74%
scala jackson hacktoberfest cbor json serialization smile xml

jackson-module-scala's Introduction

Build Status Maven Central Tidelift

Overview

Jackson is a fast JSON processor for Java that supports three models: streaming, node, and object mapping (akin to the three independent models SAX/[Stax], DOM and JAXB for XML processing).

The object mapping model is a high-level processing model that allows the user to project JSON data onto a domain-specific data model appropriate for their application, without having to deal with the low-level mechanics of JSON parsing. It is the standard object mapping parser implementaton in Jersey, the reference implementation for JSR-311 (Java API for Restful Web Services).

Scala is a functional programming language for the JVM that supports Java interoperability. Its standard library is quite distinct from Java, and does not fulfill the expectations of Jacksons default mappings. Notably, Scala collections do not derive from java.util.Collection or its subclasses, and Scala properties do not (by default) look like Java Bean properties.

The Scala Module supports serialization and limited deserialization of Scala Case Classes, Sequences, Maps, Tuples, Options, and Enumerations.

Version Support

Jackson-module-scala follows the same release strategy of jackson-databind. Master branch is used for Jackson 3 development. The latest releases are v2.12.x.

Scala 2.11, 2.12 and 2.13 are supported. Scala 2.10 support was dropped in v2.12.0. Java 8 is the minimum supported version now.

Scala 3

Scala 3 support was added in v2.13.0. There are a few differences from Scala 2 support.

  • ScalaObjectMapper is not supported for Scala 3 but ClassTagExtensions is its replacement. (#503)
  • There are still a few tests that work with Scala 2 that fail with Scala 3
  • It is expected that most use cases should work ok with Scala 3
    • Known issues with using jackson-module-scala with Scala 3 are tracked at scala3
    • There has been no testing of using Scala 3 classes with Scala 2 jackson-module-scala or Scala 2 classes with Scala 3 jackson-module-scala

Usage

To use the Scala Module in Jackson, simply register it with the ObjectMapper instance:

// With 2.10 and later
val mapper = JsonMapper.builder()
  .addModule(DefaultScalaModule)
  .build()

// versions before 2.10 (also support for later 2.x but not 3.0)
val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)

DefaultScalaModule is a Scala object that includes support for all currently supported Scala data types. If only partial support is desired, the component traits can be included individually:

val module = new OptionModule with TupleModule {}
val mapper = JsonMapper.builder()
  .addModule(module)
  .build()

One Scala module that isn't part of DefaultScalaModule is ScalaObjectDeserializerModule. This module is used to ensure that deserialization to a Scala object does not create a new instance of the object. This latter module is not yet included in DefaultScalaModule but will be included in v2.16.0. It is already included in v3.0.0, which is still under development.

DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES

It is recommended that Scala users enable DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES. This feature means that when you deserialize JSON and bind to a Scala/Java class and a required field is missing (or null), then the deserialization call will fail with a com.fasterxml.jackson.databind.exc.MismatchedInputException. By default, the deserialization call will succeed and a null value will be set for the field.

val mapper = JsonMapper.builder()
  .addModule(DefaultScalaModule)
  .enable(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES)
  .build()

ClassTagExtensions

You can also mixin ClassTagExtensions to get rich wrappers that automatically convert scala ClassTags directly into TypeReferences for Jackson to use:

val mapper = JsonMapper.builder().addModule(DefaultScalaModule).build() :: ClassTagExtensions
// or using old style
//val mapper = new ObjectMapper() with ClassTagExtensions
//mapper.registerModule(DefaultScalaModule)
val myMap = mapper.readValue[Map[String, Tuple2[Int,Int]]](src)

ClassTagExtensions is a replacement for ScalaObjectMapper, which was recently deprecated because it relies on Manifests and they are not supported in Scala 3.

This is the equivalent of

val mapper = JsonMapper.builder().addModule(DefaultScalaModule).build()
val myMap = mapper.readValue(src, new TypeReference[Map[String,Tuple2[Int,Int]]]{})

Consult the Scaladoc for further details.

Sbt

To import in sbt:

libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.17.1"

Java/Kotlin users

DefaultScalaModule is a Scala Object and to access it when you are not compiling with Scala compiler, you will need to use DefaultScalaModule$.MODULE$ instead.

import com.fasterxml.jackson.module.scala.DefaultScalaModule$;

ObjectMapper mapper = JsonMapper.builder().addModule(DefaultScalaModule$.MODULE$).build();

Building

The master branch often depends on SNAPSHOT versions of the core Jackson projects, which are published to the Sonatype OSS Repository. To make these dependencies available, create a file called sonatype.sbt in the same directory as build.sbt with the following content. The project .gitignore file intentionally prevents this file from being checked in.

resolvers ++= Resolver.sonatypeOssRepos("snapshots")

Download, docs

Check out Wiki. API Scaladocs can be found on the project site but they are not really well suited to end users, as most classes are implementation details of the module.

Related Projects

Contributing

The main mechanisms for contribution are:

  • Reporting issues, suggesting improved functionality on Github issue tracker
  • Participating in discussions on mailing lists, Gitter (see Jackson portal for details)
  • Submitting Pull Requests (PRs) to fix issues, improve functionality.

Support

Community support

Jackson components are supported by the Jackson community through mailing lists, Gitter forum, Github issues. See Participation, Contributing for full details.

Enterprise support

Available as part of the Tidelift Subscription.

The maintainers of jackson-module-scala and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. Learn more.

Core Development Team

Currently active core developers (ones who can review, accept and merge Pull Requests) are:

  • PJ Fanning (@pjfanning)

If you have questions on issues, implementation strategies, you may refer to core developers (and this is recommended if you are in doubt!), but keep in mind that these are voluntary positions: everyone is doing this because they want to, not because they are paid or contractually obligated to. This also means that time availability changes over time so getting answers may take time.

In addition, other Jackson developers with similar access (but less active) include:

  • Christopher Currie (@christophercurrie) -- original author of Scala module
  • Morten Kjetland (@mbknor)
  • Nate Bauernfeind (@nbauernfeind)
  • Tatu Saloranta (@cowtowncoder) -- main author of core Jackson components

Acknowledgements

Developed with IntelliJ IDEA

jackson-module-scala's People

Contributors

arnauld avatar brharrington avatar christophercurrie avatar cowtowncoder avatar daveclay avatar devth avatar dieu avatar dpratt avatar eugeniyk avatar helfper avatar ijuma avatar jroper avatar kscaldef avatar mbknor avatar nbauernfeind avatar nick-benoit14 avatar nicktelford avatar noam-almog avatar pjfanning avatar prb avatar relaxkeren avatar rintcius avatar scarytom avatar sethtisue avatar staffanstockholm avatar sullis avatar timmoore avatar umcodemonkey avatar xuwei-k avatar xylo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jackson-module-scala's Issues

mapper serialization inclusion ignored ?

Hello,
I'm trying to serialize a case class without the null values, but i can't get it work.
I'm trying the following :

    case class NotNull(t: String) {}
    val t = NotNull(null)
    val mapper = new ObjectMapper()
    mapper.setSerializationInclusion(Include.NON_EMPTY);
    mapper.registerModule(DefaultScalaModule)
    val test = mapper.writeValueAsString(t)
    println(test)

output: {"t":null}

The annotation

@JsonInclude(Include.NON_NULL)

doesn't work either.
Is it the correct way to avoid null value during serialization ?
Thanks

PS: i just saw #32 , which seems to be the same problem, fixed in 2.0.3, i'm using 2.1.0 and I'm having the same problem

Default serialization of Scala getters

Even if @JsonAutoDetect.getterVisibility is set to PUBLIC_ONLY, Scala-style getters are not autodetected unless explicitly specify @(JsonProperty @getter) on them. Can it be done so to behave like in Java?

Support deserialization of non-case classes

I have a situation like this:

abstract class Event {
    var property1 = _
    var property2 = _
    ...
    var property10 = _
}

class SomeEvent extends Event {
    var propertyA = _
    var propertyB = _
    var propertyC = _
}

class SomeOtherEvent extends Event {
    var propertyX = _
    var propertyY = _
    var propertyZ = _
}

Correct me if I'm wrong, but it seems to me like jackson-module-scala doesn't support deserialization of classes other than case classes?

Now, while these technically are case classes, the problem with that is that I would have to repeat property1-property10 (and more, if hierarchy is deeper) in every case class, which gets unmaintainable very fast.

unresolved dependencies

Pardon my ignorance if I am doing something stupid, but after cloning the master and typing "sbt compile", I get these warnings which results in errors.

[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: com.fasterxml.jackson.core#jackson-core;2.2.0-SNAPSHOT: not found
[warn] :: com.fasterxml.jackson.core#jackson-databind;2.2.0-SNAPSHOT: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::

Am I doing something wrong? Thanks.

Nested List and Map in Scala module

I was suggested to raise this as an issue.

I wish to convert lists of json objects, which in themselves may contain Json objects, or Lists of Json objects and would like the results to be Scala Maps or Lists as appropriate, however, I can only get the top level object to convert to a Map or a List. Is there a simple way to do this?

For example in REPL

objectMapper.readValue("{"test":"113123","myList":[{"test2":"321323"},{"test3":"11122"}]}", classOf[Map[String,Any]])
Will return

res: Map[String,Any] = Map(test -> 113123, myList -> [{test2=321323}, {test3=11122}])
Where I would like

res: Map[String,Any] = Map(test -> 113123, myList -> List(Map(test2 -> 321323), Map(test3 -> 111222)))

serializing unicode property names skips the name

When trying to serialize a case class with a unicode property name it just gets skipped.

case class UnicodeNameCaseClass(`winning-id`: Int, name: String)

class CaseClassSerializerTest extends SerializerTest with FlatSpec with ShouldMatchers {
  // ... other content elided.
  it should "serialize a case class with unicode name properties" in {
    serialize(UnicodeNameCaseClass(23, "the name of this")) should (
      equal("""{"winning-id":23,"name":"the name of this"}""")
    )
  }
}

The test case fails with:

An ObjectMapper with the CaseClassModule should serialize a case class with unicode name
properties(com.fasterxml.jackson.module.scala.ser.CaseClassSerializerTest): 
"{"name":"the name of this"}" did not equal "{"winning-id":23,"name":"the name of this"}"

java.lang.NoSuchFieldException: MODULE$ printout

In Scala 2.10, whenever I try to serialize a Wrapper instance (eg. JMapWrapper), that error gets printed twice. It seems benign in my situation, so I'd rather not see it.

This will cause it:

val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)
val v = mapper.readValue[AnyRef]("""{"a":1,"b":"c"}""", classOf[AnyRef])
mapper.writeValue(new StringWriter, v)

The problem stems from the wrapper case classes nested inside the convert.Wrappers trait. Unfortunately, I don't know enough about the Serializer internals to give a possible solution.

Maintain ordering when serializing a ListMap or LinkedHashMap

I'm trying to output a sorted map while maintaining sort order.

On the repl, I verified sort with:

scala> val m = ListMap(Map((5, 1), (2, 33), (7, 22), (8, 333)).toList.sortBy(-_._2):_*)
m: scala.collection.immutable.ListMap[Int,Int] = Map(8 -> 333, 2 -> 33, 7 -> 22, 5 -> 1)

When I serialize this, I get:

{
2: 33,
5: 1,
7: 22,
8: 333
}

Same thing when using a LinkedHashMap.

serialization of static inner Java class failed

Java scope:

public class Field {
public static enum Type {...}
...
}

Scala scope:

case class Message(fieldType: Field.Type)

Serialization of Message.fieldType fails.

The current workaround is taking the enum to the outer scope. Please allow serialization of inner classes as well.

"Conflicting getter definitions" with @BeanProperty when using ScalaClassIntrospectorModule

We have a mixed Java/Scala project where many of our domain objects are written in Scala. Because we use Hibernate for persistence, we have to annotate our properties with @BeanProperty. Unfortunately, when we use ScalaClassIntrospectorModule, Jackson picks up both the Scala-style getter and the Java Beans-style one.

Say we have a domain class like this:

package com.example
import scala.beans.BeanProperty

class Foo {
  @BeanProperty var id: Int = _
  @BeanProperty var bar: String = _
}

If we try to serialize a list of Foos with the ScalaClassIntrospectorModule added to our ObjectMapper, we get this:

com.fasterxml.jackson.databind.JsonMappingException: Conflicting getter definitions for property "id": com.example.Foo#getId(0 params) vs com.example.Foo#id(0 params) (through reference chain: java.util.ArrayList[0])
    at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:838)
    at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:387)
    at com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap.findAndAddSerializer(PropertySerializerMap.java:38)
    at com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase._findAndAddDynamic(AsArraySerializerBase.java:270)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:96)
    at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21)
    at com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:186)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:118)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:1819)

Fortunately, because of your mixin design, we can work around this by just excluding the ScalaClassIntrospectorModule and rely on @BeanProperty as we are forced to elsewhere.

But is there an easy way to make this configurable? Could the Scala introspector detect the presence of bean-style accessors and defer to them? (Having the Scala accessors take precedence over the bean-style ones would be fine, too---I just imagine that the other way would be easier.) Is there something I can configure in Jackson that I am missing?

Thanks!

Serious issues w/ deserialization

I'm including a Scala REPL transcript below to illustrate some of the oddities that I'm seeing, but here's the gist: the order that fields in a case class are defined appears to effect deserialization and there appear to be issues surrounding Tuples. Another issue that I've seen reported elsewhere is that nulls aren't being handled properly -- even if you configure your mapper to omit them, they're still showing up.

[edited to put the REPL log in a code block. /cgc]

scala> import com.fasterxml.jackson.databind.ObjectMapper
scala> import com.fasterxml.jackson.annotation.JsonInclude.Include.{NON_NULL, NON_EMPTY}
scala> val mapper = new ObjectMapper()
scala> mapper.registerModule(com.fasterxml.jackson.module.scala.DefaultScalaModule)

scala> case class Foo(
     |   id: Long,
     |   guid: String,
     |   score: Double,
     |   bestFeatures: Option[List[(String, Double)]],
     |   title: String,
     |   rawScores: Option[List[((String, String, String, String), Double, Double)]]
     | )
scala> val foo = Foo(10L, "GUID", 10.0, Some(List(("foo", 1.0), ("bar", 10.0), ("baz", 100.0))), "TITLE", None)
scala> val fooJson = mapper.writeValueAsString(foo)
scala> mapper.readValue[Foo](fooJson, classOf[Foo])

// Notice the result:
// res1: Foo = Foo(10,GUID,10.0,Some(List((foo,1.0))),null,None)
// We're getting a null title even though it was non-null in the instance we serialized.
// We're also missing some of the bestFeatures. That's no good.

scala> case class Foo(
     |   id: Long,
     |   guid: String,
     |   score: Double,
     |   bestFeatures: Option[List[String]], // notice the slight simplification here!
     |   title: String,
     |   rawScores: Option[List[((String, String, String, String), Double, Double)]]
     | )
scala> val foo = Foo(10L, "GUID", 10.0, Some(List("foo", "bar", "baz")), "TITLE", None)
scala> val fooJson = mapper.writeValueAsString(foo)
scala> mapper.readValue[Foo](fooJson, classOf[Foo])

// Notice the result now:
// res2: Foo = Foo(10,GUID,10.0,Some(List(foo, bar, baz)),TITLE,None)
// No missing bestFeatures! What if we change the order of the fields, but use the initial bestFeatures type signature?

scala> case class Foo(
     |   id: Long,
     |   guid: String,
     |   score: Double,
     |   title: String,
     |   bestFeatures: Option[List[(String, Double)]],
     |   rawScores: Option[List[((String, String, String, String), Double, Double)]]
     | )
defined class Foo

scala> val foo = Foo(10L, "GUID", 10.0, "TITLE", Some(List(("foo", 1.0), ("bar", 10.0), ("baz", 100.0))), None)
foo: Foo = Foo(10,GUID,10.0,TITLE,Some(List((foo,1.0), (bar,10.0), (baz,100.0))),None)

scala> val fooJson = mapper.writeValueAsString(foo)
fooJson: java.lang.String = {"id":10,"guid":"GUID","score":10.0,"title":"TITLE","bestFeatures":[["foo",1.0],["bar",10.0],["baz",100.0]],"rawScores":null}

scala> mapper.readValue[Foo](fooJson, classOf[Foo])
res3: Foo = Foo(10,GUID,10.0,TITLE,Some(List((foo,1.0))),None)

Re-ordering the fields also seems to solve the issue of the mysterious missing title, but it doesn't help us with the missing pairs in the bestFeatures field.

Any ideas?

Confirm Java 7 support

In issue #58, an error was reported when trying to compile a simple application using Java 7.

With the following simple code:

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

object TestJSON extends App {
  val mapper = new ObjectMapper()
  mapper.registerModule(DefaultScalaModule)
}

I get the following error:

Exception in thread "main" java.util.NoSuchElementException: key not found: groupId
  at scala.collection.MapLike$class.default(MapLike.scala:228)
  at scala.collection.AbstractMap.default(Map.scala:58)
  at scala.collection.MapLike$class.apply(MapLike.scala:141)
  at scala.collection.AbstractMap.apply(Map.scala:58)
  at com.fasterxml.jackson.module.scala.JacksonModule$.version$lzycompute(JacksonModule.scala:27)
  at com.fasterxml.jackson.module.scala.JacksonModule$.version(JacksonModule.scala:26)
  at com.fasterxml.jackson.module.scala.JacksonModule$class.version(JacksonModule.scala:45)
  at com.fasterxml.jackson.module.scala.DefaultScalaModule.version(DefaultScalaModule.scala:18)
  at com.fasterxml.jackson.databind.ObjectMapper.registerModule(ObjectMapper.java:517)
  at TestJSON$delayedInit$body.apply(TestJSON.scala:24)
  at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
  at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
  at scala.App$$anonfun$main$1.apply(App.scala:71)
  at scala.App$$anonfun$main$1.apply(App.scala:71)
  at scala.collection.immutable.List.foreach(List.scala:309)
  at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
  at scala.App$class.main(App.scala:71)
  at TestJSON$.main(TestJSON.scala:16)
  at TestJSON.main(TestJSON.scala)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:601)
  at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Scala 2.8.1

Hello,

Will this build with Scala 2.8.1?

Thanks,
Robert

JsonMappingException ("no propery name annotation") when unmarshalling inner case class

In the following code, parsing the non-inner case classes with Foo works, but parsing the inner case classes with Bar fails.

val om = new com.fasterxml.jackson.databind.ObjectMapper
om.registerModule(com.fasterxml.jackson.module.scala.DefaultScalaModule)

case class FooTuple(s:String,i:Int)
class FooParse {
  def parse(json:String) = om.readValue(json,classOf[FooTuple])
}

new FooParse().parse("""{"s":"Hello","i":42}""")

class BarParse {
  case class BarTuple(s:String,i:Int)

  def parse(json:String) = om.readValue(json, classOf[BarTuple])
}

new BarParse().parse("""{"s":"Hello","i":42}""")

Foo parse goes like this:

scala> new FooParse().parse("""{"s":"Hello","i":42}""")
res16: FooTuple = FooTuple(Hello,42)

Bar parse like this:

scala> new BarParse().parse("""{"s":"Hello","i":42}""")
com.fasterxml.jackson.databind.JsonMappingException: Argument #0 of constructor [constructor for BarParse$BarTuple, annotations: [null]] has no property name annotation; must have name when multiple-paramater constructor annotated as Creator
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:252)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:227)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:126)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:331)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:2679)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2573)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1810)
    at BarParse.parse(<console>:20)
    at .<init>(<console>:19)
    at .<clinit>(<console>)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
    at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
    at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
    at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
    at java.lang.Thread.run(Thread.java:680)
Caused by: java.lang.IllegalArgumentException: Argument #0 of constructor [constructor for BarParse$BarTuple, annotations: [null]] has no property name annotation; must have name when multiple-paramater constructor annotated as Creator
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._addDeserializerConstructors(BasicDeserializerFactory.java:450)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:352)
    at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:293)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:260)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:168)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:363)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:247)
    ... 21 more

JsonTypeInfo is not picked up for nested case classes when serializing

@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="class")
case class A(s: String)
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="class")
case class B(a: A, i: Int)

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


val o = B(A("a"), 1)
val s = m.writeValueAsString(o)

result:

"""{"class":"my.Jackson2Test$B","a":{"s":"a"},"i":1}"""

expected:

"""{"class":"my.Jackson2Test$B","a":{"class":"my.Jackson2Test$A","s":"a"},"i":1}"""

@JsonProperty is ignored for case class

It looks like the mapper can't find the property if the class parameter name is not the same as the field name within the json (considering that we are explicitly providing the @JsonProperty meta annotation).

Here http://jira.codehaus.org/browse/JACKSON-304 a similar issue is described. But, the comment is one year old...

Not sure if this is a known limitation. My guess is that it should be possible to get the value of the @JsonProperty annotation.

To reproduce the issue:

import org.specs2.Specification
import org.codehaus.jackson.map.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import org.codehaus.jackson.annotate.{JsonCreator, JsonIgnoreProperties, JsonProperty}

@JsonIgnoreProperties(ignoreUnknown = true)
case class MyCaseClass @JsonCreator()(@JsonProperty("some_property") someProperty: String)

class JsonPropertyTest extends Specification {

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


  def is =
    "This is a specification that describes a possible bug for the DefaultScalaModule module" ^
      p ^
      "The DefaultScalaModule should" ^
      "Deserialize the someProperty value from a json containing the some_property field given that we" +
        "provide @JsonProperty(\"some_property\")" ! e1

  end

  def e1 = {
    val o = mapper.readValue("{\"some_property\": \"some value\"}", classOf[MyCaseClass])
    o.someProperty must equalTo("some value")
  }

}

Support private fields in scala classes when default values are present

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.annotation.{JsonProperty, JsonCreator}

case class Person @JsonCreator() (@JsonProperty("firstName") private val firstName: String = "Jelmer", @JsonProperty("lastName") lastName: String = "Kuperus")

object Main {
def main(args: Array[String]) {
val mapper = new ObjectMapper().registerModule(DefaultScalaModule)
val person = mapper.readValue("""{"firstName":"jelmer", "lastName":"kuperus"}""", classOf[Person])
println( mapper.writeValueAsString(person) )
}
}

Returns :

{"lastName":"kuperus"}

where it should have returned :

{"firstName":"jelmer", "lastName":"kuperus"}

CaseClassModule and serializing List

Test case:

    val mapper = new ObjectMapper()
    mapper.registerModule(DefaultScalaModule)
    mapper.writeValueAsString(List("test"))

Expected behaviour -- create a JSON string.
Actual behaviour -- exception

scala.MatchError: java.lang.Object with scala.collection.TraversableView[+A >: scala.Nothing <: scala.Any, +Repr >: scala.Nothing <: scala.Any] (of class org.scalastuff.scalabeans.sig.ClassDeclExtractor$$anonfun$13$$anon$14)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler.resolveScalaType(ScalaTypeCompiler.scala:166)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$3.apply(ScalaTypeCompiler.scala:146)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$3.apply(ScalaTypeCompiler.scala:145)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)
    at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:60)
    at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:44)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:194)
    at scala.collection.mutable.ArrayBuffer.map(ArrayBuffer.scala:44)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler.compile(ScalaTypeCompiler.scala:145)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1$$anonfun$apply$2.apply(ScalaTypeCompiler.scala:51)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1$$anonfun$apply$2.apply(ScalaTypeCompiler.scala:48)
    at scala.Option$WithFilter.map(Option.scala:174)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1.apply(ScalaTypeCompiler.scala:48)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1.apply(ScalaTypeCompiler.scala:47)
    at scala.Option.flatMap(Option.scala:146)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$.classInfoOf(ScalaTypeCompiler.scala:47)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.getLinearizationOf$1(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:76)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:75)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.linearization(ScalaTypeCompiler.scala:75)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at scala.Option.map(Option.scala:133)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.getLinearizationOf$1(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:76)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:75)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.linearization(ScalaTypeCompiler.scala:75)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at scala.Option.map(Option.scala:133)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.getLinearizationOf$1(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:76)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:75)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.linearization(ScalaTypeCompiler.scala:75)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at scala.Option.map(Option.scala:133)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.getLinearizationOf$1(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:76)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:75)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.linearization(ScalaTypeCompiler.scala:75)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at scala.Option.map(Option.scala:133)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.getLinearizationOf$1(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:76)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:75)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.linearization(ScalaTypeCompiler.scala:75)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at scala.Option.map(Option.scala:133)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.getLinearizationOf$1(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:76)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$linearization$1.apply(ScalaTypeCompiler.scala:75)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.linearization(ScalaTypeCompiler.scala:75)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo$$anonfun$getLinearizationOf$1$1.apply(ScalaTypeCompiler.scala:70)
    at scala.Option.map(Option.scala:133)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.getLinearizationOf$1(ScalaTypeCompiler.scala:70)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.linearization(ScalaTypeCompiler.scala:73)
    at org.scalastuff.scalabeans.sig.ScalaTypeCompiler$ClassInfo.findPropertyType(ScalaTypeCompiler.scala:95)
    at org.scalastuff.scalabeans.PropertyDescriptor$$anonfun$4$$anonfun$apply$2.apply(PropertyDescriptor.scala:186)
    at org.scalastuff.scalabeans.PropertyDescriptor$$anonfun$4$$anonfun$apply$2.apply(PropertyDescriptor.scala:185)
    at scala.Option.flatMap(Option.scala:146)
    at org.scalastuff.scalabeans.PropertyDescriptor$$anonfun$4.apply(PropertyDescriptor.scala:185)
    at org.scalastuff.scalabeans.PropertyDescriptor$$anonfun$4.apply(PropertyDescriptor.scala:184)
    at scala.Option.flatMap(Option.scala:146)
    at org.scalastuff.scalabeans.PropertyDescriptor$.apply(PropertyDescriptor.scala:184)
    at org.scalastuff.scalabeans.BeanIntrospector$.createPropertyDescriptor$1(BeanIntrospector.scala:76)
    at org.scalastuff.scalabeans.BeanIntrospector$$anonfun$5$$anonfun$apply$5.apply(BeanIntrospector.scala:111)
    at org.scalastuff.scalabeans.BeanIntrospector$$anonfun$5$$anonfun$apply$5.apply(BeanIntrospector.scala:102)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194)
    at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34)
    at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:38)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:194)
    at scala.collection.mutable.ArrayOps.map(ArrayOps.scala:38)
    at org.scalastuff.scalabeans.BeanIntrospector$$anonfun$5.apply(BeanIntrospector.scala:102)
    at org.scalastuff.scalabeans.BeanIntrospector$$anonfun$5.apply(BeanIntrospector.scala:101)
    at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:200)
    at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:200)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:200)
    at scala.collection.immutable.List.flatMap(List.scala:45)
    at org.scalastuff.scalabeans.BeanIntrospector$.apply(BeanIntrospector.scala:101)
    at org.scalastuff.scalabeans.Preamble$.descriptorOf(Preamble.scala:31)
    at com.fasterxml.jackson.module.scala.deser.CaseClassAnnotationIntrospector$.findConstructorParamName(CaseClassDeserializerModule.scala:49)
    at com.fasterxml.jackson.module.scala.deser.CaseClassAnnotationIntrospector$.findPropertyNameForParam(CaseClassDeserializerModule.scala:39)
    at org.codehaus.jackson.map.AnnotationIntrospector$Pair.findPropertyNameForParam(AnnotationIntrospector.java:1470)
    at org.codehaus.jackson.map.introspect.POJOPropertiesCollector._addCreators(POJOPropertiesCollector.java:366)
    at org.codehaus.jackson.map.introspect.POJOPropertiesCollector.collect(POJOPropertiesCollector.java:203)
    at org.codehaus.jackson.map.introspect.BasicClassIntrospector.collectProperties(BasicClassIntrospector.java:160)
    at org.codehaus.jackson.map.introspect.BasicClassIntrospector.forSerialization(BasicClassIntrospector.java:96)
    at org.codehaus.jackson.map.introspect.BasicClassIntrospector.forSerialization(BasicClassIntrospector.java:16)
    at org.codehaus.jackson.map.SerializationConfig.introspect(SerializationConfig.java:974)
    at org.codehaus.jackson.map.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:251)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._createUntypedSerializer(StdSerializerProvider.java:782)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._createAndCacheUntypedSerializer(StdSerializerProvider.java:735)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.findValueSerializer(StdSerializerProvider.java:344)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.findTypedValueSerializer(StdSerializerProvider.java:420)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:601)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:256)
    at org.codehaus.jackson.map.ObjectMapper._configAndWriteValue(ObjectMapper.java:2566)
    at org.codehaus.jackson.map.ObjectMapper.writeValueAsString(ObjectMapper.java:2088)
    at com.qatarlyst.contract.service.OptionSerializationTest$$anonfun$1.apply$mcV$sp(OptionSerializationTest.scala:45)
    at com.qatarlyst.contract.service.OptionSerializationTest$$anonfun$1.apply(OptionSerializationTest.scala:41)
    at com.qatarlyst.contract.service.OptionSerializationTest$$anonfun$1.apply(OptionSerializationTest.scala:41)
    at org.scalatest.FunSuite$$anon$1.apply(FunSuite.scala:1265)
    at org.scalatest.Suite$class.withFixture(Suite.scala:1968)
    at com.qatarlyst.contract.service.OptionSerializationTest.withFixture(OptionSerializationTest.scala:38)
    at org.scalatest.FunSuite$class.invokeWithFixture$1(FunSuite.scala:1262)
    at org.scalatest.FunSuite$$anonfun$runTest$1.apply(FunSuite.scala:1271)
    at org.scalatest.FunSuite$$anonfun$runTest$1.apply(FunSuite.scala:1271)
    at org.scalatest.SuperEngine.runTestImpl(Engine.scala:168)
    at org.scalatest.FunSuite$class.runTest(FunSuite.scala:1271)
    at com.qatarlyst.contract.service.OptionSerializationTest.runTest(OptionSerializationTest.scala:38)
    at org.scalatest.FunSuite$$anonfun$runTests$1.apply(FunSuite.scala:1304)
    at org.scalatest.FunSuite$$anonfun$runTests$1.apply(FunSuite.scala:1304)
    at org.scalatest.SuperEngine$$anonfun$org$scalatest$SuperEngine$$runTestsInBranch$1.apply(Engine.scala:226)
    at org.scalatest.SuperEngine$$anonfun$org$scalatest$SuperEngine$$runTestsInBranch$1.apply(Engine.scala:215)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:215)
    at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:282)
    at org.scalatest.FunSuite$class.runTests(FunSuite.scala:1304)
    at com.qatarlyst.contract.service.OptionSerializationTest.runTests(OptionSerializationTest.scala:38)
    at org.scalatest.Suite$class.run(Suite.scala:2286)
    at com.qatarlyst.contract.service.OptionSerializationTest.org$scalatest$FunSuite$$super$run(OptionSerializationTest.scala:38)
    at org.scalatest.FunSuite$$anonfun$run$1.apply(FunSuite.scala:1310)
    at org.scalatest.FunSuite$$anonfun$run$1.apply(FunSuite.scala:1310)
    at org.scalatest.SuperEngine.runImpl(Engine.scala:318)
    at org.scalatest.FunSuite$class.run(FunSuite.scala:1310)
    at com.qatarlyst.contract.service.OptionSerializationTest.run(OptionSerializationTest.scala:38)
    at org.scalatest.junit.JUnitRunner.run(JUnitRunner.scala:94)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Environment

Scala 2.9.1, jackson-scala-module 1.9.1 or 1.9.2-SNAPSHOT

Workaround

Special-casing 'List' similarly to 'Option' and 'Tuple' in CaseClassDeserializerModule:

diff --git a/src/main/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerModule.scala b/src/main/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerModule.scala
index 455598a..904a767 100644
--- a/src/main/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerModule.scala
+++ b/src/main/scala/com/fasterxml/jackson/module/scala/deser/CaseClassDeserializerModule.scala
@@ -13,6 +13,7 @@ private object CaseClassAnnotationIntrospector extends NopAnnotationIntrospector
     if (!PRODUCT.isAssignableFrom(cls)) false
     else if (OPTION.isAssignableFrom(cls)) false
     else if (cls.getName.startsWith("scala.Tuple")) false
+    else if (classOf[List[_]].isAssignableFrom(cls)) false
     else true
   }

Case Classes with Option[Long] parameters don't deserialize properly

It seems that for small numbers, an Option[Long] in a case class actually gets deserialized with a runtime type of int. This can then manifest in a couple ways. Maps using these values as keys may not behave as expected, and conversions to Java Longs will throw a ClassCastException:

[info]   java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
[info]   at scala.runtime.BoxesRunTime.unboxToLong(Unknown Source)

This only seems to affect case classes. Option[Long] by itself seems to behave correctly.

Using from java

Is it possible to configure this module from java? I tried

this.jacksonObjectMapper.registerModule(DefaultScalaModule);

But get error:

DefaultScalaModule cannot be resolved to a variable

The import statement itself doesn't complain.

can't deserialize byte array

Hello,
deserialization doesn't work with an Array[Byte]

case class TestSer(foo: String, bar: String, timestampingContent: Array[Byte])

...
myMapper.readValue( """{"foo":"foo","bar":"bar","timestampingContent": null}""", classOf[TestSer])

com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.avricot.avrilog.json.TestSer]: can not instantiate from JSON object (need to add/enable type information?)
at [Source: java.io.StringReader@40e7fd03; line: 1, column: 2]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObjectUsingNonDefault(BeanDeserializer.java:400)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:289)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2796)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1942)
at com.avricot.avrilog.json.JsonMapperTest.jsonTestMapp(JsonMapperTest.scala:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

How to deserialize a json file to Map[String,String] in scala?

It works fine for me in java where as in scala i am getting the below exception. Please let me know how can i resolve this?

val jsonContent ="""{"test":"113123","myList":{"test2":"321323"}}"""
val mapData = mapper.readValue(jsonContent, classOf[Map[String,String]])

Error:

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of scala.collection.immutable.Map, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
at [Source: java.io.StringReader@603b1d04; line: 1, column: 1]

Cannot deserialize Option[Int] when JodaModule is registered (ClassCastException: org.joda.time.Period)

I'm having trouble deserializing to a bean that contains an Option[Int]. It seems that when the JodaModule is registered, the deserialization puts a Some[JodaPeriod] in as the value of the Option[Int] (!) which then causes a ClassCastException when I try to access it.

The following exception is thrown by the mapper2.readValue call in the sample code.

Exception in thread "main" java.lang.ClassCastException: org.joda.time.Period cannot be cast to java.lang.Integer
    at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
    at JodaTimeTest$.main(JodaTimeTest.scala:15)
    at JodaTimeTest.main(JodaTimeTest.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.joda.JodaModule
import com.fasterxml.jackson.module.scala.{DefaultScalaModule, JacksonModule}

object JodaTimeTest {

  def main(args: Array[String]): Unit = {
    val mapper1 = new ObjectMapper()
    mapper1.registerModule(DefaultScalaModule)
    val int1 =  mapper1.readValue("""{"x":123}""",classOf[OptionalInt]).x.get

    val mapper2 = new ObjectMapper()
    mapper2.registerModule(DefaultScalaModule)
    mapper2.registerModule(new JodaModule())
    val int2 =  mapper2.readValue("""{"x":123}""",classOf[OptionalInt]).x.get
  }
}

case class OptionalInt(x: Option[Int])

Support Scala collection classes

Note: re-creation of [http://jira.codehaus.org/browse/JACKSON-211] -- see that issue for more details.


(as suggested by Paul S on Jersey list)

It would be nice if Scala Lists (collections, Maps) were recognized and handled by Jackson.

Since Scala does not implement JDK collections classes, Jackson currently does not recognize these as containers.
But it might be possible to change this: especially since mechanism for adding dynamic optional pieces already exists.
Alternative way would be to create separate jackson-scala jar; it all depends on how much code is involved and whether changes can be modularized.

First thing would be to write bit of code to see what Scala thingies look like from JVM perspective and go from there.

Support Scala case classes

(copied from [http://jira.codehaus.org/browse/JACKSON-304] -- see details)

(by James Strachan, Greg Zoller)

It doesn't feel very dry doing Scala with Jackson...

@BeanInfo class Position {
@BeanProperty
var x: Double = _
@BeanProperty
var y: Double = _

override def toString = "Position(" + x + "," + y + ")"
}

when it would be much nicer to be able to do

case class Position(x: Double, y: Double)

The main issue is that this class is immutable and that (ii) there are no fields/setters to call when deserializing, just a constructor.

Though when serializing the fields can be used.

Unfortunately Scala doesn't yet seem to support an easy way to iterate through the product field names & constructor argument names AFAIK so until Scala offers more reflection help this might be tricky...

JsonInclude.Include.NON_NULL is ignored for Option.empty in a map

// the source code

val mapper = new ObjectMapper()
mapper.registerModule(DefaultScalaModule)
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
mapper.registerModule(DefaultScalaModule)

val testValue = Map("nothing" -> Option.empty[String])
mapper.writeValueAsString(testValue) // expect {}, but {"nothing":null} is returned instead

case class field names are empty in generate JSON

Using 2.0.2 of the module.
the case class

case class Message(topic:String,data:Map[String,String],arguments:Option[Seq[AnyRef]],callback:Option[String])

produces an invalid JSON string. The field values are generated fine but the field names are always empty. as in

{"":"test","":{},"":["d"],"":"callback"}

expected output:

{"topic":"test","data":{},"arguments":["d"],"callback":"callback"}

There also seems to be some unnecessary utf8 characters after the JSON as in:
{"topic":"test","data":{},"arguments":["d"],"callback":"callback"}\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000

I think that results in an extra 8 bytes...

For the moment I've worked around it by changing from a case class and making the params fields as in

class Message(
               t: String,
               d: Map[String, Any],
               arg: Option[Seq[AnyRef]] = None,
               cb: Option[String] = None
               ) {
  def this() = this("", Map(), None, None)

   //have to use var
  @JsonProperty var topic = t
  @JsonProperty var data = d
  @JsonProperty var arguments = arg
  @JsonProperty var callback = cb
}

This serialize / deserializes fine and I haven't seen an instance where it puts the excess utf8 on the end...

Wrong type when deserializing List[UUID]

When running the code below, the deserialized data is a list of String not a list of UUID.
Either this is a bug, or I'm doing it wrongly.

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

val data: Seq[UUID] = List(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID())

val json = mapper.writeValueAsString(data)
val deSerObj = mapper.readValue(json, classOf[List[UUID]])
assert(deSerObj(0).equals(data(0)))

Case classes with option types don't follow serialization configuration

I'm trying to keep jackson from writing the None Option value as "null". I believe the scala module is not honoring the serialization conf. In the following test case, the first two tests fail because they are returning {"foo":null} despite the mapper being configured to include only non-null values. The third is not a case class and passes with the expected response of "{}":

class ScalaOptionTest extends FlatSpec with ShouldMatchers {
  it should "not write a null value" in {
    val o = CaseClass1(None)
    getMapper.writeValueAsString(o) should be ("{}")
  }

  it should "not also write a null value" in {
    val o = CaseClass2(None)
    getMapper.writeValueAsString(o) should be ("{}")
  }

  it should "not still write a null value" in {
    val o = new TestObject3
    getMapper.writeValueAsString(o) should be ("{}")
  }

  def getMapper = {
    val mapper = new ObjectMapper()
    mapper.registerModule(new DefaultScalaModule())
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
    mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
    mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
  }
}

case class CaseClass1(@JsonInclude(JsonInclude.Include.NON_NULL) foo: Option[String])

case class CaseClass2(foo: Option[String])

class TestObject3() {
  var foo: Option[String] = None
}

which returns:

Tests in error: 
  should not write a null value(ScalaOptionTest): "{"foo":null}" was not equal to "{}"
  should not also write a null value(ScalaOptionTest): "{"foo":null}" was not equal to "{}"

CaseClassModule is incompatible with Options.

def testJsonWithOption() {
  val mapper = new ObjectMapper()
  mapper.registerModule(new JacksonModule
    with CaseClassModule
    with EnumerationModule
    with SeqModule
    with IterableModule
    with TupleModule
    with MapModule
    with OptionModule
  )

  val writer = new StringWriter()
  mapper.writeValue(writer, Option(42))
  println(writer.toString)
}

That throws an exception. It works fine if I remove the CaseClassModule from the mixin. Do you know how I can fix this? Deserialization works fine. I really want a nested Option in my case class.

In fact the CaseClassModule by itself does not work properly with Options.

Collection Serializers do not support `JsonSerialize.Inclusion.NON_EMPTY`

From Todd Vierling:

It looks like jackson 1.9.0 still doesn't have a way to hook into this functionality, which is part of PropertyBuilder, without subclassing BeanSerializerFactory. I did create an implementation of that here, which supports anything that extends either Product (such as Option or any case class) or TraversableLike (all collection classes except TraversableOnce):

https://github.com/tvierling/jackson-module-scala/blob/master/src/main/scala/com/fasterxml/jackson/module/scala/ser/ScalaPropertyBuilder.scala

I didn't submit a pull request because it's incomplete; to use it, it must be done at the caller level (since a module cannot override BeanSerializerFactory), as in:

mapper.setSerializerFactory(new ScalaSerializerFactory)

That's obviously suboptimal, and rather needs a hook in Module.SetupContext to make it "cleaner". What would you suggest I do from here?

JsonDeserialize on case class constructor argument not working from Java... sometimes

Sorry for the terrible issue name. This seems like an issue pretty specific to this particular edge case:
deserializing to a case class with @JsonDeserialize(using=...) on one of the constructor arguments, specifically doing the deserialization from Java.

Here is an example case class:

abstract class A
case class A1(prop1: String) extends A
case class A2(prop1: String, prop2: String) extends A

class ADeserializer extends JsonDeserializer[A] {
  def deserialize(jp: JsonParser, c: DeserializationContext)  = {
    (not important)
  }
}

case class B(prop1: String, @JsonDeserialize(using = classOf[ADeserializer]) prop2: A)

object Util {
  def mapper = {
    val m = new ObjectMapper()
    m.registerModule(DefaultScalaModule)
    m
  }

  val jsonString = """{"prop1":"asdf","prop2":{"prop1":"qwer"}}"""

  def fromJson(str:String) = mapper.readValue(str,classOf[B])
}

Now for the deserialization code in Scala:

val v = Util.mapper.readValue(Util.jsonString, classOf[B])
assert(v == B("asdf",A1("qwer"))) // Works as expected!

And for the Java code:

B v = Util.mapper.readValue(Util.jsonString(), B.class) // throws exception, jackson cannot instantiate an abstract type without additional info

And here is the creepy part:

B v1 = Util.fromJson(Util.jsonString()) // works just fine...
// and now this will work!
B v = Util.mapper.readValue(Util.jsonString(), B.class) // exactly the same as above.

It would be plausible that the first line somehow warms up the mapper so that the second line can succeed, but note that we are actually creating a new mapper for each line. Perhaps there is some state change in the DefaultScalaModule?

Because I am deserializing to B using SpringMVC, the fromJson method is not going to work, so here is my workaround version of B:

case class B(prop1: String, @JsonDeserialize(using = classOf[ADeserializer) var prop2: A){
  @JsonDeserialize(using = classOf[ADeserializer)
  def setProp2(a: A) {
    prop2 = a
  }
}
B v = Util.mapper.readValue(Util.jsonString(), B.class) // now, this works all on its own

I guess the key thing to note is that @JsonDeserialize is supposed to be placed on the setter, not the constructor argument. Obviously, there is not normally a setter with case classes, and using purely scala there is no problem.

This workaround is suboptimal because B is no longer an immutable object, as desired.

Please let me know if you need more information, or if I'm doing something totally wrong.

Thanks,
-John

Serialization doesn't apply PropertyNamingStrategy on case classes

When serializing a case class, the property naming strategy defined in the ObjectMapper doesn't appear to be applied. For example, the following tests should pass, but do not:

import com.fasterxml.jackson.databind.{ PropertyNamingStrategy, ObjectMapper }
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import org.specs2.mutable.SpecificationWithJUnit
import scala.Some

class JacksonCaseClassSpec extends SpecificationWithJUnit {
  private val mapper = new ObjectMapper
  mapper.setPropertyNamingStrategy(
    PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES)
  mapper.registerModule(new DefaultScalaModule)

  "Serializing a case class" should {
    val foo = new Foo(Some(1), "Bar", "baz")
    val json = mapper.readTree(mapper.writeValueAsString(foo))
    "yield an object with the required fields" in {
      Option(json.get("id")).map(_.asInt) must beSome(1)
      Option(json.get("name")).map(_.asText) must beSome("Bar")
      Option(json.get("camel_case")).map(_.asText) must beSome("baz")
    }
    "not have a camelCase property" in {
      Option(json.get("camelCase")).map(_.asText) must beNone
    }
  }

  final case class Foo(id: Option[Int], name: String, camelCase: String)
}

IndexOutOfBoundsException: 0 when deserializing generic case class

I'm trying to deserialize a generic type but this fails with IndexOutOfBoundsException: 0

Full test result and stack trace below

class Test extends Specification {
  "the json object containing an array" should {
    "be correctly deserialised to the generic class Pager" in {
      val json = """{"entities":[]}"""
      val pager = deserialize[Pager[Object]](json)
      pager.entities.size must be equalTo(0)
    }
  }

  def deserialize[T: Manifest](value: String) : T =
    mapper.readValue(value, new TypeReference[T]() {
      override def getType = new ParameterizedType {
        val getActualTypeArguments = manifest[T].typeArguments.map(_.erasure.asInstanceOf[Type]).toArray
        val getRawType = manifest[T].erasure
        val getOwnerType = null
      }
  })

 case class Pager[T](
    entities: List[T])
[info] the json object containing an array should
[error] ! be correctly deserialised to the generic class Pager
[error]     IndexOutOfBoundsException: 0 (List.scala:45)
[error] org.scalastuff.scalabeans.sig.ScalaTypeCompiler.<init>(ScalaTypeCompiler.scala:135)
[error] org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1$$anonfun$apply$2.apply(ScalaTypeCompiler.scala:51)
[error] org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1$$anonfun$apply$2.apply(ScalaTypeCompiler.scala:48)
[error] org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1.apply(ScalaTypeCompiler.scala:48)
[error] org.scalastuff.scalabeans.sig.ScalaTypeCompiler$$anonfun$1.apply(ScalaTypeCompiler.scala:47)
[error] org.scalastuff.scalabeans.sig.ScalaTypeCompiler$.classInfoOf(ScalaTypeCompiler.scala:47)
[error] org.scalastuff.scalabeans.PropertyDescriptor$$anonfun$4.apply(PropertyDescriptor.scala:185)
[error] org.scalastuff.scalabeans.PropertyDescriptor$$anonfun$4.apply(PropertyDescriptor.scala:184)
[error] org.scalastuff.scalabeans.PropertyDescriptor$.apply(PropertyDescriptor.scala:184)
[error] org.scalastuff.scalabeans.BeanIntrospector$.createPropertyDescriptor$1(BeanIntrospector.scala:76)
[error] org.scalastuff.scalabeans.BeanIntrospector$$anonfun$5$$anonfun$apply$5.apply(BeanIntrospector.scala:111)
[error] org.scalastuff.scalabeans.BeanIntrospector$$anonfun$5$$anonfun$apply$5.apply(BeanIntrospector.scala:102)
[error] org.scalastuff.scalabeans.BeanIntrospector$$anonfun$5.apply(BeanIntrospector.scala:102)
[error] org.scalastuff.scalabeans.BeanIntrospector$$anonfun$5.apply(BeanIntrospector.scala:101)
[error] org.scalastuff.scalabeans.BeanIntrospector$.apply(BeanIntrospector.scala:101)
[error] org.scalastuff.scalabeans.Preamble$.descriptorOf(Preamble.scala:31)
[error] org.codehaus.jackson.map.AnnotationIntrospector$Pair.findDeserializablePropertyName(AnnotationIntrospector.java:1450)
[error] org.codehaus.jackson.map.introspect.POJOPropertiesCollector._addFields(POJOPropertiesCollector.java:351)
[error] org.codehaus.jackson.map.introspect.POJOPropertiesCollector.collect(POJOPropertiesCollector.java:218)
[error] org.codehaus.jackson.map.introspect.BasicClassIntrospector.collectProperties(BasicClassIntrospector.java:160)
[error] org.codehaus.jackson.map.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:108)
[error] org.codehaus.jackson.map.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:16)
[error] org.codehaus.jackson.map.DeserializationConfig.introspect(DeserializationConfig.java:868)
[error] org.codehaus.jackson.map.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:587)
[error] org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:401)
[error] org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:310)
[error] org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:290)
[error] org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:159)
[error] org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeserializer(StdDeserializerProvider.java:180)
[error] org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.java:2829)
[error] org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2728)
[error] org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1870)
[error] Test.deserialize(Test.scala:72)
[error] Test$$anonfun$5$$anonfun$apply$22.apply(Test.scala:66)
[error] Test$$anonfun$5$$anonfun$apply$22.apply(Test.scala:64)

Support Iterators

Jackson core supports serialization of iterators, but the scala module doesn't.

I will make a pull request for my implementation of it.

Avoid serializing properties with None value

Option[T] properties with None value are now serialized as null JSON properties. Is there any way to avoid them being serialized at all (when the value is None) instead of as null JSON properties?

  • I tried to set mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_EMPTY), as a None Option value is somewhat empty, but it doesn't work for me.
  • Inclusion.NON_NULL won't work either (althought it won't write null Scala properties as JSON null values, it will write None scala properties as so).

Thank you very much!

Module does not correctly serialize Map keys which are scala objects

Gist here that shows the badness that happens.

https://gist.github.com/3243273

If you have map which is keyed by a scala object, then the map is not correctly written to json. If you run the example, you see the type of the key which comes back is actually a string and not a tuple as you would expect and what is written to the JSON file is a string and not a representation of a Tuple (it writes '(2,3)' instead of '[2,3]').

The deserialization issue I think I understand, because you need to add a special KeyDeserializer which is separate from a normal JSONDeserializer in that it has to be for an exact type. I can work around that in my code by creating custom KeyDeserializers for my objects (since i know the types ahead of time), but that isn't useful to me if I cannot get it to correctly serialize the map's keys.

Serialization of Option[java.lang.Integer]

Jackson is NPEing when trying to serialize an Option[java.lang.Integer].

def score: Option[java.lang.Integer] = reviewSummary.map { _.getScore }

If I define it like this, it works as expected:

def score = reviewSummary match {
  case Some(rs) => rs.getScore
  case _ => null
}

Which is strange because it looks like that's exactly what OptionSerializerModule is doing:
https://github.com/FasterXML/jackson-module-scala/blob/master/src/main/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerModule.scala#L11-14

Stacktrace:

org.codehaus.jackson.map.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.HashMap["searchPageData"]->scala.collection.MapWrapper["productListItemDataList"]->scala.collection.IterableWrapper[1]->scala.collection.MapWrapper["wtbScore"])
    at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:218)
    at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:183)
    at org.codehaus.jackson.map.ser.std.SerializerBase.wrapAndThrow(SerializerBase.java:140)
    ..continued...
Caused by: java.lang.NullPointerException
    at com.fasterxml.jackson.module.scala.ser.OptionSerializer.serialize(OptionSerializerModule.scala:13)
    at com.fasterxml.jackson.module.scala.ser.OptionSerializer.serialize(OptionSerializerModule.scala:8)
    at org.codehaus.jackson.map.ser.std.MapSerializer.serializeFields(MapSerializer.java:262)

Handle Scala option type (if possible)

note: re-created from [http://jira.codehaus.org/browse/JACKSON-247], see original issue for more details


Initial description:

So, the type of field I'm trying to map is a Scala Option[A] type. You can read some decent introductory stuff on it on various blogs. It's really useful when you have a value that is optional.

The specific case that I'm having a problem with is this Link class

class Link(href: URI, rel: String, length: Option[Long], hreflang: Option[String])

length and hreflang are never null. They are either Some or None. But when serializing, if the value is None, then I don't want to write a field out at all. But, the BeanPropertyWriter will see those values as being non-null and write out the field even if we don't want it to.


Comments:


Greg Zoller added a comment - 19/Nov/10 5:36 PM

Not sure who is the original requester but their desired approach to have no output for None won't work. Despite their assertion that length and hreflang will never be null, only Some() or None, a generalize json representation of Scala Option types can't make that heroic assumption.

An option is really a trinary value: Some(), None, or null, and a json representation must account for this.

The prototype package released under ticket http://jira.codehaus.org/browse/JACKSON-211 addresses this and handles Option (I think) correctly.

BigInt with hex values

De/serializing BigInt works well for decimal numbers. However, I would need it for hexadecimal numbers instead. With Jerkson I figured how to write short custom deserializer and serializer for this purpose. How could I do something similar for Jackson Module Scala? Thanks a lot for your help.

JSON schema for Option

I'm using jackson-module-scala to serialize and deserialize case classes to JSON and vice versa. and it works pretty well. I'd like to generate a json-schema for those case classes, but the generated schema uses type 'any' for Option types in my case classes.

According to Jackson the serializer should implement SchemaAware in order to provide schema information. The problem is that I can't extend OptionSerializer in OptionModule, since it is a private Object.

Could the OptionModule be made schema aware so that it generates the schema of the contained type? Is there any other solution? Is there something I'm doing wrong?

Thanks in advance.

Options for serializing enumerations

Is there any way to config how an enumeration is serialized?

I'm seeing:

{
  enumClass: "com.website.model.Comparison",
  value: "Newer"
}

but I'd rather just see

"Newer"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.