BuilderWithBackRef2686Test.java

package com.fasterxml.jackson.databind.tofix;

import java.beans.ConstructorProperties;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonManagedReference;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import com.fasterxml.jackson.databind.testutil.failure.JacksonTestFailureExpected;

import static org.junit.jupiter.api.Assertions.assertNotNull;

// [databind#2686]: Not sure if this can ever be solved as
//  setter/builder is on Builder class, but it is called after
//  building completes, i.e. on wrong class.

class BuilderWithBackRef2686Test extends DatabindTestUtil {
    // [databind#2686]
    public static class Container {
        Content forward;

        String containerValue;

        @JsonManagedReference
        public Content getForward() {
            return forward;
        }

        @JsonManagedReference
        public void setForward(Content forward) {
            this.forward = forward;
        }

        public String getContainerValue() {
            return containerValue;
        }

        public void setContainerValue(String containerValue) {
            this.containerValue = containerValue;
        }
    }

    @JsonDeserialize(builder = Content.Builder.class) // Works when removing this, i.e. using the constructor
    public static class Content {
        //         @JsonBackReference
        private Container back;

        private String contentValue;

        @ConstructorProperties({"back", "contentValue"})
        public Content(Container back, String contentValue) {
            this.back = back;
            this.contentValue = contentValue;
        }

        public String getContentValue() {
            return contentValue;
        }

        @JsonBackReference
        public Container getBack() {
            return back;
        }

        @JsonPOJOBuilder(withPrefix = "")
        public static class Builder {
            private Container back;
            private String contentValue;

            @JsonBackReference
            Builder back(Container b) {
                this.back = b;
                return this;
            }

            Builder contentValue(String cv) {
                this.contentValue = cv;
                return this;
            }

            Content build() {
                return new Content(back, contentValue);
            }
        }
    }

    private final ObjectMapper MAPPER = newJsonMapper();

    @JacksonTestFailureExpected
    @Test
    void buildWithBackRefs2686() throws Exception {
        Container container = new Container();
        container.containerValue = "containerValue";
        Content content = new Content(container, "contentValue");
        container.forward = content;

        String json = MAPPER.writeValueAsString(container);
        Container result = MAPPER.readValue(json, Container.class); // Exception here

        assertNotNull(result);
    }
}