Issue
I'm using Hibernate with Panache and I need to add a user when the application starts.
For that, I'm annotating my bean with @Startup
and then I have a method with the annotation @PostConstruct
.
Currently, I'm using the following code:
@Startup
@ApplicationScoped
class AuthService {
@Inject
lateinit var userRepository: UserRepository
@PostConstruct
fun init() {
logger.info("Creating admin user")
val user = User(
"Admin", ADMIN_NAME, BcryptUtil.bcryptHash(ADMIN_PASS), mutableSetOf(Role.ADMIN)
)
Panache.withTransaction {
userRepository.persist(user)
}.subscribe().with({
logger.info("Done")
}, { fail ->
logger.error("Failed admin creation: $fail")
})
}
}
From what I found, when this method is called there are no guarantees that everything is already set, and I guess that is why it sometimes fails with the error Session/EntityManager is closed
.
I have already checked this question but since it is for Spring, the method doesn't work and I didn't find anything similar for Quarkus.
Am I missing any solution or is there a better approach to this?
Solution
This should work (I wrote it in Java because I'm not familiar with Kotlin):
@PostConstruct
public void init() {
logger.info( "Creating admin user" );
User user = new User(
"Admin", ADMIN_NAME, BcryptUtil.bcryptHash(ADMIN_PASS), mutableSetOf(Role.ADMIN)
);
Panache
.withTransaction( () -> userRepository.persist( user ) )
.onItemOrFailure().invoke( (v, e ) -> {
if (e != null) {
logger.info( "Done!" );
}
else {
logger.errorf( "Failed admin creation: %s", e );
}
} )
.await().indefinitely();
}
Note that this code is not reactive though. The .await().indefinitely()
will block the thread until the operation is completed.
The correct approach should be having a method like:
@PostConstruct
public Uni<Void> init() {
...
return Panache.withTransaction(...);
}
But this doesn't work at the moment in Quarkus.
Answered By - Davide D'Alto
Answer Checked By - Cary Denson (JavaFixing Admin)