Help

I am a core developer on the Hibernate products Annotations, EntityManager, Search and Validator. Currently I am focusing on the implementation JSR 303 - Bean Validation.

Location: Göteborg, Sweden
Occupation: Developer at JBoss, a division of Red Hat
Archive

Today we are happy to announce the 5.0.1.Final release of Hibernate Validator. In case you are wondering what happened with 5.0.0.Final - it has not gone missing. In fact it was released on the 11th of April.

The long story is, that we had to release 5.0.0.Final to meet the Java EE 7 release schedule. At the time the functionality was complete, but documentation was not. Given the amount of changes introduced by Bean Validation 1.1, we felt it was important to wait with the announcement of Hibernate Validator 5 until the documentation is up to scratch. That's the case with 5.0.1.Final. Not only does this release offer a complete Bean Validation 1.1 implementation it also includes an updated online documentation.

The highlights of Hibernate Validator 5 are (with pointers into the freshly baked documentation):

  • Standardized method validation of parameters and return values. This has been a Hibernate Validator 4 specific functionality, but got now standardized as part of Bean Validation 1.1.
  • Integration with Context and Dependency Injection (CDI). There are default ValidatorFactory and Validator instances available and you can now use @Inject in ConstraintValidator implementations out of the box. Requested custom implementations (via validation.xml) of resources like ConstraintValidatorFactory, MessageInterpolator, ParameterNameProvider or TraversableResolver are also provided as managed beans. Last but not least, the CDI integration offers transparent method validation for CDI beans.
  • Group conversion
  • Error message interpolation using EL expressions

We are also planning to create a little blog series introducing these new features in more detail. Stay tuned!

For now have a look at the Getting Started section of the documentation to see what you need to use Hibernate Validator 5. Naturally you will need the new Bean Validation 1.1 dependency, but you will also need an EL implementation - either provided by a container or added to your Java SE environment. Additional migration pointers can also be found in the Hibernate Validator migration guide.

You find the full release notes as usual on Jira. Maven artefacts are on the JBoss Maven repository under the GAV org.hibernate:hibernate-validator:5.0.1.Final and distribution bundles are available on SourceForge.

We are looking forward to get some feedback either on the Hibernate Validator forum or on stackoverflow using the hibernate-validator tag.

Enjoy!

With the endgame for Bean Validation 1.1 in full swing, we want to make sure that everyone has the chance to test and integrate early. So without further ado:

Bean Validation TCK 1.1.0.CR2

Hibernate Validator 5.0.0.CR2

The TCK work has been about increasing test coverage - see BVTCK-42, whereas Hibernate Validator work was focused around these 17 issues. Most notably is the rework of the CDI integration via a portable extension (HV-723, HV-740).

Enjoy!

Playing catchup with last week's Bean Valdiation specification release (1.1.0.Beta3) we are happy to make the following releases available as well:

Bean Validation TCK 1.1.0.Beta3

  • Maven artefacts on the JBoss Maven repository under the GAV org.hibernate.beanvalidation.tck:beanvalidation-tck-tests:1.1.0.Beta3
  • Zip and tar bundles on SourceForge

Hibernate Validator 5.0.0.Beta1

Given that the specification addressed 38 issues in its latest release, we were not quite able to sync the TCK and RI completely. There are still some missing TCK tests and the RI has missing features as well. For example, the XML configuration of method validation is still work in progress (see HV-373).

The TCK addresses 6 issues and Hibernate Validator 36. In case you are wondering, the main work in the TCK was the addition of test for new Bean Validation 1.1 features. This was addressed in BVTCK-32 which alone has 12 pull requests. Feel free to review the tests to verify that we are on the right track ;-)

Most notably we are behind with documentation though. Both, the TCK docs as well as the Hibernate Validator docs could need some love. Ever wanted to contribute, but did not know how? Here is your chance! Contact us via email or use the issue tracker.

Last but not least, here is a little teaser about what is new in this release. As of HV-676 it is now possible to use the Unified Expression Language (UEL) in the constraint message descriptors. We offered something in this direction before with ValueFormatterMessageInterpolator (which is by the way deprecated now), but there we offered only a way to format the validated value. Now you can interpolate the constraint annotation paramters as well and you can navigate the objects via the dot notation. And you can even have conditional messages. Here are a couple of examples:


    # ternary operator for conditional DecimalMax constraints - see also HV-256
    javax.validation.constraints.DecimalMax.message  = must be less than ${inclusive == true ? 'or equal to ' : ''}{value}

    # a custom date range annotation with custom formatted validated date
    com.acme.DateRange.message = the specified date ${formatter.format('%1%tY-%tm-%td', validatedValue)} lies not between formatter.format('%1%tY-%tm-%td', min)} and formatter.format('%1%tY-%tm-%td', max)}
There is another release at least of Hibernate Validator planned for next week. So stay tuned.

Enjoy!

Inspired by these questions on the Search forum and stackoverflow I decided to blog about different solutions for the problem using only the tools available in Search right now (4.1.1.Final). But let's start with the problem.

The Problem

How can I define a custom analyzer for a field added in a custom class bridge? Let's look at an example. Below the class Foo defines a custom bridge FooBridge. How can I specify a custom analyzer for the field added by this bridge?

@Entity
@Indexed
@ClassBridge(impl = FooBridge.class)
public static class Foo {
	@Id
	@GeneratedValue
	private Integer id;
}

Solution 1

The straight forward approach looks something like that.

@Entity
@Indexed
@ClassBridge(name = "myCustomField", impl = FooBridge.class, analyzer = @Analyzer(impl = MyCustomAnalyzer.class))
public static class Foo {
	@Id
	@GeneratedValue
	private Integer id;
}

This works fine, provided the field you are adding in FooBridge has the name myCustomField. In case you are adding a field (or even multiple fields) with a different name this approach does not work anymore. In Lucene analyzers are specified per field identified by field name. Since from your @ClassBridge definition we cannot tell which fields you are adding, there is no way of registering and applying the right analyzers. See also the related issue HSEARCH-904.

Solution 2

In the second solution you are managing the analyzers on your own. The relevant part is in the bridge implementation:

public class FooBridge implements FieldBridge {

	@Override
	public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
		Field field = new Field(
				name,  
				"",
				luceneOptions.getStore(),
				luceneOptions.getIndex(),
				luceneOptions.getTermVector()
		);
		try {
			String text = "whatever you want to index";
			MyCustomAnalyzer analyzer = new MyCustomAnalyzer( );
			field.setTokenStream( analyzer.reusableTokenStream( name, new StringReader( text ) ) );
			document.add( field );
		}
		catch ( IOException e ) {
			// error handling
		}
	}
}
As you can see you need to instantiate your analyzer yourself and then set the token stream for the field you want to add. This will work, but it does not work with @AnalyzerDef which is often used to define and reuse analyzers globally for your application. Lets have a look at this solution.

Solution 3

Let's start directly with the code:

	@Entity
	@Indexed
	@AnalyzerDefs({
			@AnalyzerDef(name = "analyzer1",
					tokenizer = @TokenizerDef(factory = MyFirstTokenizer.class),
					filters = {
							@TokenFilterDef(factory = MyFirstFilter.class)
					}),
			@AnalyzerDef(name = "analyzer2",
					tokenizer = @TokenizerDef(factory = MySecondTokenizer.class),
					filters = {
							@TokenFilterDef(factory = MySecondFilter.class)
					}),
			@AnalyzerDef(name = "analyzer3",
					tokenizer = @TokenizerDef(factory = MyThirdTokenizer.class),
					filters = {
							@TokenFilterDef(factory = MyThirdFilter.class)
					})
	})
	@ClassBridge(impl = FooBridge.class)
	@AnalyzerDiscriminator(impl = FooBridge.class)
	public static class Foo {
		@Id
		@GeneratedValue
		private Integer id;
	}

	public static class FooBridge implements Discriminator, FieldBridge {

		public static final String[] fieldNames = new String[] { "field1", "field2", "field3" };
		public static final String[] analyzerNames = new String[] { "analyzer1", "analyzer2", "analyzer3" };

		@Override
		public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
			for ( String fieldName : fieldNames ) {
				Fieldable field = new Field(
						fieldName,
						"Your text to analyze and index",
						luceneOptions.getStore(),
						luceneOptions.getIndex(),
						luceneOptions.getTermVector()
				);
				field.setBoost( luceneOptions.getBoost() );
				document.add( field );
			}
		}

		public String getAnalyzerDefinitionName(Object value, Object entity, String field) {
			for ( int i = 0; i < fieldNames.length; i++ ) {
				if ( fieldNames[i].equals( field ) ) {
					return analyzerNames[i];
				}
			}
			return null;
		}
	}
A lot is going on here and the example shows many useful features of Search. First @AnalyzerDefs is used to declaratively define and build your analyzers. This analyzers are globally available under their given names and can be reused across the application (see also SearchFactory#getAnalyzer(String)). You build an analyzer by first specifying its tokenizer and then a list of filters to apply. Have a look at named analyzers in the online documentation for more information.

Next the example uses @ClassBridge(impl = FooBridge.class) to define the custom class bridge. Nothing special there. Which fields you are adding in the implementation is up to you.

Last but not least, we have @AnalyzerDiscriminator(impl = FooBridge.class). This annotation is normally used for dynamic analyzer selection based on the entity state. However, it can easily be used in this context as well. To make things easy I let the field bridge directly implement the required Discriminator interface. Discriminator#getAnalyzerDefinitionName will now be called for each field being added to the index. You also get passed the entity itself and the value (in case the field bridge is defined on a property), but this is not important in this case. All which remains to be done is to make sure to return the right analyzer name based on the passed field name.

Solution 3 seems maybe longer, but it is a declarative approach and it also allows you to reuse analyzer configurations. It also shows that the current API might still have its shortcomings (eg HSEARCH-904), but using the tools already available, there are often work-arounds.

Happy analyzing,

Hardy

Good news for all of you waiting for an early version of Hibernate Validator 5 in order to experiment with the new Bean Validation 1.1 (JSR 349) features. Hibernate Validator 5.0.0.Alpha1 is now available for download in the JBoss Maven Repository under the GAV org.hibernate:hibernate-validator:5.0.0.Alpha1 or via SourceForge.

The focus of the release was the alignment of Hibernate Validator with the first early draft of Bean Validation 1.1 (1.1.0.Alpha1). The Hibernate Validator changelog circles for this reason around HV-571 which served as placeholder for those specification changes. Of course the biggest change was the formalization of method validation, but there are other interesting new features as well. For example:

  • In conjunction with method validation it is worth having a look at the ParameterNameProvider interface which helps to identify the parameter of a failing parameter constraint in the resulting ConstraintViolation. The Path API was also extended to provide additional meta information about a failing constraint. You can get the element descriptor via Path.Node#getElementDescriptor (of course you need to iterate to the leaf node of first). The element discriptors themselves got extended by ConstructorDescriptor, MethodDescriptor, ParameterDescriptor and ReturnValueDescriptor.
  • Support for container injection in ConstraintValidator. Check out the new life cycle methods ValidatorFactory#close and ConstraintValidatorFactory#releaseInstance in this context.
  • Expose settings defined in XML in the Configuration API. Refer to the new interface javax.validation.ConfigurationSource, but be aware that there is a follow up issue (BVAL-292) as well.

The easiest way to find out more about these new interfaces and classes is to have a look at the Hibernate Validator test suite where you will find tests for all the mentioned new features.

There are more proposals which are still under active discussion. Feel free to contribute :-)

Given that this is an early draft there will be further changes to the API. For this reason Hibernate Validator 5.0.0.Alpha1 is not a production release. On the other hand, for integrators and tool developers it makes a lot of sense to have an early evaluation to see whether we are on the right track.

Enjoy!

Showing 1 to 5 of 46 blog entries