Как обрабатывать оригинальный объект при обновлении, стоит ли клонировать объект перед сохранением
Что проверяют
Понимаете ли вы, откуда берутся побочные эффекты при общих изменяемых объектах, и знаете ли, что clone() в Java почти никогда не лучший ответ. Следом часто спрашивают, как это устроено в JPA.
Как отвечать
Сначала назовите, от чего защищаетесь: кто ещё держит ссылку на объект и может увидеть его в полуизменённом состоянии. Дальше варианты по степени предпочтительности:
- неизменяемые объекты:
record(с Java 16) или final-поля без сеттеров. Обновление создаёт новый экземпляр через конструктор или метод вродеwithAge(), и вопрос клонирования исчезает; - защитные копии: в конструкторе и геттерах копируйте изменяемые поля, коллекции через
List.copyOf(), который возвращает неизменяемый список; - копирующий конструктор или фабрика:
new User(other)явно показывает, что копируется глубоко, а что нет, и не тянет за собой checked-исключение; - DTO на входе: данные запроса приходят в DTO, а сущность обновляется точечно, вручную или через MapStruct. Так клиент не перезапишет поля, которые менять не должен.
Про Cloneable скажите прямо: это интерфейс без методов, Object.clone() делает поверхностную копию, возвращает Object, бросает CloneNotSupportedException и обходит конструкторы. В «Effective Java» его советуют избегать.
В JPA своя логика. Managed-сущность отслеживается Hibernate: изменения уходят в базу при flush без явного save(). Клон будет detached, и merge() вернёт новую managed-копию, а не ваш объект. Конкурентные обновления решает оптимистическая блокировка через @Version, а не копии.
Где спотыкаются
Клонируют через super.clone() объект с изменяемыми полями и считают копию независимой. Список внутри остаётся общим, и изменение в копии видно в оригинале.
Вызывают repository.save(copy) для detached-объекта и продолжают работать с исходной ссылкой. Managed стал объект, который вернул save(), а изменения в старой ссылке в базу уже не попадут.
Клонируют каждый объект перед сохранением «на всякий случай». Это лишние аллокации и ложное чувство безопасности: общее изменяемое состояние лечится дизайном, неизменяемостью и понятной границей владения, а не копированием.