No way to combine @JsonTypeInfo(include = As.PROPERTY) and @JsonIdentityInfo(generator = PropertyGenerator.class) (original) (raw)

Describe the bug
I have tried many different ways to combine @JsonTypeInfo(include = As.PROPERTY) and @JsonIdentityInfo(generator = PropertyGenerator.class), but it always ends up throwing an exception at me like this one:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid Object Id definition for `foo.JacksonDeserializationTest$BaseEntity`: cannot find property with name '@id'
 at [Source: (String)"{"@c":"foo.JacksonDeserializationTest$Bar","@id":1,"foo":{"@c":"foo.JacksonDeserializationTest$Foo","@id":0,"other":1}}"; line: 1, column: 1]

    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1915)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:268)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findNonContextualValueDeserializer(DeserializationContext.java:644)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:539)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:294)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:654)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4956)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4826)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3772)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3740)

Version information
2.15.2

To Reproduce

class JacksonDeserializationTest {

@Test
void test() throws Exception {
    Foo foo = new Foo();
    Bar bar = new Bar();
    foo.setOther(bar);
    bar.setFoo(foo);

    ObjectMapper mapper = new ObjectMapper();
    System.out.println(mapper.writeValueAsString(bar));
    Bar deserialized = mapper.readValue(mapper.writeValueAsString(bar), Bar.class);
}

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@c")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "@id")
public interface BaseEntity {
    class Id {
        static int next = 0;
    }
    @JsonProperty("@id")
    Integer getId();
}

public static class Foo implements BaseEntity {
    private BaseEntity other;
    private Integer id = Id.next++;

    @Override
    public Integer getId() {
        return id;
    }

    public BaseEntity getOther() {
        return other;
    }

    public void setOther(BaseEntity other) {
        this.other = other;
    }
}

public static class Bar implements BaseEntity {
    private BaseEntity foo;

    private Integer id = Id.next++;

    @Override
    public Integer getId() {
        return id;
    }

    public BaseEntity getFoo() {
        return foo;
    }

    public void setFoo(BaseEntity foo) {
        this.foo = foo;
    }
}

}

Expected behavior
It seems like it should be possible to combine these two features somehow. I have tried all combinations I can think of, but couldn't get it to work, so I assume there must be some bug here.

Additional context
I have a set of Java objects I want to serialize, where the references in the object graph form many cycles, so I need to use @JsonIdentityInfo for this. Also, I have an inheritance hierarchy, so I need to use @JsonTypeInfo to cover this.