According to the Glassfish 4.0 wiki, Glassfish 4.0 should include JSR349 Bean Validation 1.1.: GF4 wiki link
According to the JSR349 spec, CDI Injection should work out of the box: Bean Validation 1.1. CDI Integration
So I changed my pom.xml accordingly:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
<scope>provided</scope>
</dependency>
And tried injecting a CDI Bean into the ConstraintValidator:
public class UniqueEmaiValidator implements ConstraintValidator<UniqueEmail, String> {
@Inject
private UserAccountService accountService;
@Override
public void initialize(UniqueEmail constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return !accountService.userExistsByEmail(value);
}
}
However, when testing the application (Running Arquillian 1.1.1. with arquillian-glassfish-remote-3.1 1.0.0.CR4), the validation will always fail because userAccountService
is null and thus will throw a NullPointerException
eventually.
What am I missing to make the Bean Validation 1.1 work?
edit:
A) Can confirm it is not caused by the Arquillian remote test - will also throw a NPEx. when run on the server
B) Running on a GlassFish Server Open Source Edition 4.0 (build 89)
C) I re-built the bean-validation.jar explicitly using the 5.0.1.FINAL of Hibernate Validator. The mvn package
output:
[INFO] Building Validation API (JSR 349) version 1.1.0.Final, Hibernate Validator version 5.0.1.Final and its dependencies repackaged as OSGi bundle 2.1.92
Upon startup of the GlassFish server I get greeted with the following:
INFO: GlassFish Server Open Source Edition 4.0 (89) startup time : Felix (5,736ms), startup services(2,078ms), total(7,814ms)
INFO: HV000001: Hibernate Validator 5.0.1.Final
So I suppose the rebuilding did work. However, it did not resolve my issue of the NullPointerException :/
D) @Gunnar
This is the entity class, using a @Constraint
annotation:
@Entity
public class UserAccount extends AbstractEntity implements VisibilitySettings {
@UniqueEmail
private String email;
[...]
}
The Annotation itself:
@Constraint(validatedBy = {UniqueEmailValidator.class})
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueEmail {
String message() default "{validator.security.useraccount.emailexists}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
And the corresponding ConstraintValidator
:
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
@Inject
private UserAccountService accountService;
@Override
public void initialize(UniqueEmail constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return !accountService.userExistsByEmail(value);
}
}
The UserAccountService
is annotated with @ApplicationScoped @Transactional
CDI integration won't work out of the box when manually bootstrapping a validator via Validation.buildDefaultValidatorFactory()
.
When performing validation as part of the entity lifecycle via JPA, CDI integration should work; If it doesn't, there still might be an issue how Bean Validation is integrated into GlassFish. If this actually is the case, you might work around the issue by configuring a custom constraint validator factory in META-INF/validation.xml
which creates CDI managed validator instances.
For this, you may use the factory provided by Hibernate Validator's CDI integration as starting point. Note that the factory needs a default constructor though when configured via XML; to satisfy that requirement you could get a reference to the BeanManager
via JNDI.
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