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

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions