FasterXML / jackson-dataformats-binary

Uber-project for standard Jackson binary format backends: avro, cbor, ion, protobuf, smile
Apache License 2.0
314 stars 136 forks source link

Stack overflow when generating Protobuf schema on class containing cyclic type definition #140

Closed acommuni closed 5 years ago

acommuni commented 6 years ago

I'm trying to generate schema from class on the following class :

 class B {
        public boolean isC() {
            return c;
        }

        public void setC(boolean c) {
            this.c = c;
        }

        private boolean c = true;

    }

    class A {
        private OffsetDateTime date;
        private List<B> b = Arrays.asList(new B[] { new B(), new B() });
        private B[] b2 = new B[] { new B(), new B() };

        public List<B> getB() {
            return b;
        }

        public void setB(List<B> b) {
            this.b = b;
        }

        public B[] getB2() {
            return b2;
        }

        public void setB2(B[] b2) {
            this.b2 = b2;
        }

        public OffsetDateTime getDate() {
            return date;
        }

        public void setDate(OffsetDateTime date) {
            this.date = date;
        }
    }

I generate the class with this :

private JsonProvider provider = new JacksonProvider();
    private ProtobufMapper mapper = new ProtobufMapper();

Class<?> cls = A.class;
        ProtobufSchema schemaWrapper = protoBuffCache.get(cls);
        schemaWrapper = mapper.generateSchemaFor(cls);

The stack loops on OffsetDatetime resolution


TypeResolver._resolve(MessageElement) line: 134 
TypeResolver._findAnyResolved(FieldElement, String) line: 182   
TypeResolver._resolve(MessageElement) line: 134 
TypeResolver._findAnyResolved(FieldElement, String) line: 182   
TypeResolver._resolve(MessageElement) line: 134 
TypeResolver._findAnyResolved(FieldElement, String) line: 182   
TypeResolver._resolve(MessageElement) line: 134 
TypeResolver._findAnyResolved(FieldElement, String) line: 182   
TypeResolver._resolve(MessageElement) line: 134 
TypeResolver._findAnyResolved(FieldElement, String) line: 182   
TypeResolver._resolve(MessageElement) line: 134 
TypeResolver.resolve(MessageElement) line: 93   
NativeProtobufSchema.forFirstType() line: 81    
ProtobufSchemaGenerator.getGeneratedSchema(boolean) line: 49    
ProtobufSchemaGenerator.getGeneratedSchema() line: 32   
ProtobufMapper.generateSchemaFor(Class<?>) line: 111    
cowtowncoder commented 6 years ago

Quick question: are you registering Java 8 date/time module (jackson-datatype-jsr310)? Without it, your schema generation would probably not work as expected, as Java 8 datatypes would not be supported explicitly.

acommuni commented 6 years ago

It works better now. Thanks ! It would be nice to have loop detection and a log notifying which class or field is the root of the loop

cowtowncoder commented 6 years ago

@acommuni I agree, loop should be detected and gracefully handled. If I have time, I hope to figure out a simple reproduction, using simple POJO (to avoid Java 8 dependency for 2.x)

cowtowncoder commented 5 years ago

Interesting. Direct self-reference is fine, and did not cause issue. It's only loop through at least one class. At least I can reproduce it now, initially had some issues.