Skip to main content

Using Bean Validation with EclipseLink in a Java SE Environment

Posted by lancea on May 6, 2010 at 10:31 AM PDT

The Bean Validation specification went final around the same time that the Java EE 6 specifications went final. The Java Persistence 2.0 specification allows for Managed classes (entities, mapped superclasses and embeddable classes) to be configured with Bean Validation constraints.

In this example we are going to use Eclipse Galileo which you can download and then install from here. You will also need to download the Bean Validation RI and Java DB.  

Once you have installed Eclipse, downloaded the Bean Validation RI and Java DB, you will want to create a JPA project, we called ours JPA-BeanValidation.
We will want to install Eclipselink 2.x in our project. You will do this by:

  • right clicking on the project
  • select properties
  • select Java Persistence
  • click the download library icon and choose Eclipselink 2.x to be installed

Screen shot 2010-05-06 at 9.34.24 AM

Next, you will need to include the Bean Validation RI and the derby jars in your project by:

  • right clicking on the project
  • select Java Build path
  • select add external jars
  • Include the following jars from the Bean Validation RI:
    • hibernate-validator-4.0.1.GA.jar
    • log4j-1.2.14.jar
    • slf4j-api-1.5.6.jar
    • slf4j-log4j12-1.5.6.jar
    • validation-api-1.0.0.GA.jar
  • Include the following jar(s) from your Java DB install:
    • derby.jar
    • derbyclient.jar(only if you decide to use the Derby Network Server)

Screen shot 2010-05-06 at 9.35.14 AM

To exercise Bean Validation with EclipseLink, we will create the following Entity which specifies that the field name cannot exceed 10 characters and that the id and name fields cannot be null:

package demo;
import java.io.Serializable;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

/**
* Entity implementation class for Entity: Player
*
*/
@Entity

public class Player implements Serializable {

       
        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @NotNull
        private int id;
       
        @NotNull
        @Size(max=10)
        private String name;
       
        public Player() {
       
        }
        public Player(String name) {
                this.setName(name);
        }

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

        public int getId() {
                return id;
        }

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

        public String getName() {
                return name;
        }
  
}

Create a client application to test that Bean Validation is enabled in Java SE:

package demo;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import demo.Player;

public class Client {
        private EntityManagerFactory emf;
        private EntityManager em;

        public Client() {
                emf = Persistence.createEntityManagerFactory("DerbyEmbeddedPU");
                em = emf.createEntityManager();
        }

       
        public static void main(String[] args) {
                Client pgm = new Client();
                pgm.run();
        }

        private void run() {
                em.getTransaction().begin();
                em.persist(new Player("Lance"));
                em.persist(new Player("Lance Andersen"));
                em.getTransaction().commit();

                List players = em.createQuery("Select p from Player p")
                                .getResultList();
                for (Player p : players) {
                        System.out.println("Player:" + p);
                }

        }

}

Here is the persistence.xml that is being used with the application:



" title="http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
">http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  " transaction-type="RESOURCE_LOCAL">
     org.eclipse.persistence.jpa.PersistenceProvider
    demo.Player
   
     
                                      value="jdbc:derby:/file/databases/testDB;create=true"/>
     
     
     
     
   

 

We are using the Java DB embedded JDBC driver and our database will be created when the application connects if it does not already exist. You will need to modify the properties to match what is required for your environment.

Validation will be automatically enabled because we added the Bean Validation RI to the classpath of our project. When we run the application we will get the following exception:

<[EL Config]: 2010-05-06 12:58:09.63--ServerSession(1464447632)--Thread(Thread[main,5,main])--The access type for the persistent class [class demo.Player] is set to [FIELD].
[EL Config]: 2010-05-06 12:58:09.654--ServerSession(1464447632)--Thread(Thread[main,5,main])--The alias name for the entity class [class demo.Player] is being defaulted to: Player.
[EL Config]: 2010-05-06 12:58:09.656--ServerSession(1464447632)--Thread(Thread[main,5,main])--The table name for entity [class demo.Player] is being defaulted to: PLAYER.
[EL Config]: 2010-05-06 12:58:09.665--ServerSession(1464447632)--Thread(Thread[main,5,main])--The column name for element [field id] is being defaulted to: ID.
[EL Config]: 2010-05-06 12:58:09.667--ServerSession(1464447632)--Thread(Thread[main,5,main])--The column name for element [field name] is being defaulted to: NAME.
log4j:WARN No appenders could be found for logger (org.hibernate.validator.util.Version).
log4j:WARN Please initialize the log4j system properly.
[EL Info]: 2010-05-06 12:58:10.402--ServerSession(1464447632)--Thread(Thread[main,5,main])--EclipseLink, version: Eclipse Persistence Services - 2.0.1.v20100213-r6600
[EL Fine]: 2010-05-06 12:58:11.317--Thread(Thread[main,5,main])--Detected Vendor platform: org.eclipse.persistence.platform.database.JavaDBPlatform
[EL Config]: 2010-05-06 12:58:11.332--ServerSession(1464447632)--Connection(1898052961)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
        platform=>JavaDBPlatform
        user name=> "APP"
        datasource URL=> "jdbc:derby:/Users/lanceandersen/Java_EE/glassfishv3/databases/testDB;create=true"
))
[EL Config]: 2010-05-06 12:58:11.334--ServerSession(1464447632)--Connection(2062322058)--Thread(Thread[main,5,main])--Connected: jdbc:derby:/Users/lanceandersen/Java_EE/glassfishv3/databases/testDB
        User: APP
        Database: Apache Derby  Version: 10.5.3.0 - (802917)
        Driver: Apache Derby Embedded JDBC Driver  Version: 10.5.3.0 - (802917)
[EL Config]: 2010-05-06 12:58:11.335--ServerSession(1464447632)--Connection(1060766226)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
        platform=>JavaDBPlatform
        user name=> "APP"
        datasource URL=> "jdbc:derby:/Users/lanceandersen/Java_EE/glassfishv3/databases/testDB;create=true"
))
[EL Config]: 2010-05-06 12:58:11.336--ServerSession(1464447632)--Connection(1062659565)--Thread(Thread[main,5,main])--Connected: jdbc:derby:/Users/lanceandersen/Java_EE/glassfishv3/databases/testDB
        User: APP
        Database: Apache Derby  Version: 10.5.3.0 - (802917)
        Driver: Apache Derby Embedded JDBC Driver  Version: 10.5.3.0 - (802917)
[EL Info]: 2010-05-06 12:58:11.367--ServerSession(1464447632)--Thread(Thread[main,5,main])--file:/Users/lanceandersen/Documents/workspace/JPA-BeanValidation/build/classes/_DerbyEmbeddedPU login successful
[EL Fine]: 2010-05-06 12:58:11.387--ServerSession(1464447632)--Connection(1062659565)--Thread(Thread[main,5,main])--DROP TABLE PLAYER
[EL Fine]: 2010-05-06 12:58:11.674--ServerSession(1464447632)--Connection(1062659565)--Thread(Thread[main,5,main])--CREATE TABLE PLAYER (ID INTEGER GENERATED ALWAYS AS IDENTITY NOT NULL, NAME VARCHAR(255), PRIMARY KEY (ID))
Exception in thread "main" javax.validation.ConstraintViolationException: Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'prePersist'. Please refer to embedded ConstraintViolations for details.
        at org.eclipse.persistence.internal.jpa.metadata.listeners.BeanValidationListener.validateOnCallbackEvent(BeanValidationListener.java:90)
        at org.eclipse.persistence.internal.jpa.metadata.listeners.BeanValidationListener.prePersist(BeanValidationListener.java:62)
        at org.eclipse.persistence.descriptors.DescriptorEventManager.notifyListener(DescriptorEventManager.java:670)
        at org.eclipse.persistence.descriptors.DescriptorEventManager.notifyEJB30Listeners(DescriptorEventManager.java:613)
        at org.eclipse.persistence.descriptors.DescriptorEventManager.executeEvent(DescriptorEventManager.java:200)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectClone(UnitOfWorkImpl.java:4231)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNotRegisteredNewObjectForPersist(UnitOfWorkImpl.java:4208)
        at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.registerNotRegisteredNewObjectForPersist(RepeatableWriteUnitOfWork.java:424)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(UnitOfWorkImpl.java:4148)
        at org.eclipse.persistence.internal.jpa.EntityManagerImpl.persist(EntityManagerImpl.java:368)
        at demo.Client.run(Client.java:31)
        at demo.Client.main(Client.java:25)

The error occurs because:

em.persist(new Player("Lance Andersen"));

specifies a value for the name field which exceeds the max length allowed due to the validation constraint specified which indicated that the maximum length was 10.

We can disable validation by adding the validation-mode element to the persistence.xml with a value of NONE:



" title="http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
">http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  " transaction-type="RESOURCE_LOCAL">
     org.eclipse.persistence.jpa.PersistenceProvider
    demo.Player
   NONE
   
     
                                      value="jdbc:derby:/file/databases/testDB;create=true"/>
     
     
     
     
   

 

The values that may be specified for the validation-mode element are:

  • AUTO (default if the validatione-mode element is not specified)
  • NONE
  • CALLBACK (enables validation but generates an error if their is no validation provider available)

When we re-run the application, we will no longer see the validation error due to validation being disabled:

[EL Config]: 2010-05-06 12:41:05.792--ServerSession(661272757)--Thread(Thread[main,5,main])--The access type for the persistent class [class demo.Player] is set to [FIELD].
[EL Config]: 2010-05-06 12:41:05.816--ServerSession(661272757)--Thread(Thread[main,5,main])--The alias name for the entity class [class demo.Player] is being defaulted to: Player.
[EL Config]: 2010-05-06 12:41:05.818--ServerSession(661272757)--Thread(Thread[main,5,main])--The table name for entity [class demo.Player] is being defaulted to: PLAYER.
[EL Config]: 2010-05-06 12:41:05.828--ServerSession(661272757)--Thread(Thread[main,5,main])--The column name for element [field id] is being defaulted to: ID.
[EL Config]: 2010-05-06 12:41:05.829--ServerSession(661272757)--Thread(Thread[main,5,main])--The column name for element [field name] is being defaulted to: NAME.
[EL Info]: 2010-05-06 12:41:06.403--ServerSession(661272757)--Thread(Thread[main,5,main])--EclipseLink, version: Eclipse Persistence Services - 2.0.1.v20100213-r6600
[EL Fine]: 2010-05-06 12:41:07.177--Thread(Thread[main,5,main])--Detected Vendor platform: org.eclipse.persistence.platform.database.JavaDBPlatform
[EL Config]: 2010-05-06 12:41:07.192--ServerSession(661272757)--Connection(1377144006)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
        platform=>JavaDBPlatform
        user name=> "APP"
        datasource URL=> "jdbc:derby:/Users/lanceandersen/Java_EE/glassfishv3/databases/testDB;create=true"
))
[EL Config]: 2010-05-06 12:41:07.194--ServerSession(661272757)--Connection(63323788)--Thread(Thread[main,5,main])--Connected: jdbc:derby:/Users/lanceandersen/Java_EE/glassfishv3/databases/testDB
        User: APP
        Database: Apache Derby  Version: 10.5.3.0 - (802917)
        Driver: Apache Derby Embedded JDBC Driver  Version: 10.5.3.0 - (802917)
[EL Config]: 2010-05-06 12:41:07.195--ServerSession(661272757)--Connection(1278499651)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
        platform=>JavaDBPlatform
        user name=> "APP"
        datasource URL=> "jdbc:derby:/Users/lanceandersen/Java_EE/glassfishv3/databases/testDB;create=true"
))
[EL Config]: 2010-05-06 12:41:07.196--ServerSession(661272757)--Connection(1278255007)--Thread(Thread[main,5,main])--Connected: jdbc:derby:/Users/lanceandersen/Java_EE/glassfishv3/databases/testDB
        User: APP
        Database: Apache Derby  Version: 10.5.3.0 - (802917)
        Driver: Apache Derby Embedded JDBC Driver  Version: 10.5.3.0 - (802917)
[EL Info]: 2010-05-06 12:41:07.227--ServerSession(661272757)--Thread(Thread[main,5,main])--file:/Users/lanceandersen/Documents/workspace/JPA-BeanValidation/build/classes/_DerbyEmbeddedPU login successful
[EL Fine]: 2010-05-06 12:41:07.245--ServerSession(661272757)--Connection(1278255007)--Thread(Thread[main,5,main])--DROP TABLE PLAYER
[EL Fine]: 2010-05-06 12:41:07.486--ServerSession(661272757)--Connection(1278255007)--Thread(Thread[main,5,main])--CREATE TABLE PLAYER (ID INTEGER GENERATED ALWAYS AS IDENTITY NOT NULL, NAME VARCHAR(255), PRIMARY KEY (ID))
[EL Fine]: 2010-05-06 12:41:07.615--ClientSession(1171248050)--Connection(1278255007)--Thread(Thread[main,5,main])--INSERT INTO PLAYER (NAME) VALUES (?)
        bind => [Lance]
[EL Fine]: 2010-05-06 12:41:07.749--ClientSession(1171248050)--Connection(1278255007)--Thread(Thread[main,5,main])--values IDENTITY_VAL_LOCAL()
[EL Fine]: 2010-05-06 12:41:07.772--ClientSession(1171248050)--Connection(1278255007)--Thread(Thread[main,5,main])--INSERT INTO PLAYER (NAME) VALUES (?)
        bind => [Lance Andersen]
[EL Fine]: 2010-05-06 12:41:07.774--ClientSession(1171248050)--Connection(1278255007)--Thread(Thread[main,5,main])--values IDENTITY_VAL_LOCAL()
[EL Fine]: 2010-05-06 12:41:08.019--ServerSession(661272757)--Connection(1278255007)--Thread(Thread[main,5,main])--SELECT ID, NAME FROM PLAYER
Player:demo.Player@3db158db
Player:demo.Player@4631ff23
AttachmentSize
JPA-BeanValidation.zip15.76 KB
Related Topics >>

Comments

Multiple validation points

Thanks for the concise post. However, I still have some doubts regarding bean validation and the place it occupies in the parameter validation chain of an enterprise application. I used to validate entities' fields in their "set' methods (things like nullity and min/max), but now that kind of verification along with bean validation turns the entity code into an unmaintainable, largely redundant thing. Besides that, they are different beasts, each taking place in a different point (bean validation during persistence, "set" validation during object construction/population). My question is, can the two methods coexist? How? Thanks a lot.

I have another question, that

I have another question, that when I catch the exception when persisting, how to output the custom validation message defined with constraints itself? Thanks.