Двунаправленная ассоциация Hibernate и TomEE + вызывает рекурсивность JSON - PullRequest
0 голосов
/ 17 декабря 2018

Я использую TomEE 9.0.12 с Hibernate 5.3.7 и в настоящее время получаю исключение stackoverflow из-за рекурсивности json.Обратите внимание, что я не использую Джексона, и в идеале не хочу, но стандарт, который поставляется с TomEE +: org.apache.johnzon.

Исключение:

Caused by: java.lang.StackOverflowError
    at org.apache.johnzon.mapper.Mappings.findOrCreateClassMapping(Mappings.java:340)
    at org.apache.johnzon.mapper.MappingGeneratorImpl.doWriteObjectBody(MappingGeneratorImpl.java:240)

Вот мой класс User.java:

import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

/**
 * A user
 */
@Entity
@Table(name = "users")
public class User implements Serializable {

    private static final long serialVersionUID = -9012412584251217L;

    // TODO: 16/12/2018 they keep nesting each other: { user { posts { user { posts } } }  }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "username")
    private String username;

    @Column(name = "email")
    private String email;

    @Column(name = "password")
    private String password;

    @Column(name = "salt")
    private String salt;

    @OneToMany(mappedBy = "user")
    private Set<Post> posts = new HashSet<>();

    /**
     * Constructs an empty user (for persistence purposes)
     */
    public User() {}

    // Setters and getters removed for convenience
}

А вот мой Post.java

import javax.persistence.*;
import java.io.Serializable;

/**
 * Project created by ExpDev
 */
@Entity
@Table(name = "posts")
public class Post implements Serializable {

    private static final long serialVersionUID = -9887234238952234L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @Column(name = "data")
    private String data;

    /**
     * Constructs an empty post (for persistence purposes)
     */
    public Post() {}

    // Setters and getters removed for convenience
}

Проблема

Проблема в том, что они будут продолжать ссылаться друг на друга.Пользователь будет ссылаться на сообщения, которые будут ссылаться на пользователя, который снова будет ссылаться на сообщения - и поэтому злой круг продолжается.

Я знаю, что могу использовать аннотацию org.apache.johnzon @JsonbTransient для «user» в User.java, чтобы она не сериализовалась, но это делает так, чтобы она никогда не отображалась (чего я хочу, но условно).Почему я хочу это так?

Поскольку, скажем, к GET / users / 1 обращаются, 1 является идентификатором пользователя, я хочу показать все сообщения пользователя (или хотя бы их идентификатор).), но не хочу, чтобы он ссылался на пользователя (вложенный пользователь внутри сообщения внутри пользователя).

Однако, если GET / api / posts / 3, 3 - это идентификатор, я хочу, чтобы он отображалсяпользователь, который сделал пост, но не посты снова внутри пользователя.

Таким образом, аннотации должны быть условными и конкретными.В настоящее время именно так я получаю и показываю пользователя (фреймворк автоматически преобразовывает возвращаемый объект в JSON при обращении к методу).

@GET
@Path("/{id}")
public User get(@PathParam("id") Long id) {
    // Find the user and return them
    return HiberUtil.getSession().get(User.class, id);
}

Заранее спасибо!Я искал 5 часов, но ни одно из решений или материалов для чтения не помогло решить мою проблему.

Ответы [ 2 ]

0 голосов
/ 06 августа 2019

Для справки, johnzon поддерживает обработку ссылок с помощью опции deduplicateObjects в mapper (tomee 7) и свойства johnzon.deduplicateObjects (tomee 8, meecrowave и т. Д.).Это решает эту проблему, заменяя уже просмотренные ссылки jsonpointer.

0 голосов
/ 18 декабря 2018

Я исправил это, просто переместившись из TomEE + в Spring Framework (со встроенным сервером Tomcat), который использует Джексона по умолчанию вместо "org.apache.johnzon. С этим я смог использоватьполезные аннотации:

@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class,
  property = "id")
@JsonIdentityReference(alwaysAsId=true)
private List<Post> posts;

Это сделано для того, чтобы JSON выглядел так:

{
    "username":"test",
    "posts": [2, 5, 6, 8, 2]
}

И так же для Пользователя внутри Post, если он также помечен этими аннотациямиЭто именно то, что я хотел, и то, как я использую интерфейсный веб-фреймворк, EmberJS, и многие другие, ожидают, что данные будут возвращены. Так что это идеально для меня. Кроме того, после небольшой игры с Spring на некоторое время свстроенный сервер Tomcat, мне он тоже больше нравится (я тоже прошел через Glassfish, но мне это не понравилось).

Важно отметить, что исправление было не потому, что я перешел наВесной, но вместо этого я использовал Джексона. Если вы все еще хотите использовать TomEE +, вы можете просто посмотреть https://stackoverflow.com/a/38915278/7120095, как использовать Джексона вместо johnzon с TomEE.

...