-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
I wrote this small test program to demonstrate the issue:
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.databind.ObjectMapper;
public class ObjectIdTest {
public static class Foo {
@JsonIdentityReference(alwaysAsId = true)
public Bar bar1;
@JsonIdentityReference()
public Bar bar2;
}
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class)
public static class Bar {
}
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
// create structure to serialize
Foo mo = new Foo();
mo.bar1 = new Bar();
mo.bar2 = mo.bar1;
// serialize it
System.out.println(mapper.writeValueAsString(mo));
}
}
When executing this test program in the latest version (2.7.4), the output will be {"bar1":1,"bar2":{"@id":2}}
- the second field will be written with a new id even though both fields reference the same object. Because of this, writing forward references is essentially impossible.
The issue seems to be the fact that BeanSerializerBase will always call WritableObjectId.generateId if the referenced object has not been written in plain format yet (https://github.com/FasterXML/jackson-databind/blob/master/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java#L600). This will also happen if an id has been generated before.
It might also be smarter to only generate a new id in WritableObjectId.generateId if that hasn't happened before; as that method doesn't have a javadoc I can't tell how it is supposed to work.