@SoftDelete and Jakarta @PreRemove

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()));
        }
    }

}