Bean-Validation 1.1 in Glassfish 4.0 - CDI Injection not working as intended

南笙酒味 提交于 2019-12-04 11:35:42

问题


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


回答1:


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.




回答2:


I resolved. I created a Qualifier annotation:

@Qualifier   
@Retention(RUNTIME)   
@Target({TYPE,FIELD})   
public @interface Validation {

}

I annotated my ConstraintValidator:

@Validation 
public class MyValidatorImpl implements ConstraintValidator<MyValidator, MyBean> {

}

I created my ConstraintValidatorFactory:

public class CDIConstraintValidatorFactory implements ConstraintValidatorFactory {

    @Override
    public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> type) {
        try{

            T t = getBeanInstance(type);
            if(t==null){
                t = type.newInstance();
            }
            return t;
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }

    private BeanManager getBeanManager() throws NamingException {
            String name = "java:comp/" + BeanManager.class.getSimpleName();
            InitialContext ic = new InitialContext();
            BeanManager beanManager = (BeanManager) ic.lookup(name);
            return beanManager;
    }

    public <T> T getBeanInstance(final Class<T> type) throws Exception{
        BeanManager beanManager =  getBeanManager();
        Validation v = type.getAnnotation(Validation.class);
        if(v!=null){
            final Set<Bean<?>> beans = beanManager.getBeans(type,v);
            beanManager.resolve(beans);
            if(!beans.isEmpty()){
                final Bean<T> bean = (Bean<T>) beanManager.resolve(beans);
                final CreationalContext<T> creationalContext = beanManager.createCreationalContext(bean);
                return (T) beanManager.getReference(bean, type,creationalContext);
            }else{
                return null;
            }
        }else{
            return null;
        }
    }



}

and then i registried it my validation.xml:

<?xml version="1.0" encoding="UTF-8"?>
<validation-config    xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration validation-configuration-1.1.xsd">
        <constraint-validator-factory>xxx.be.framework.validator.CDIConstraintValidatorFactory</constraint-validator-factory>
</validation-config> 

regards, Giancarlo



来源:https://stackoverflow.com/questions/19925540/bean-validation-1-1-in-glassfish-4-0-cdi-injection-not-working-as-intended

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!