Родительско-дочерние отношения между двумя объектами вызывают JSON StackOverflowError - PullRequest
1 голос
/ 17 февраля 2020

Я пытаюсь установить отношения родитель-потомок между некоторыми объектами, и у меня возникли некоторые проблемы.

В моем случае я пытаюсь хранить объекты внутри других объектов (например, контейнер хранит несколько элементов или другие контейнеры с элементами). Сложность состоит в том, что каждый объект в хранилище должен иметь возможность определить, какой он является внешним родительским объектом. Хотя это, кажется, работает в моей базе данных в памяти (в настоящее время используется h2), попытка получить JSON представление всех моих элементов хранения дает это (я возвращаю List<StorageUnit>):

Не удалось записать JSON: бесконечная рекурсия (StackOverflowError); вложенное исключение: com.faster xml .jackson.databind.JsonMappingException: бесконечная рекурсия (StackOverflowError) (через цепочку ссылок: java .util.ArrayList [0] -> com.warehousing.storage.FixedContentsCase ["contents"] -> java .util.ArrayList [0] -> com.warehousing.storage.FixedContentsCase ["contents"] -> ...

Вот классы:

StorageUnit

@Entity
@Inheritance
public abstract class StorageUnit {

   @Id
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   private Long id;
   @ManyToOne
   private Location location;
   protected Long parentContainerId;
   // <getters & setters> 
   public abstract List<StorageUnit> getContents();
}

FixedContentCase


@Entity
public class FixedContentsCase extends StorageUnit {
    @OneToMany
    private List<Item> items; 

    public FixedContentsCase() {
        super();
        items = new ArrayList<>();
    }
    // <getters & setters> 
    @Override
    public List<StorageUnit> getContents() {
        // Return the case itself and its contents
        List<StorageUnit> contents = new ArrayList<>(Arrays.asList(this));
        for (StorageUnit item : items) 
            contents.addAll(item.getContents());
        return contents;
    }   
}

Элемент

@Entity
public class Item extends StorageUnit {

    private String description;

    public Item() {
        super();
        this.description = "";
    }
    // <getters & setters> 
    @Override
    public List<StorageUnit> getContents() {
        return Arrays.asList(this);
    }   
}

I Я пытался аннотировать класс StorageUnit с помощью @JsonIgnoreProperties("parentContainerId"), но это не сработало. Аннотации parentContainerId с @JsonIgnore тоже не помогли. Я также попытался аннотировать геттеры вместо самих атрибутов (согласно * 1031) * follow ). Есть ли способ обойти это или необходимо какое-то изменение дизайна? Спасибо!

Ответы [ 2 ]

1 голос
/ 17 февраля 2020

Используя Джексона, это определенно возможно благодаря аннотациям типа @JsonIgnore или подходу DTO, упомянутому BugsForBreakfast.

Я создал обработчик Джексона MixIn, чтобы разрешить динамическую c фильтрацию, которую я использую, чтобы избежать шаблонов DTO

https://github.com/Antibrumm/jackson-antpathfilter

примеры в файле readme должны показать, как это работает и возможно ли это для вас.

0 голосов
/ 17 февраля 2020

Ваша проблема в том, что вы добавляете саму единицу хранения в список содержимого, что приводит к бесконечной рекурсии, если вы перемещаетесь по дереву вниз. Решение: используйте ссылку и сериализуйте объект только один раз, используя @JsonIdentityInfo и @JsonIdentityReference:

public class MyTest {

    @Test
    public void myTest() throws JsonProcessingException {
        final FixedContentsCase fcc = new FixedContentsCase();
        fcc.setId(Long.valueOf(1));
        final Item item = new Item();
        item.setId(Long.valueOf(2));
        item.setDescription("item 1");
        fcc.getItems().add(item);
        final ObjectMapper om = new ObjectMapper();
        System.out.println(om.writeValueAsString(fcc));
    }
}

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@JsonIdentityReference(alwaysAsId = false)
class Item extends StorageUnit {

    ...
}

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@JsonIdentityReference(alwaysAsId = false)
class FixedContentsCase extends StorageUnit {

    ...
}

abstract class StorageUnit {

    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...