1

I'm serializing and deserializing a list including two objects, with circular references there.

First I tried ObjectIdGenerators.StringIdGenerator as the generator.

//Using latest version for the dependencies
//jackson.version = 2.13.1
//jackson-jsog = 1.1.2

    @NoArgsConstructor
    @JsonIdentityInfo(generator = ObjectIdGenerators.StringIdGenerator.class)
    public static class Outer {
        @Setter
        @Getter
        private Inner inner;
    }

    @NoArgsConstructor
    @JsonIdentityInfo(generator = ObjectIdGenerators.StringIdGenerator.class)
    public static class Inner {

        @Getter
        private Outer outer;

        public Inner(Outer outer) {
            this.outer = outer;
            outer.setInner(this);
        }
    }

public static void main(String[] args) throws Exception {
        // There are circular references between Outer and Inner
        Outer outer = new Outer();
        Inner inner = new Inner(outer);
        // Turn on type info
        PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder().allowIfSubType(Object.class).build();
        ObjectMapper mapper = new ObjectMapper()
                .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.EVERYTHING,
                        JsonTypeInfo.As.PROPERTY);

        List<Object> source = Lists.newArrayList(outer, inner);
        String json = mapper.writeValueAsString(source);
        System.out.println(json);
        //This is the json serialized by StringIdGenerator, which doesn't make sense for the second instance(no type info there,just a UUID)
        //See below
        List<Object> target = mapper.readerForListOf(Object.class).readValue(json);
        System.out.println(target);
        //So I finally got an Outer instance and a string in the target list, not equal to source list at all
        //[com.foo.bar.SomeTest$Outer@4b29d1d2, acb5231d-13de-4e22-92c6-cb1ec0530de1]

    }

This is the json serialized by StringIdGenerator, which doesn't make sense for the second instance(no type info there,just a UUID)

[
    "java.util.ArrayList",
    [
        {
            "@class": "com.foo.bar.SomeTest$Outer",
            "@id": "df6ed346-6b27-4983-8dc2-5c07ddfa8f8f",
            "inner":
            {
                "@class": "com.foo.bar.SomeTest$Inner",
                "@id": "acb5231d-13de-4e22-92c6-cb1ec0530de1",
                "outer": "df6ed346-6b27-4983-8dc2-5c07ddfa8f8f"
            }
        },
        "acb5231d-13de-4e22-92c6-cb1ec0530de1"
    ]
]

Then I tried JSOGGenerator


    @NoArgsConstructor
    @JsonIdentityInfo(generator = JSOGGenerator.class)
    public static class Outer {
        @Setter
        @Getter
        private Inner inner;
    }

    @NoArgsConstructor
    @JsonIdentityInfo(generator = JSOGGenerator.class)
    public static class Inner {

        @Getter
        private Outer outer;

        public Inner(Outer outer) {
            this.outer = outer;
            outer.setInner(this);
        }
    }

    public static void main(String[] args) throws Exception {
        // There are circular references between Outer and Inner
        Outer outer = new Outer();
        Inner inner = new Inner(outer);
        // Turn on type info
        PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder().allowIfSubType(Object.class).build();
        ObjectMapper mapper = new ObjectMapper()
                .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.EVERYTHING,
                        JsonTypeInfo.As.PROPERTY);

        List<Object> source = Lists.newArrayList(outer, inner);
        String json = mapper.writeValueAsString(source);
        System.out.println(json);
        //This is the json serialized by JSOGGenerator, which does make sense
        //See below
        List<Object> target = mapper.readerForListOf(Object.class).readValue(json);
        //However, I got an InvalidTypeIdException while deserializing
        //Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class com.voodoodyne.jackson.jsog.JSOGRef]: missing type id property '@class'

    }


This is the json serialized by JSOGGenerator, which does make sense.


[
    "java.util.ArrayList",
    [
        {
            "@class": "com.foo.bar.SomeTest$Outer",
            "@id": "1",
            "inner":
            {
                "@class": "com.foo.bar.SomeTest$Inner",
                "@id": "2",
                "outer":
                {
                    "@ref": "1"
                }
            }
        },
        {
            "@ref": "2"
        }
    ]
]

However, I got an InvalidTypeIdException while deserializing. And I found the property "@id" is not handled correctly.

See ObjectIdValueProperty._valueDeserializer._baseType, which type is JSOGRef and it can not parse "1"(String) as object id value.

My questions

  • What's the correct way to deal with this?
  • Do we have some other generator to try?
Anderson
  • 2,496
  • 1
  • 27
  • 41
  • From the documentation it seems jackson cannot handle the double circular reference, so you should modify manually the json to obtain the expected result. – dariosicily Jan 14 '22 at 22:09
  • Bug reported. https://github.com/FasterXML/jackson-databind/issues/3372 – Anderson Jan 15 '22 at 02:34

0 Answers0