Wrong JsonStreamContext hierarchy when using JsonNode.traverse TreeTraversingParser

18 views
Skip to first unread message

Paolo Bazzi

unread,
Aug 22, 2018, 7:02:43 AM8/22/18
to jackson-user
I run into a strange JsonStreamContext hierarchy problem within my custom deserializer when using JsonNode.traverse (TreeTraversingParser) as input for my deserialization instead of deserializing an Inputstream. I tracked down the problem to a simple example setup:

Input JSON:   

{
  "items": [
    {
      "name": "foo"
    }
  ]
}

Defined by Container and Items Java classes:

static class Container {
Collection<Item> items;

public Collection<Item> getItems() {
return items;
}

public void setItems(Collection<Item> items) {
this.items = items;
}
}

static class Item {

@JsonDeserialize(using = ItemNameDeserializer.class)
String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

The custom Deserializer on Item.name is only used to print out the JsonStreamContext:

static class ItemNameDeserializer extends StdDeserializer<String> {
private static final long serialVersionUID = 1L;

public ItemNameDeserializer() {
super(String.class);
}

@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
debugOutContext(p.getParsingContext());
return p.readValueAs(String.class);
}

private void debugOutContext(JsonStreamContext ctx) {
System.out.println("Context: " + ctx.hashCode() + ",\tcurName=" + ctx.getCurrentName() + ",\tcurIndex=" + ctx.getCurrentIndex() +",\ttype=" + ctx.getTypeDesc() + ",\tcurValue=" + ctx.getCurrentValue());
if (ctx.getParent() != null) {
debugOutContext(ctx.getParent());
}
}
}



JSON input serialized and deserialized using default ObjectMapper write/readValue methods:

ObjectMapper mapper = new ObjectMapper();

Container container = new Container();
Item item = new Item();
item.name = "foo";
container.items = new ArrayList<>();
container.items.add(item);

String json = mapper.writeValueAsString(container);
Container containerMashalled = mapper.readValue(json, Container.class);

Looking at the Context hierarchy, the output is as expected:

ROOT Context
  OBJECT Context with value "Container " instance
    ARRAY Context with Collection instance
      OBJECT Context with "Item" instance

Context: 486898233, curName=name, curIndex=0, type=OBJECT, curValue=ch.pbz.jackson.Test$Item@26be92ad
Context: 1282473384, curName=null, curIndex=0, type=ARRAY, curValue=[]
Context: 575593575, curName=items, curIndex=0, type=OBJECT, curValue=ch.pbz.jackson.Test$Container@14acaea5
Context: 1188392295, curName=null, curIndex=0, type=ROOT, curValue=null

Now deserializing the same JSON using the JsonNode.traverse() as input:

ObjectMapper mapper = new ObjectMapper();
JsonParser jsonParser = mapper.getFactory().createParser(json);
JsonNode doc = jsonParser.readValueAsTree();
JsonParser traverse = doc.traverse(jsonParser.getCodec());
Container container = mapper.readValue(traverse, Container.class);

Looking at the Context hierarchy, the output is "strange"

- No ROOT Context ?
- OBJECT Context, but with Collection instance as current value instead of "Container" instance??
    ARRAY Context with no current value??
      OBJECT Context with "Item" instance  (correct!)

Context: 466505482, curName=name, curIndex=0, type=OBJECT, curValue=ch.pbz.jackson.Test$Item@5e3a8624
Context: 1547425104, curName=null, curIndex=0, type=ARRAY, curValue=null
Context: 152134087, curName=items, curIndex=0, type=OBJECT, curValue=[]

It seems like the items OBJECT context is overridden with the current value of the ARRAY context and the ARRAY context misses the correct current value.

Any suggestions if we use the ObjectMapper in an inappropriate way or if this is a Jackson bug?

See attached Test.java complete test case to reproduce.

Regards,
Paolo
Test.java

Paolo Bazzi

unread,
Aug 22, 2018, 7:11:45 AM8/22/18
to jackson-user
Additional info: verified with latest Jackson 2.9.6 version

Tatu Saloranta

unread,
Aug 31, 2018, 5:26:06 PM8/31/18
to jackson-user
Quick answer: sounds like a Jackson bug.

Longer answer: maintaining accurate read context hierarchy gets
complicated since it needs to "stitch" together contexts from original
context (physical parser, originally), and then context for
TreeTraversingParser (for JsonNode) or its equivalent for TokenBuffer
(when re-reading buffered content).

I think there has been a report before for `jackson-core` (or
`jackson-databind`), but I can not locate one now on issue tracker.

-+ Tatu +-

On Wed, Aug 22, 2018 at 4:11 AM Paolo Bazzi <paolo...@gmail.com> wrote:
>
> Additional info: verified with latest Jackson 2.9.6 version
>
> --
> You received this message because you are subscribed to the Google Groups "jackson-user" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user...@googlegroups.com.
> To post to this group, send email to jackso...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages