Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate model data with JPA?

I am trying to get JPA validation to work, however it seems that the validation annotations are ignored. I found this example of JPA validation on SO: JPA Entity Validation, but it does not work for me. The @NotNull and @Size annotations seem to be ignored.

As in the answer mentioned above I use only two classes:

Customer.java:

package com.validation.test;

import javax.persistence.*;
import javax.validation.constraints.*;

@Entity
@Table(name = "T_CUSTOMER")
public class Customer {
    @Id
    @NotNull
    @SequenceGenerator(name = "customerIdSeq", sequenceName = "T_CUSTOMER_ID_SEQ", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "customerIdSeq")
    private Long id;

    @NotNull
    @Size(min = 3, max = 80)
    private String name;

    public Customer() {};

    public Customer(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }    
}

CustomerTest.java:

package com.validation.test.test;

import static org.junit.Assert.*;

import javax.persistence.*;
import javax.validation.*;
import javax.validation.constraints.Size;

import org.junit.*;

import com.validation.test.Customer;

public class CustomerTest {
    private static EntityManagerFactory emf;
    private EntityManager em;

    @BeforeClass
    public static void createEntityManagerFactory() {
        emf = Persistence.createEntityManagerFactory("testPU");
    }

    @AfterClass
    public static void closeEntityManagerFactory() {
        emf.close();
    }

    @Before
    public void beginTransaction() {
        em = emf.createEntityManager();
        em.getTransaction().begin();
    }

    @After
    public void rollbackTransaction() {
        if (em.getTransaction().isActive()) {
            em.getTransaction().rollback();
        }
        if (em.isOpen()) {
            em.close();
        }
    }

    @Test
    public void nameTooShort() {
        try {
            Customer customer = new Customer("bo");
            em.persist(customer);
            em.flush();
            fail("Expected ConstraintViolationException wasn't thrown.");
        } catch (ConstraintViolationException e) {
            assertEquals(1, e.getConstraintViolations().size());
            ConstraintViolation<?> violation = e.getConstraintViolations().iterator().next();

            assertEquals("name", violation.getPropertyPath().toString());
            assertEquals(Size.class, violation.getConstraintDescriptor().getAnnotation().annotationType());
        }
    }
}

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.validation.test</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>    
    <repositories>
        <repository>
            <id>maven2-repository.java.net</id>
            <name>Java.net Repository for Maven</name>
            <url>http://download.java.net/maven/2/</url>
            <layout>default</layout>
        </repository>    
    </repositories>    
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>1.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.oracle</groupId>
                <artifactId>ojdbc5</artifactId>
            <version>11.2.0.2.0</version>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0.GA</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.0.3.Final</version>
            <scope>test</scope>
        </dependency>
    </dependencies>    
    <build>
        <finalName>wwd-bs</finalName>
        <pluginManagement>
            <plugins>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.1</version>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.16</version>
                </plugin>    
            </plugins>
        </pluginManagement>    
    </build>
</project>

persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
    xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="testPU" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.validation.test.Customer</class>
        <properties>
            <property name="eclipselink.logging.level" value="FINE" />
            <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
            <property name="javax.persistence.jdbc.user" value="user" />
            <property name="javax.persistence.jdbc.password" value="password" />
            <property name="eclipselink.logging.level" value="INFO" />
        </properties>
    </persistence-unit>
</persistence>

The test fails at the fail(...) so the exception is never thrown.

How can I make (any) validation work with JPA? I cannot use Hibernate or Spring.

Thank you for your help

EDIT: added hibernate-validator to pom.xml (with no effect)

like image 918
svenhuebner Avatar asked Feb 19 '14 08:02

svenhuebner


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 the use of @valid annotation?

The @Valid annotation ensures the validation of the whole object. Importantly, it performs the validation of the whole object graph. However, this creates issues for scenarios needing only partial validation. On the other hand, we can use @Validated for group validation, including the above partial validation.

What is @email annotation in Spring boot?

@Email annotation is part of javax. validation. constraints package. Using Just @Email annotation like below @Data.


2 Answers

Add this to your pom.xmls.

     <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>4.2.0.Final</version>
        <exclusions>
            <exclusion>
                <groupId>javax.xml.bind</groupId>
                <artifactId>jaxb-api</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.sun.xml.bind</groupId>
                <artifactId>jaxb-impl</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.0.0.GA</version>
    </dependency>

And set validation property to AUTO this must to be enable in persistence.xml

<property name="javax.persistence.validation.mode" value="AUTO" />

Or do it progrmatically.

final Set<ConstraintViolation<Object>> errors = validator.validate(object, classes);
like image 138
Koitoer Avatar answered Sep 28 '22 18:09

Koitoer


Do you have a runtime implementation of the validator on your classpath? Typically people seem to use hibernate validator. (e.g. indeed by adding hibernate-validator to your pom.xml)

edit: Your version of EclipseLink also looks quite old, it should be a JPA2 implementation. If it is a JPA1 implementation, you should register your own event listener, which will be a bit more work. You can find some hints in the eclipse docs (scroll down to JPA section), but it looks like you'll have to slightly edit the standard validators to make it work. This blog might be helpful.

like image 41
wds Avatar answered Sep 28 '22 17:09

wds