Hi, guys !
In my opinion, JPA is a specification for stateless web app, and, of course, I will give two examples of that.
First at all, JPA doesn't provide
flushmode in
MANUAL.To second reason, I will have to write a little more.....
I think JSR 303 spec doesn't fix some validations issues in truly stateful apps.
Imagine we have this domain model:
Code:
@Entity
public class Person {
@javax.persistence.OneToMany(fetch = javax.persistence.FetchType.LAZY, cascade = CascadeType.ALL)
@Valid
java.util.List<Address> addresses = new java.util.ArrayList<Address>();
@javax.persistence.OneToMany(fetch = javax.persistence.FetchType.LAZY, cascade = CascadeType.ALL)
@Valid
java.util.List<PhoneNumber> phoneNumbers = new java.util.ArrayList<PhoneNumber>();
@org.hibernate.validator.NotEmpty
@Column(name = "name")
String name;
....
}
@Entity
public class Address {
@org.hibernate.validator.NotEmpty
@Column(name = "street")
String street;
.....
}
@Entity
public class PhoneNumber {
@org.hibernate.validator.NotEmpty
@Column(name = "phone")
String phone;
.....
}
Very simple, isn't it ? Well, we will continue with our mental experiment. Imagine I want to make a wizard with four steps:
First step: I will fill Person information
Second Step. I will fill one or many addresses of this person
Third Step. I will fill one or many phone numbers of this person
Fourth Step. I will show all the information and ask for confirmation.
Step 1, 2 and 3 will do exactly the same on
Next button:
Code:
public class persistPersonInfo() {
entityManager.persist(personInstance);
}
Next button on Step 4:
Code:
public class flushPersonInfo() {
entityManager.flush(personInstance);
}
As you can see, before finishing my wizard, I persist Person entity instance and all its addresses and phone numbers in
persistence context, NOT in
database, because I configured my
flushmode in MANUAL. Only when user confirms at the end of the wizard, I flush all information in database in one shot, as it should be.
Problem is validation.
Imagine in first step my user doesn't fill Persons name. Validation will fail, and will ask to user to fill Persons name... my user will fill Persons name and when he clicks Next, app will crash, because Person instance will be detached.
How I fixed it ? Very simple:
Code:
public class persistPersonInfo() {
ClassValidator personValidator=new ClassValidator(Person.class);
InvalidValues values=personValidator.getInvalidValues(personInstance);
if(invalidValues==0) {
entityManager.persist(personInstance);
}
}
It seems to be fixed, but it isn't. Problem is the second and third steps of wizard. Imagine that our user doesn't insert street information in second step, and press Next.I'm saving my addresses and phone numbers using
cascade, but Hibernate sometimes proxies addresses and phone numbers instances, so, when I persist Person and all related collections, validation doesn't work ( because validation annotations doesn't pass from original class to proxied class )
Ok, but JPA specification says we can use
EntityListeners. I change all my domain model classes adding
@EntityListeners(JPAValidateListener.class), and it seems to fixed everything.
NO !! Why ?
Imagine I develop a second wizard, to edit Person information, with same four steps, but showing Person information, and allowing user to edit it.
When I execute method persistPersonInfo() validation doesn't run, because JPA specification says validation will run in flush() method ( PrePersist and PreUpdate events ) ! But I want validation in persist(), in my first, second and third steps of my wizard, not at the end of it !
If I'm using frameworks like Spring, I have no problems, because usually I
persist AND flush in every step of my wizard ( not saving my state in persistence context, because it dissapears, but in another place ). But I'm using Seam, and I want to flush at the end of my wizard.
Another option is to use Interceptors, but I don't want to manage my transactions using Hibernate Transactions, I want to use Entity Manager Transaction ( according to JPA spec )
One last thing ... Emmanuel B, if you want to answer me, give me solutions, don't react as usually, saying I didn't understand something. And if I didn't understand, explain me WHAT I didn't understand, in order to help me. Thanks !
P.S. I'm sorry for my english !