I made a custom @UniqueNombre validator to check if an user name already exists in the database and, when it is not repeated and tries to persist the data it throws an Hibernate exception:
ERROR org.hibernate.AssertionFailure - HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in es.cesga.cloudpyme2.openinnovation.Usuario entry (don't flush the Session after an exception occurs)
The code of the validator is:
public class UniqueNombreValidator implements ConstraintValidator<UniqueNombre, String> {
@Override
public void initialize(UniqueNombre paramA) {
}
@Override
public boolean isValid(String nombre, ConstraintValidatorContext ctx) {
return (Usuario.countFindUsuariosByNombreEquals(nombre) == 0);
}
}
And the controller:
@RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String create(@Valid Usuario usuario, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
populateEditForm(uiModel, usuario);
return "usuario/create";
}
uiModel.asMap().clear();
setUpUsuario(usuario, httpServletRequest);
usuario.persist();
return "redirect:/usuario/" + encodeUrlPathSegment(usuario.getIdUsuario().toString(), httpServletRequest);
}
Without the check for a repeated user name, the controller works like charm. Any ideas?
UPDATE: Here is the method that is used inside the validator:
public static Long Usuario.countFindUsuariosByNombreEquals(String nombre) {
if (nombre == null || nombre.length() == 0) throw new IllegalArgumentException("The nombre argument is required");
EntityManager em = Usuario.entityManager();
TypedQuery q = em.createQuery("SELECT COUNT(o) FROM Usuario AS o WHERE o.nombre = :nombre", Long.class);
q.setParameter("nombre", nombre);
return ((Long) q.getSingleResult());
}
I cannot be sure without the full stacktrace, but it looks like you are trying to use the EntityManager
outside of a transaction. It is declared static in the Usuario
class, and called through a static method. But unless you declared a transaction in your controller (which would be uncommon), none is opened when you call em.createQuery(...)
, so Hibernate throws an exception.
As you only do readonly operation, a simple workaround is to use the open session in view pattern with an OpenSessionInViewFilter
. It allows for a (normally readonly) session to be disponible all along a request processing.