jackson-module-scala icon indicating copy to clipboard operation
jackson-module-scala copied to clipboard

in some cases serialization of option is not working

Open oshai opened this issue 6 years ago • 17 comments

We are using jackson 2.9.8.

Sometimes (we couldn't find any consistent case) it ignore option (like scala module is unaware of option and just writing a json like this:
{"x":1,"empty":false,"defined":true} (in this case this is an option of int).

oshai avatar Feb 12 '19 16:02 oshai

Is there any chance you teased out what kind of types (static inner classes, anonymous inner classes, etc) it fails to serialize?

nbauernfeind avatar Mar 25 '19 13:03 nbauernfeind

It was simple types like Boolean and Int (Option of them)

oshai avatar Mar 25 '19 13:03 oshai

I doubt it is that simple. We have tests that pass on all released versions of this module that specifically serialize Option[Int].

See: https://github.com/FasterXML/jackson-module-scala/blob/master/src/test/scala/com/fasterxml/jackson/module/scala/ser/OptionSerializerTest.scala#L69

Is there any chance you were using an ObjectMapper that did not have the proper scala modules registered?

nbauernfeind avatar Mar 25 '19 13:03 nbauernfeind

I don't think so. It looked like a race condition, because it didn't happen to the type on all mapping but only on specific methods.

oshai avatar Mar 25 '19 14:03 oshai

Race condition, in that sometimes a singular code path would serialize correctly and other times it would not?

What version of scala are you using? Do you still observe this issue?

nbauernfeind avatar Mar 25 '19 14:03 nbauernfeind

It's more looks like a race condition on construction time because when it fails for a specific endpoint it will constantly fail on that. However, it wasn't failing on all entities with that type and we also have few instances of the service and it failed only on a couple of them. Scala version is 2.11.7.

oshai avatar Mar 25 '19 14:03 oshai

If you can tease out a toy program that (when run enough times) will eventually fail, then I would be happy to investigate further. Otherwise, I am not aware of any inherent race conditions in scala 2.11.x - so I'm not even sure what would be an appropriate scenario to try.

nbauernfeind avatar Mar 25 '19 14:03 nbauernfeind

Unfortunately, we didn't manage to reproduce it.

oshai avatar Mar 25 '19 14:03 oshai

@plokhotnyuk, I see your +1 -- any chance you have a different use case or a repeatable issue?

nbauernfeind avatar Mar 25 '19 14:03 nbauernfeind

One thing that might help is that we reverted to 2.6.5 and don't see the issue anymore.

oshai avatar Mar 25 '19 14:03 oshai

That slightly helps ... in that the code paths for Option before and after 2.7.4 are completely different.

nbauernfeind avatar Mar 25 '19 14:03 nbauernfeind

@nbauernfeind the working w/a for me is using jsoniter-scala instead - it generates codecs at compile time and can print their sources for validation, like here

plokhotnyuk avatar Apr 10 '19 03:04 plokhotnyuk

Hi guys I have the same problem, not had time to extract it to a simple test yet as gotta just revert the version bump to get into prod, but this is what I know so far.

The bug can manifest rendering a simple DTO that contains two scala Option[Long] both Some(..)'s the first option renders as a Number the second as a an Option rendered by the Bean Mapper showing it's properties , eg value, empty and defined

A simple test of my WebRestObjectMapper (see below) does not have a problem.

class WebRestObjectMapper extends ObjectMapper { registerModule(new DefaultScalaModule) registerModule(new JodaModule) configure(WRITE_DATES_AS_TIMESTAMPS, false) configure(FAIL_ON_UNKNOWN_PROPERTIES, false) this.setSerializationInclusion(JsonInclude.Include.NON_NULL) this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY) this.setSerializationInclusion(JsonInclude.Include.NON_ABSENT) }

the FunSpec test looks like

`/** test for Bug ParentId is an Option[Long] but sometimes represents like * * "parentId": { * "value": 11, * "empty": false, * "defined": true * } * */ describe("WebRestObjectMapper for EntityCategoryDto") {

it("should writeEntityCategoryDto non-empty parentId Option[Long] as a simple Number") {
  new Fixtures {
    val dto1 = EntityCategoryDto(Some(22), "Number 22", "testing", Some(22L))
    mapper.writeValueAsString(dto1) should be("""{"id":22,"name":"Number 22","type":"testing","parentId":22}""")
  }
}

}`

However when using Spring WebMVC (version 4.3.5.RELEASE ) vial a Controller the error manifests. debugging by placing a breakpoint at BeanPropertyWriter.java.702 to watch the _dynamicSeralizers Map be a different instance for first Option and second Option in EntityCategoryDto The first time the _dynamicSeralizers is the Single instance which works matching “scala.Some” with “scala.Some” in

if (type == _type)

on line PropertySerializerMap.java:279

the second time it is the Double and the equivalent if(type = type) on line 310 compares “scala.Some” with “scala.None” so doesn’t match and falls back to the _serializer2 which is a the BeanMapper which renders the Options properties.

I do not know why the _dynamicSeralizers are different each time while running through the my EntityCategoryDto case class.

Hope this helps someone to fix it.

Cheers

karlroberts avatar Jun 11 '19 00:06 karlroberts

Hey guys,

We would like to upgrade to scala 2.13 and use the latest jackson-module-scala version which supports it.

Any news about this issue? we are in concern about upgrading to the latest version when this issue still exists.

Thanks a lot!

galando avatar Aug 20 '19 09:08 galando

@galando Github issues are not good discussion forum: please use mailing list:

https://groups.google.com/forum/#!forum/jackson-user

for questions like this.

cowtowncoder avatar Aug 20 '19 19:08 cowtowncoder

Thanks @cowtowncoder for the clarification.

galando avatar Sep 02 '19 11:09 galando

I noticed the email so maybe others can comment there, but 2 other things:

  1. Looks like there is no reliable reproduction (unless I missed it from above): one is needed to show what exactly is wrong -- and especially on Jackson side. It is possible issue is with framework(s), not Jackson, since they typically do not pass fully resolve type information (mostly fault of JDK lacking good mechanisms, but that's longer discussion)
  2. We have a new co-owner of this module, @pjfanning, who might be able to have a look at this issue, so cc:ing him.

cowtowncoder avatar Sep 04 '19 03:09 cowtowncoder