#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
}