Спящий режим пользователя и друзей JsonReference

#java #json #hibernate #jackson

#java #json #переход в спящий режим #джексон

Вопрос:

У меня есть две таблицы: Users и User_Friend для отображения связей с полями добавления.

 CREATE TABLE public.users
(
  uuid              VARCHAR(36) PRIMARY KEY                     NOT NULL,
  username          VARCHAR(45) UNIQUE                          NOT NULL,
  first_name        VARCHAR(255)                                NOT NULL,
  last_name         VARCHAR(255),
  middle_name       VARCHAR(255)
);



CREATE TABLE public.user_friends
(
  uuid          VARCHAR(36) PRIMARY KEY,
  user_uuid     VARCHAR(36) REFERENCES public.users (uuid) NOT NULL,
  friend_uuid   VARCHAR(36) REFERENCES public.users (uuid) NOT NULL,
  friendAddDate TIMESTAMP                                  NOT NULL,
  friendTypeId  INT                                        NOT NULL,
  CONSTRAINT friend_unique UNIQUE (user_uuid, friend_uuid)
);
  

Объекты Java с аннотациями гибернации:

 @Entity
@Table(name = "users")
public class User implements Serializable {

    @Id
    @GeneratedValue(generator = "system-uuid", strategy = GenerationType.IDENTITY)
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @Column(name = "uuid", unique = true)
    protected String uuid;

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

    @JsonManagedReference
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<UserFriend> userFriends = new HashSet<>();

@JsonManagedReference
@OneToMany(fetch = FetchType.LAZY, mappedBy = "friendUser", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<UserFriend> userFriendOf = new HashSet<>();

}

@Entity
@Table(name = "user_friends")
@AssociationOverrides({
        @AssociationOverride(name = "user",
                joinColumns = @JoinColumn(name = "user_uuid")),
        @AssociationOverride(name = "friendUser",
                joinColumns = @JoinColumn(name = "friend_uuid")) })
public class UserFriend implements Serializable {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @Column(name = "uuid", unique = true)
    protected String uuid;

    @JsonBackReference
    @ManyToOne(optional = false)
    @JoinColumn(name="user_uuid")
    private User user;

    @JsonBackReference
    @ManyToOne(optional = false)
    @JoinColumn(name="user_uuid")
    private User friendUser;

    @Column(name = "friendadddate")
    protected Date friendAddDate;

    @Column(name = "friendtypeid")
    protected int friendTypeId;
}
  

Я пытаюсь решить проблему с рекурсией при десериализации в JSON, я добавил @JsonManagedReference к набору userFriends и userFriendOf пользовательского класса и @JsonBackReference к объектам user и friendUser класса UserFriend, и теперь в JSON на JSP у меня нет полей ни friendUser, ни user.

Но в этом случае — без установки friendsOf в классе User в JSON я могу использовать friendsuser класса UserFriend.

 @Entity
@Table(name = "users")
public class User implements Serializable {

    @Id
    @GeneratedValue(generator = "system-uuid", strategy = GenerationType.IDENTITY)
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @Column(name = "uuid", unique = true)
    protected String uuid;

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

    @JsonManagedReference
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<UserFriend> userFriends = new HashSet<>();

}

@Entity
@Table(name = "user_friends")
@AssociationOverrides({
        @AssociationOverride(name = "user",
                joinColumns = @JoinColumn(name = "user_uuid")),
        @AssociationOverride(name = "friendUser",
                joinColumns = @JoinColumn(name = "friend_uuid")) })
public class UserFriend implements Serializable {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid2")
    @Column(name = "uuid", unique = true)
    protected String uuid;

    @JsonBackReference
    @ManyToOne(optional = false)
    @JoinColumn(name="user_uuid")
    private User user;

    @ManyToOne(optional = false)
    @JoinColumn(name="user_uuid")
    private User friendUser;

    @Column(name = "friendadddate")
    protected Date friendAddDate;

    @Column(name = "friendtypeid")
    protected int friendTypeId;
}
  

Итак, мой вопрос в том, что я должен сделать, чтобы получить friendUser и user во всех наборах пользовательского класса?

Ход обновления: я гуглю информацию о своем вопросе и два дня подряд вижу первую (вторую) ссылку в Google — этот вопрос… 😉 Я все еще не могу решить свою проблему с режимами jsonreference. Я начинаю думать об изменении архитектуры базы данных.

Ответ №1:

Я сделал это. Снова. StackOverflow дает мне больше мотивации, чем проблемы: D

Итак, после 3 долгих дней ежечасных размышлений о моей проблеме я почти отказался от десериализации в json и принял решение не использовать json в этом случае, но затем я подумал о jsonidentity класса, и это мое решение.

Используя JsonIdentityInfo, каждый раз, когда Jackson сериализует ваш объект, он будет добавлять к нему идентификатор (в моем случае это uuid), так что он не будет сканировать его снова всегда.

ОБНОВИТЕ ASNWER (я удалил предыдущую версию ответа для сокращения ответа): К сожалению, когда я тестировал свое решение в разных случаях, я обнаружил, что оно работает только для первой версии json identity. Итак, первое «сканирование» полностью работает как шарм, но вместо второго сканирования я получил идентификатор jsonidentity вместо object. Это дает мне понимание, что мне нужна моя собственная логика сериализации, где я могу контролировать глубину рекурсии. И я написал это. Я могу показать только скелет пользовательского сериализатора json, потому что логика сериализации проста и зависит от структуры класса.

 public class JsonUserSerializer extends JsonSerializer<User> {
        @Override
        public void serialize(User o, JsonGenerator jsonGen, SerializerProvider serializerProvider)
                throws IOException, JsonProcessingException {
            // ... logic of json generation
            Field[] userClassFields = o.getClass().getDeclaredFields();
            // ... logic of json generation
        }

        @Override
        public Class<User> handledType() {
            return User.class;
        }
    }
  

Основная проблема, которую мне приходится решать при работе над кодом, это присвоение имен полям. Поскольку структура json такова: «name»: «value» — а в моем случае name — это fieldName. Но жестко закодировать это не мой способ. Чем я нашел решение для получения ВСЕХ полей класса, которым он является o.getClass().getDeclaredFields() , и чем требуется поиск поля по индексу. Я думаю, что это не лучшее решение, но я не нашел другого в течение часа (если вы знаете другой способ — напишите комментарий — я поблагодарю автора за это).

Забыли показать, как использовать пользовательский JsonSerialiser, который указан для определенного класса:

 @Entity
@Table(name = "users")
@JsonSerialize(using = JsonUserSerializer.class)
public class User implements Serializable {
    // a lot of fields and getter, and setters
}