This is my entity:
@Builder
@Data
@Entity
@Table(name = "audit_log")
public class AuditEventEntity {
@Id
@GeneratedValue
private UUID id;
private long createdEpoch;
@NotNull
@Size(min = 1, max = 128)
private String label;
@NotNull
@Size(min = 1)
private String description;
}
And this is my repository:
@Repository
public interface AuditEventRepository extends PagingAndSortingRepository<AuditEventEntity, UUID> {
}
When I write the following unit test for the repository, the save is successful even though the "label" field is null!
@DataJpaTest
@RunWith(SpringRunner.class)
public class AuditRepositoryTest {
@Test
public void shouldHaveLabel() {
AuditEventEntity entity = AuditEventEntity.builder()
.createdEpoch(Instant.now().toEpochMilli())
.description(RandomStringUtils.random(1000))
.build();
assertThat(entity.getLabel()).isNullOrEmpty();
AuditEventEntity saved = repository.save(entity);
// Entity saved and didn't get validated!
assertThat(saved.getLabel()).isNotNull();
// The label field is still null, and the entity did persist.
}
@Autowired
private AuditEventRepository repository;
}
Whether I use @NotNull
or @Column(nullable = false)
the database is created with the not null
flag on the column:
Hibernate: create table audit_log (id binary not null, created_epoch bigint not null, description varchar(255) not null, label varchar(128) not null, primary key (id))
I thought the validators would work automatically. What am I doing wrong here?
I thought the validators would work automatically. What am I doing wrong here?
You save the entity but you don't flush the state of the current entity manager.
So the validation of the entity is not performed yet.
You can refer to the Hibernate validator FAQ :
Why is my JPA entity not validated when I call persist()?
Why is my JPA entity not validated when I call
persist()
? The short answer is callEntityManager#flush()
if you want the validation to be triggered.Hibernate ORM and a few other ORMs try to batch as many operations as possible when accessing the database. It is likely that the actual entity "persist" operation only happens when you call
flush()
or when the transaction commits.Also, knowing which entity is about to be persisted depends on your cascading strategy and the state of your object graph. Flush is when Hibernate ORM identifies all the entities that have been changed and require database actions (see also HHH-8028).
So use JpaRepository.saveAndFlush()
instead of JpaRepository.save()
to allow the entity to be validated.
Or alternatively inject an EntityManager
or an TestEntityManager
in the test class, invoke JpaRepository.save()
and then invoke EntityManager/TestEntityManager.flush()
.
For information :
JpaRepository.save()
invokes em.persist(entity)
/em.merge(entity)
JpaRepository.saveAndFlush()
invokes JpaRepository.save()
and then em.flush()
To be able to invoke saveAndFlush()
, you have to make your Repository interface extend JpaRepository
such as :
public interface AuditEventRepository extends JpaRepository<AuditEventEntity, UUID> {
As JpaRepository
extends PagingAndSortingRepository
, this change stays consistent with your existing declaration.
I would add that this assertion is not required :
assertThat(saved.getLabel()).isNotNull();
What you want to assert is that ValidationException
is thrown and maybe that it contains the actual error message.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With