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

Nested sequence of polymorphic type serialized without type info (ver 2.10.2) #442

Open
tremaluca opened this issue Mar 9, 2020 · 4 comments

Comments

@tremaluca
Copy link

The following code works as expected

import com.fasterxml.jackson.annotation.{JsonSubTypes, JsonTypeInfo}
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes(Array(
  new JsonSubTypes.Type(value = classOf[Ingredient.Meat], name = "meat"),
  new JsonSubTypes.Type(value = classOf[Ingredient.Vegetable], name = "veggie")
))
trait Ingredient
object Ingredient {
  case class Meat(of: String) extends Ingredient
  case class Vegetable(name: String) extends Ingredient
}

case class Burrito(filling: Seq[Ingredient])

case class BurritoTray(content: Seq[Burrito])

object Main extends App {
  val mapper = new ObjectMapper().registerModule(DefaultScalaModule)
  println(mapper.writeValueAsString(BurritoTray(Seq(
    Burrito(Seq(Ingredient.Meat("chicken"), Ingredient.Vegetable("salad"))),
    Burrito(Seq(Ingredient.Vegetable("salad"), Ingredient.Vegetable("pickles")))
  ))))
}

printing the following output

{"content":[{"filling":[{"type":"meat","of":"chicken"},{"type":"veggie","name":"salad"}]},{"filling":[{"type":"veggie","name":"salad"},{"type":"veggie","name":"pickles"}]}]}

But if the Burrito class is replaced by a simple Seq[Ingredient]

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes(Array(
  new JsonSubTypes.Type(value = classOf[Ingredient.Meat], name = "meat"),
  new JsonSubTypes.Type(value = classOf[Ingredient.Vegetable], name = "veggie")
))
trait Ingredient
object Ingredient {
  case class Meat(of: String) extends Ingredient
  case class Vegetable(name: String) extends Ingredient
}

case class BurritoTray(content: Seq[Seq[Ingredient]])

object Main extends App {
  val mapper = new ObjectMapper().registerModule(DefaultScalaModule)
  println(mapper.writeValueAsString(BurritoTray(Seq(
    Seq(Ingredient.Meat("chicken"), Ingredient.Vegetable("salad")),
    Seq(Ingredient.Vegetable("salad"), Ingredient.Vegetable("pickles"))
  ))))
}

the type information is omitted in the resulting json

{"content":[[{"of":"chicken"},{"name":"salad"}],[{"name":"salad"},{"name":"pickles"}]]}

This issue is not present in equivalent java code

public class JacksonNestedCollection {
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({
        @JsonSubTypes.Type(value = Meat.class, name = "Meat"),
        @JsonSubTypes.Type(value = Veggie.class, name = "Veggie")
    })
    private interface Ingredient {}
    private static class Meat implements Ingredient {
        public final String of;
        public Meat(String of) {
            this.of = of;
        }
    }
    private static class Veggie implements Ingredient {
        public final String name;
        public Veggie(String name) {
            this.name = name;
        }
    }

    private static final class BurritoTray {
        public final List<List<Ingredient>> content;
        public BurritoTray(List<List<Ingredient>> content) {
            this.content = content;
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writeValueAsString(new BurritoTray(Arrays.asList(
            Arrays.asList(new Meat("chicken"), new Veggie("salad")),
            Arrays.<Ingredient>asList(new Veggie("salad"), new Veggie("pickles"))
        ))));
    }
}
@iLoveZod13
Copy link

iLoveZod13 commented Apr 26, 2020

I think similar symptom also occurs to Tuple.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
class PyContextMetaType

case class Wpbp (sepInd: Int
                 , esgGrping: Int
                 , psaGrping: Int
                 , pernr: BigInt
                 , eeGrp: Char
                 , eeSubGrp: String
                 , perArea: String
                 , perSubArea: String
                 , orgUnit: String
                 , position: String
                 , costCenter: String) extends PyContextMetaType

case class LogNode2(var text: String,

                   @JsonBackReference
                   dadNode: Option[AnyRef] = None,

                   var data: (Option[PyContextMetaType],Option[PyContextMetaType]) = (None, None),

                   @JsonManagedReference
                   children: ListBuffer[LogNode] = new ListBuffer[LogNode],
                   detailText: String = "") extends CborSerializable
{
    ....
}

object Main3 {
  def main(args: Array[String]): Unit = {
    val wpbp = Wpbp(1,3,3,28000001,1,"A0","CN01","SH01","HR Dept","","CC1234")
    val wpbpNode2 = LogNode2("WPBP", None, (None, Some(wpbp)))

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

    val jsonStr = mapper.writeValueAsString(wpbpNode2)

    println(jsonStr)
  }

}

Pay attention to the "data" member of LogNode2, which is a Tuple2 that uses PyContextMetaType.
The serialized jsonStr lost the type info of Wpbp object:

{
  "text": "WPBP",
  "data": [
    null,
    {
      "sepInd": 1,
      "esgGrping": 3,
      "psaGrping": 3,
      "pernr": 28000001,
      "eeGrp": "\u0001",
      "eeSubGrp": "A0",
      "perArea": "CN01",
      "perSubArea": "SH01",
      "orgUnit": "HR Dept",
      "position": "",
      "costCenter": "CC1234"
    }
  ],
  "children": [],
  "detailText": ""
}

The expected jsonStr should be:

{
  "text": "WPBP",
  "data": [
    null,
    {
      "Wpbp": {
        "sepInd": 1,
        "esgGrping": 3,
        "psaGrping": 3,
        "pernr": 28000001,
        "eeGrp": "\u0001",
        "eeSubGrp": "A0",
        "perArea": "CN01",
        "perSubArea": "SH01",
        "orgUnit": "HR Dept",
        "position": "",
        "costCenter": "CC1234"
      }
    }
  ],
  "children": [],
  "detailText": ""
}

@iLoveZod13
Copy link

@tremaluca

Hi there,

Were you able to find a workaround for this?

@tremaluca
Copy link
Author

Hi @iLoveZod13,
I also had some different issues with tuples (ids not properly serialized), and I solved by not using tuples, replacing them with a simple "Pair" case class...

@iLoveZod13
Copy link

Hi @tremaluca
Yes I noticed your Pair case class workaround in issue 443, and I am trying that now. Thanks a lot for the enlightening.

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

2 participants