Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to integrate JPA validation with CDI and Seam Validation

Regarding to my previous question, The JSR 303 bean validation, The extended ConstraintValidator cannot use the CDI, The Seam Validation Module give me a perfect solution for centralizing all JSF and EJB business validation with out repeating the code.

Anyhow when I try to let the JPA (EclipseLink) to perform the validation, the system give me as the following:

java.lang.IllegalStateException: WEB9031: WebappClassLoader unable to load resource [javax.enterprise.inject.spi.BeanManager], because it has not yet been started, or was already stopped

The full stack trace is as the following:-

Caused by: java.lang.IllegalStateException: WEB9031: WebappClassLoader unable to load resource [javax.enterprise.inject.spi.BeanManager], because it has not yet been started, or was already stopped
at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1401)
at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1359)
at org.jboss.seam.validation.InjectingConstraintValidatorFactory.getInstance(InjectingConstraintValidatorFactory.java:67)
at org.hibernate.validator.internal.engine.ConstraintTree.createAndInitializeValidator(ConstraintTree.java:346)
at org.hibernate.validator.internal.engine.ConstraintTree.getInitializedValidator(ConstraintTree.java:334)
at org.hibernate.validator.internal.engine.ConstraintTree.validateConstraints(ConstraintTree.java:155)
at org.hibernate.validator.internal.engine.ConstraintTree.validateConstraints(ConstraintTree.java:125)
at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:86)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:442)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:387)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:351)
at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:303)
at org.hibernate.validator.internal.engine.ValidatorImpl.validate(ValidatorImpl.java:133)
at org.eclipse.persistence.internal.jpa.metadata.listeners.BeanValidationListener.validateOnCallbackEvent(BeanValidationListener.java:84)
at org.eclipse.persistence.internal.jpa.metadata.listeners.BeanValidationListener.prePersist(BeanValidationListener.java:62)
at org.eclipse.persistence.descriptors.DescriptorEventManager.notifyListener(DescriptorEventManager.java:698)
at org.eclipse.persistence.descriptors.DescriptorEventManager.notifyEJB30Listeners(DescriptorEventManager.java:641)
at org.eclipse.persistence.descriptors.DescriptorEventManager.executeEvent(DescriptorEventManager.java:200)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectClone(UnitOfWorkImpl.java:4257)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNotRegisteredNewObjectForPersist(UnitOfWorkImpl.java:4234)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.registerNotRegisteredNewObjectForPersist(RepeatableWriteUnitOfWork.java:513)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(UnitOfWorkImpl.java:4176)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.persist(EntityManagerImpl.java:440)

I'm not sure if I can use the CDI with Constraint Validator together with JPA or not. Could you please help to advice further? Thank you very much for your help in advance. I'm looking forward to hearing from you soon.

My Environment is as follows:

  1. Windows 7 64 bits
  2. JDK 1.6.0_31 64 bits
  3. Eclipse Indigo SR1 64 bits
  4. Glassfish 3.1.2.2
  5. EclipseLink 2.3.2 (bundle with GF)
  6. Weld 1.1.10-Final
  7. Hibernate Valiation 4.3.0.Final
  8. Seam Solder 3.1.1.Final
  9. Seam Validation 3.1.0.Final

My example coding

The utility

@Singleton
public class MyUtility {
    public boolean isValid(final String input) {
       return (input != null) || (!input.trim().equals(""));
    }
}

The constraint annotation

@Retention(RetentionPolicy.RUNTIME)
@Target({
    ElementType.TYPE,
    ElementType.ANNOTATION_TYPE,
    ElementType.FIELD
    })
@Constraint(validatedBy = Validator.class)
@Documented
public @interface Validatable {
    String  message() default "Validation is failure";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

The constraint validator

public class Validator extends ConstraintValidator<Validatable, MyBean> {
    //
    //----> Try to inject the utility with Seam validation
    //
    @Inject
    private MyUtility myUtil;

    public void initialize(ValidatableconstraintAnnotation) {
        //nothing
    }

    public boolean isValid(final MyBean myBean, 
                           final ConstraintValidatorContext constraintContext) {

        if (myBean == null) {
            return true;
        }
        //
        //----> It works as expected, but not for the JPA layer
        //
        return this.myUtil.isValid(myBean.getName());
    }
}

The data bean as an Entity bean

@Entity
//--other JPA annotation
@Validatable
public class MyBean {
    private String name;
    //Getter and Setter here
}

The JSF backing bean

@Named
@SessionScoped
public class Page1 {
    //javax.validation.Validator
    @Inject
    private Validator validator;

    @Inject
    private MyBean myBean;

    @PersistenceContext(unitName = "mydb-pu")
    private EntityManager em;

    //Submit method
    public void submit() {
        Set<ConstraintViolation<Object>> violations = 
                         this.validator.validate(this.myBean);
        if (violations.size() > 0) {
            //Handle error here.
        }
        this.em.persist(this.myBean);
    }
}

The Persistence.xml

<persistence-unit name="mydb-pu"
    transaction-type="JTA">
    <jta-data-source>jdbc/mydb</jta-data-source>
    <class>...</class>

    <!-- If I comment this, the exception occurs -->
    <validation-mode>NONE</validation-mode>

    <properties>
        <property name="eclipselink.ddl-generation" value="create-tables"/>
        <property name="eclipselink.ddl-generation" value="none" />
        <property name="eclipselink.ddl-generation.output-mode" value="both"/>
    </properties>

</persistence-unit>

The 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.0.xsd">

    <constraint-validator-factory>
        org.jboss.seam.validation.InjectingConstraintValidatorFactory
    </constraint-validator-factory>
</validation-config>

Regarding to the mentioned Persistence.xml, if I remove the validation-mode, the system gives me an exception. At the moment, I disable the JPA validation as an interim solution.

like image 459
Charlee Chitsuk Avatar asked Oct 15 '12 11:10

Charlee Chitsuk


People also ask

What is JPA Validator?

Data validation is a common task that occurs in all layers of an application, including persistence. The Java™ Persistence API (JPA) 2.0 provides support for the Bean Validation API so that data validation can be done at run time.

What is Hibernate Validator used for?

Hibernate Validator allows to express and validate application constraints. The default metadata source are annotations, with the ability to override and extend through the use of XML. It is not tied to a specific application tier or programming model and is available for both server and client application programming.

Which of the following is type of bean validation method provided in Jersey?

Validation is the process of verifying that some data obeys one or more pre-defined constraints. It is, of course, a very common use case in most applications. The Java Bean Validation framework (JSR-380) has become the de-facto standard for handling this kind of operations in Java.

Is Hibernate Validator thread safe?

In the setUp() method, a Validator instance is retrieved from the ValidatorFactory . Validator instances are thread-safe and may be reused multiple times.


1 Answers

I came across this same issue and fixed it by adding:

<property name="javax.persistence.validation.factory" value="org.jboss.seam.validation.InjectingConstraintValidatorFactory"/>

to my persistence unit properties in the persistence.xml. Once you do that you can remove the validation-mode.

like image 179
NBW Avatar answered Oct 29 '22 03:10

NBW