In the beginning of this chapter we said that even when you map entities to the database with hbm.xml
files, you can still use Hibernate Search annotations mapping to Lucene. However, if you really want to avoid putting annotations in your entity classes altogether, there is an API available for declaring your Lucene mappings programmatically at runtime.
This might come in handy if your search configuration needs to change at runtime based on some circumstances. It is also the only approach available if you cannot alter your entity classes for some reason, or if you are a hard-line believer in separating your configuration from your POJO's.
The heart of the programmatic mapping API is the SearchMapping
class, which stores the Hibernate Search configuration that is normally pulled from annotations. Typical usage looks like the query DSL code that we saw in the previous chapter. You call a method on a SearchMapping
object, call a method on the object returned, and so on in a long nested series.
The methods available at each step of the way intuitively resemble the search annotations that you have already seen. The
entity()
method replaces the @Entity
annotation, indexed()
replaces @Indexed
, field()
replaces @Field
, and so on.
If you need to use the programmatic mapping API in an application, then you can find more details in Reference Manual and Javadocs, both available at http://www.hibernate.org/subprojects/search/docs.
The starting point in Javadocs is the org.hibernate.search.cfg.SearchMapping
class, and the other relevant classes are all in the org.hibernate.search.cfg
package as well.
In the downloadable source code available from the Packt Publishing website, the chapter2-mapping
subdirectory contains a version of the VAPORware Marketplace application that uses the programmatic mapping API.
This version of the example application includes a factory class, with a method that configures and returns a SearchMapping
object upon demand. It doesn't matter what you name the class or the method, so long as the method is annotated with @org.hibernate.search.annotations.Factory
:
public class SearchMappingFactory { @Factory public SearchMapping getSearchMapping() { SearchMapping searchMapping = new SearchMapping(); searchMapping .entity(App.class) .indexed() .interceptor(IndexWhenActiveInterceptor.class) .property("id", ElementType.METHOD).documentId() .property("name", ElementType.METHOD).field() .property("description", ElementType.METHOD).field() .property("supportedDevices", ElementType.METHOD).indexEmbedded().depth(1) .property("customerReviews", ElementType.METHOD).indexEmbedded().depth(1) .entity(Device.class) .property("manufacturer", ElementType.METHOD).field() .property("name", ElementType.METHOD).field() .property("supportedApps", ElementType.METHOD).containedIn() .entity(CustomerReview.class) .property("stars", ElementType.METHOD).field() .property("comments", ElementType.METHOD).field(); return searchMapping; } }
Notice that this factory method is only three lines long, strictly speaking. The bulk of it is one continuous line of chained method calls, originating from the SearchMapping
object, that map our three persistent classes.
To integrate the mapping factory into Hibernate Search, we add a property to the main hibernate.cfg.xml
configuration file:
...
<property name="hibernate.search.model_mapping">
com.packtpub.hibernatesearch.util.SearchMappingFactory
</property>
...
Now, whenever Hibernate ORM opens a Session
, Hibernate Search and all of the Lucene mappings come along for the ride!