Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Case classes with option types don't follow serialization configuration #32

Closed
fehguy opened this issue Jun 27, 2012 · 14 comments
Closed
Milestone

Comments

@fehguy
Copy link

fehguy commented Jun 27, 2012

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 "{}"
@christophercurrie
Copy link
Member

Thanks for the bug report, I'll take a look at why the works for normal classes and see what needs to be added to the case class logic.

@christophercurrie
Copy link
Member

While I haven't yet worked out a way to support this using JsonInclude.Include.NON_NULL (which makes the most logical sense, but doesn't appear to have a hook in JsonSerializer, I have added support in OptionSerializer to recognize and honor JsonInclude.Include.NON_EMPTY to achieve the same goal.

@christophercurrie
Copy link
Member

Reopening, as I realize now that this issue is slightly different than #9.

christophercurrie added a commit that referenced this issue Jul 2, 2012
@christophercurrie
Copy link
Member

I added what I think is a functionally equivalent pair of tests to CaseClassSerializerTest and was not able to reproduce the problem. If you can, please retest your use case with the latest code and reopen if you continue to have issues.

@christophercurrie
Copy link
Member

Well it looks like my tests were bad. Reopening as I've fixed the tests and the problem still exists.

@christophercurrie
Copy link
Member

Ok, filing in some more information so I don't forget it.

  • The non-case class isn't succeeding because it's working properly, it's succeeding because the Scala module doesn't currently recognized the property. If I add @JsonProperty annotation to TestObject3, the test fails.
  • Getting NOT_NULL recognized requires that Jackson recognize that it's possible for a non-null value in the JVM to be serialized as JSON "null". Jackson doesn't currently have a hook for this, but I've got an idea for an approach that might work by replacing BeanPropertyWriter with a new version that recognizes "null-like" values.

I should have a fix for this shortly.

@leons727
Copy link

With jackson 2.1.0 and jackson-module-scala 2.1.1-SNAPSHOT:

case class Foo(val a: String, val b: Option[Int] = None)

@RunWith(classOf[BlockJUnit4ClassRunner])
class TryJSON {

@test
def testNulls() {
val m = new ObjectMapper()
m.registerModule(new DefaultScalaModule())
m.setSerializationInclusion(JsonInclude.Include.NON_NULL)
println(m.writeValueAsString(new Foo(null, None)))
}
}

Prints:

{"a":null,"b":null}

Am I missing something?

@christophercurrie
Copy link
Member

Nope, my tests are bad, #45 also reported this. Will fix ASAP and issue a 2.1.1 for it.

christophercurrie added a commit to christophercurrie/jackson-module-scala that referenced this issue Oct 26, 2012
@christophercurrie
Copy link
Member

This issue should be resolved in 2.1.1, just released.

@leons727
Copy link

Yes, works for me correctly now. Thanks for the quick turnaround!

@jsw
Copy link

jsw commented Aug 10, 2016

This seems to be broken again in 2.7.4 and 2.7.5.

I setup my ObjectMapper using

val mapper = new ObjectMapper with ScalaObjectMapper
mapper.registerModule(DefaultScalaModule)
mapper.registerModule(new JavaTimeModule)
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
mapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)

and the following test fails

val json = mapper.writeValueAsString(C(None, None))
assert(json === "{}")
[info] - should not serialize null fields *** FAILED ***
[info]   "{["a":null,"b":null]}" did not equal "{[]}" (JacksonUtilTest.scala:27)

@devshorts
Copy link

Seems still broken in 2.8.3 as well

@ptagr
Copy link

ptagr commented Nov 27, 2016

is there a workaround for this ?

@jsw
Copy link

jsw commented Nov 27, 2016

Use JsonInclude.Include.NON_ABSENT. See issue 280

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants