Skip to content

@JsonIgnore on Record property ignored if there is getter override #3992

@ennishol

Description

@ennishol

Describe the bug
With v 2.15.x I run into com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError). The code works with 2.14.2

To Reproduce
Run the unit test below, see comments in the code

package org.acme.json.error;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

class SerializationTest {

    private ObjectMapper objectMapper;

    @BeforeEach
    void setUp() {
        objectMapper = new ObjectMapper();
    }

    @Test
    public void greeting() throws JsonProcessingException {
        var beanWithRecursion = new Recursion();
        beanWithRecursion.add(beanWithRecursion);
        var gr = new GreetingWithTransientRecursion("hello", beanWithRecursion);
        var json = objectMapper.writer().writeValueAsString(gr);
        System.out.println(json);
    }

    @Test
    public void hello() throws JsonProcessingException {
        var beanWithRecursion = new Recursion();
        beanWithRecursion.add(beanWithRecursion);
        var hello = new HelloWithoutTransientRecursion("hello", beanWithRecursion);
        var json = objectMapper.writer().writeValueAsString(hello);
        System.out.println(json);
    }

    @Test
    public void hellorecord() throws JsonProcessingException {
        var beanWithRecursion = new Recursion();
        beanWithRecursion.add(beanWithRecursion);
        var hello = new HelloRecord("hello", beanWithRecursion);
        var json = objectMapper.writer().writeValueAsString(hello);
        System.out.println(json);
    }

    //works fine as the class but not if converted to record
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class HelloWithoutTransientRecursion implements Serializable {
        @Serial
        private static final long serialVersionUID = 1L;
        private final String text;
        @JsonIgnore
        private final Recursion hidden;

        public HelloWithoutTransientRecursion(String text, Recursion hidden) {
            this.text = text;
            this.hidden = hidden;
        }

        public String getText() {
            return text;
        }

        public Recursion getHidden() {
            return hidden;
        }

        @Override
        public String toString() {
            return "GreetingWithTransientRecursion{" +
                    "text='" + text + '\'' +
                    ", hidden='" + hidden + '\'' +
                    '}';
        }
    }

    /**
     * Infinite recursion (StackOverflowError)
     */
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public record HelloRecord(String text, @JsonIgnore Recursion hidden) {

        /**
         * when the method is not overriden it works
         */
        @Override
        public Recursion hidden() {
            return hidden;
        }

    }

    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static final class GreetingWithTransientRecursion implements Serializable {
        @Serial
        private static final long serialVersionUID = 1L;
        private String text;
        @JsonIgnore
        private transient Recursion hidden; //transient keyword causes Infinite recursion (StackOverflowError)

        public GreetingWithTransientRecursion(String text, Recursion hidden) {
            this.text = text;
            this.hidden = hidden;
        }

        public void setText(String text) {
            this.text = text;
        }

        public void setHidden(Recursion hidden) {
            this.hidden = hidden;
        }

        public String getText() {
            return text;
        }

        public Recursion getHidden() {
            return hidden;
        }
    }

    public static class Recursion {
        private final List<Recursion> all = new ArrayList<>();

        void add(Recursion recursion) {
            all.add(recursion);
        }

        public List<Recursion> getAll() {
            return all;
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    RecordIssue related to JDK17 java.lang.Record support

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions