I have tried the new @SoftDelete annotation. This works so far, but unfortunately Jakarta @PreRemove is not triggered by it.
Or am I doing something wrong? Is there another annotation to fill e.g. a DeletedAt field with the date of the Delete?
I have tried the new @SoftDelete annotation. This works so far, but unfortunately Jakarta @PreRemove is not triggered by it.
Or am I doing something wrong? Is there another annotation to fill e.g. a DeletedAt field with the date of the Delete?
You’re not doing anything wrong, this sounds like a bug to me. Please try to create a reproducer with our test case template and if you are able to reproduce the issue, create a bug ticket in our issue tracker and attach that reproducer.
I have the same aim. I found that it is not @PreRemove not work. @PreRemove worked but the data not update to the database (Maybe because hibernate think it is a remove operation). I use EntityManager in EntityListener to sovle it. like follow:
@ToString(onlyExplicitlyIncluded = true)
@Getter
@MappedSuperclass
@EntityListeners({AuditingEntityListener.class, DeletedDateEntityListener.class})
@SoftDelete
public abstract class AbstractEntity extends AbstractAggregateRoot<AbstractEntity> implements Serializable {
@Serial
private static final long serialVersionUID = 6798146935361596394L;
...
@Setter
@Column(name = "deleted_date")
private Instant deletedDate;
...
}
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class DeletedDateEntityListener {
private final EntityManager entityManager;
@PreRemove
void preRemove(final Object object) {
if (object instanceof final AbstractEntity entity) {
entity.setDeletedDate(Instant.now());
entityManager.merge(entity);
entityManager.flush();
}
}
}
I found the previous code with cascade will have error, finally I use jdbc to operate the field.
I do not know if it is a better way.
@RequiredArgsConstructor(onConstructor_ = @Lazy)
public class DeletedDateEntityListener {
private final JdbcTemplate jdbcTemplate;
@PreRemove
void preRemove(final Object object) {
if (object instanceof final AbstractEntity entity) {
final var entityClass = entity.getClass();
final var allSuperclasses = ClassUtils.getAllSuperclasses(entityClass);
final var firstEntityClass = Stream.concat(allSuperclasses.stream(), Stream.of(entityClass))
.filter(c -> c.getAnnotation(Entity.class) != null)
.findFirst()
.orElseThrow();
final var annotation = firstEntityClass.getAnnotation(Table.class);
final String tableName;
if (annotation != null) {
tableName = annotation.name();
} else {
tableName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, firstEntityClass.getSimpleName());
}
jdbcTemplate.execute(
"UPDATE %s SET deleted_date=UTC_TIMESTAMP() WHERE id=%d".formatted(tableName, entity.getId()));
}
}
}