I'm the person behind annotations in Hibernate: Hibernate Annotations, Hibernate EntityManager, Hibernate Validator and Hibernate Search. I am a member of the JPA 2.0 expert group as well as the JSR-303 Bean validation spec lead. You can check out my book Hibernate Search in Action by Manning.
| Recent Entries |
|
27. Feb 2010
|
|
|
25. Feb 2010
|
|
|
03. Dec 2009
|
|
|
02. Dec 2009
|
|
|
18. Nov 2009
|
|
|
11. Nov 2009
|
|
|
13. Oct 2009
|
|
|
20. Jul 2009
|
|
|
12. Jun 2009
|
|
|
30. May 2009
|
|
|
31. Mar 2009
|
|
|
12. Feb 2009
|
|
|
06. Jan 2009
|
|
|
04. Dec 2008
|
|
|
17. Nov 2008
|
It was bound to happen, the minute I announced the Wicket integration, I've received a few emails describing integrations with other frameworks (like Tapestry). I've created a wiki page to list all frameworks integrating Bean Validation and a pointer to their documentation. Go ahead and fill it up with any active integration you are aware of. The page is here.
People following our work and vision on Bean Validation know that the ultimate goal is to get the ecosystem of Java frameworks to natively integrate Bean Validation where it makes sense. A particularly important area is the the presentation layer that should call Bean Validation to validate the values to be put in the domain model.
This is a feature we have added in JSF 2 and I am happy to see the model being embraced by other frameworks. A new addition to the game is Wicket: Zenika has created a project to integrate Bean Validation in Wicket just like we did for JSF. It's all explained here.
If I may, my next wish is to get rid of this annoying lonely line:
personForm.add(new JSR303FormValidator());
Just get it to work out of the box :) Aside from this detail, this is exactly how a component based framework should integrate Bean Validation. great work.
Now that Bean Validation is officially part of Java EE 6 and that Java EE6 is officially voted YES, let's see how Bean Validation integrates with the rest of the eco system.
What is Bean Validation
It's goal is to let application developers declare their data constraints once by annotating their model and make sure these constraints are validated by the different layers of the application in a consistent manner. Without Bean Validation, people have to write their validation rules in their favorite presentation framework, then in their business layer, then in their persistent layer, to some degree in the database schema and keep all of them synchronized.
Here is how this centralized constraint declaration looks like:
class User {
@NotEmpty @Size(max=100)
String getLogin() { ... }
@NotEmpty @Size(max=100)
String getFirstname() { ... }
@Email @Size(max=250)
String getEmail() { ... }
...
}
There are many more features like constraint composition, grouping but let's focus on how Bean Validation integrates with the EE 6 stack.
So what do I have to do to make it work in Java EE 6
The short answer is nothing. Not even an XML configuration trick.
Simply add your constraints on your domain model and the platform does the rest for you.
JSF and how to expose constraint violations to the user
In JSF, you bind form inputs to properties of your domain model. JSF 2 and Bean Validation smartly figure out which property you are binding to and execute the constraints associated to it.
<h:form id="register">
<div style="color: red">
<h:messages id="messages" globalOnly="true"/>
</div>
<div>
Login:
<h:inputText id="login" value="#{identifier.user.login}"/>
<h:message style="color: red" for="login"/>
<br/>
Password:
<h:inputSecret id="password" value="#{identifier.user.password}"/>
<h:message style="color: red" for="password"/>
<br/>
Firstname:
<h:inputText id="firstname" value="#{identifier.user.firstname}"/>
<h:message style="color: red" for="firstname"/>
<br/>
Email:
<h:inputText id="email" value="#{identifier.user.email}"/>
<h:message style="color: red" for="email"/>
<br/>
<h:commandButton id="Login" value="Login" action="#{identifier.register}"/>
<br/>
<h:button id="cancel" value="Cancel" outcome="/home.xhtml"/>
</div>
</h:form>
If the email, for example is malformed and the first name is left empty, Bean Validation will return the constraint violations to JSF 2 that will expose them to the user in a localized error message. By default, it just works and you don't even have to think about it.
For more advanced use cases, like disabling constraint validation for one or several fields or using a specific group or set of groups instead of the default one, you can use the <f:validateBean/> tag (check line 8 and 20 in the following example).
<h:form id="register">
<div style="color: red">
<h:messages id="messages" globalOnly="true"/>
</div>
<div>
<!-- ***** use a specific group ***** -->
<f:validateBean validationGroups="${identifier.validationGroups}">
Login:
<h:inputText id="login" value="#{identifier.user.login}"/>
<h:message style="color: red" for="login"/>
<br/>
Password:
<h:inputSecret id="password" value="#{identifier.user.password}"/>
<h:message style="color: red" for="password"/>
<br/>
Firstname:
<!-- ***** disable validation for firstname ***** -->
<h:inputText id="firstname" value="#{identifier.user.firstname}">
<f:validateBean disabled="true"/>
</h:inputText>
<h:message style="color: red" for="firstname"/>
<br/>
Email:
<h:inputText id="email" value="#{identifier.user.email}"/>
<h:message style="color: red" for="email"/>
<br/>
<h:commandButton id="Login" value="Login" action="#{identifier.register}"/>
<br/>
<h:button id="cancel" value="Cancel" outcome="/home.xhtml"/>
</f:validateBean>
</div>
</h:form>
In the future, we want to work with RichFaces so that the constraints declared on the object model are validated in the JSF components on the client side. This is something we had prototyped already and that Pete, Dan and I proposed to the JSF 2 expert group initially but we had to scale down our ambitions :) Expect some innovations from us in this area.
But not all your data comes from the presentation layer.
JPA 2: last line of defense
Again, by default, your JPA 2 provider runs Bean Validation on the entities you are about to persist or update. You are then guaranteed to not put invalid data in your database and thus increasing the quality of your data overall. Oh, and these are the same constraints you would have validated in JSF 2.0.
You can disable validation in JPA 2 using the validation-mode element in persistence.xml or the javax.persistence.validation.mode property and set them to none. More interestingly, you can chose which group will be validated upon entity persist, update and even delete operations. By default, the Default group is validated when you persist or update entities. Use any one of these properties to adjust that.
<property name="javax.persistence.validation.group.pre-persist"
value"javax.validation.groups.Default, com.acme.model.Structural"/>
<property name="javax.persistence.validation.group.pre-update"
value"javax.validation.groups.Default, com.acme.model.Structural"/>
<property name="javax.persistence.validation.group.pre-delete"
value"com.acme.model.SafeDestruct"/>
Hibernate Core and Hibernate Validator go a bit beyond that and propagate the constraints to the database schema (provided that you let Hibernate Core generate or update the schema for you). Simply set the hibernate.hbm2ddl.auto property to create, update or create-drop.
How about my service layer
You can inject a Validator or ValidatorFactory instance in any injectable POJO in Java EE 6.
class SalesService {
@Inject Validator validator;
@Inject @Current User user;
public boolean canBuyInOneClick() {
return validator.validate(user, BuyInOneClick.class).size() == 0;
}
Where can I try it?
All of this is now available in JBoss AS 6 M1 that have just been released. Enjoy!
One of the innovations we have brought to Hibernate Search is an alternative way to define the mapping information: a programmatic API.
The traditional way to map an entity into Hibernate Search is to use annotations. And it's perfectly fine for 95% of the use cases. In some cases though, some people had had a need for a more dynamic approach:
- they use a metamodel to generate or customize what is indexed in their entities and need to reconfigure things either on redeployment or on the fly based on some contextual information.
- they ship a product to multiple customers that require some customization.
What people asked for: the XML Way(tm)
For a while, people with this requirement have asked for an XML format equivalent to what annotations could do. Now the problem with XML is that:
- it's very verbose in it's way to duplicate the structural information of your code
<class name="Address">
<property name="street1">
<field>
<analyzer definition="ngram"/>
</field>
</property>
<!-- ... -->
</class>
- while XML itself is type-safe, XML editors are still close to stone age, and developers writing XML in notepad are unfortunately quite common
- even if XML is type-safe, one cannot refactor the Java code and expect to get compile time errors or even better automatic integrated refactoring. For example, if I rename Address to Location, I still need to remember to change this in my xml file
- and finally, dynamically generating an XML stream to cope with the dynamic reconfiguration use case is not what I would call an intuitive solution
So we took a different road.
What they get: a fluent programmatic API
Instead of writing the mapping in XML, let's write it in Java. And to make things easier let's use a fluent contextual API (have intuitive method names, only expose the relevant operations).
SearchMapping mapping = new SearchMapping();
mapping
.analyzerDef( "ngram", StandardTokenizerFactory.class )
.filter( LowerCaseFilterFactory.class )
.filter( NGramFilterFactory.class )
.param( "minGramSize", "3" )
.param( "maxGramSize", "3" )
.entity(Address.class)
.indexed()
.property("addressId", METHOD)
.documentId()
.property("street1", METHOD)
.field()
.field()
.name("street1_ngram")
.analyzer("ngram")
.property("country", METHOD)
.indexedEmbedded()
.property("movedIn", METHOD)
.dateBridge(Resolution.DAY);
As you can see, it's very easy to figure out what is going on here. But something you cannot see in this example is that your IDE only offers the relevant methods contextually. For example, unless you have just declared a property(), you won't be able to add a field() to it. Likewise, you can set an analyzer on a field, only if you are defining a field. It's like the dynamic languages fluent APIs be better ;)
The next step is to associate the programmatic mapping object to the Hibernate configuration.
//in Hibernate native Configuration configuration = ...; configuration.setProperty( "hibernate.search.mapping_model", mapping ); SessionFactory factory = configuration.buildSessionFactory();
//in JPA Map<String,String> properties = new HashMap<String,String)(1); properties.put( "hibernate.search.mapping_model", mapping ); EntityManagerFactory emf = Persistence.createEntityManagerFactory( "userPU", properties );
And voila!
Extensibility
The beauty of this API is that it's very easy for XML fan boys to create their own XML schema descriptors and use the programmatic API when parsing the XML stream. More interestingly, an application can expose specific configuration options (via a simple configuration file, a UI or any other form) and use this configuration to customize the mapping programmatically.
Please give this API a try, tell us what works and what does not, we are still figuring out things to make it as awesome as possible :)
Download
Many thanks to Amin Mohammed-Coleman for taking my half done initiative and polishing it up.
You can get Hibernate Search 3.2 Beta 1 here, the complete API documentation is present in the distribution; chapter 4.4.
I have been at a few conferences lately and the EE 6 wave is taking a bunch of people by surprise. Tsunami level 6. The last two examples are W-JAX and Devoxx.
Devoxx
The Java EE 6 university talk was packed. And when you know the capacity of Devoxx's rooms that's really impressive! Kudos to Antonio and Alexis for managing expectations during they lecture.
The JSF 2 and the Java EE 6 BoFs were basically full as well.
W-JAX
Keynote on Java EE 6, full day tracks on EE 6 and EJB: full. An EJB session full, WTF? What's going on?
What we are seeing is Java EE 6 and its Web profiles are becoming the hot topic of the day. If I was a proprietary web application stack, in Java or not, I would be very scared:
- JSF 2 becomes actually usable
- CDI (JSR-299) brings injection, context management and framework portability across the SE and EE platforms
- Bean Validation integrates validation from the presentation down to the data layer
- JAX-RS is simply awesome when you want to expose REST APIs
- EE 6 looks like a platform designed by a single person, heresy!
and many more features are invading the EE landscape.
Disclaimer
I know it sounds like a blog written by some marketing borg but I have a few counter arguments to that:
- did you see any forward-looking statement in this blog?
- seriously, that's just happening (I am especially excited about CDI's portable extensions Gavin has been blogging about lately).
| Showing 1 to 5 of 52 blog entries |
|
|