It's my great pleasure to announce the release of Hibernate OGM 4.1.0.Beta1! This version shines with:
- support for CouchDB
- query execution via JPA
- new Option API
- and much more, including a version bump
But wait, hasn't the last released version been 4.0.0.Beta4? That's true indeed, and in case you were wondering, we did not forget to do a final release of the 4.0 line. The reason for the version bump is that Hibernate OGM is now compatible with JPA 2.1 and Hibernate ORM 4.3. To reflect this we thought it'd be a good idea to jump to a new minor version as well.
As usual, you can get the release from SourceForge (ZIP, TAR.GZ) or retrieve it from the JBoss Nexus repository server using your favorite dependency management tool. The GAV coordinates are:
- org.hibernate.ogm:hibernate-ogm-core:4.1.0.Beta1 for the OGM engine and
- org.hibernate.ogm:hibernate-ogm-<datastore>:4.1.0.Beta1, depending on the backend you want to use.
Note that we did move some packages around, so make sure to look at our migration guide.
Enough of the introductory words, let's have a closer look at some of the new features.
Support for CouchDB
Based on a huge contribution of community member Andrea Boriero (thanks again, Andrea!), Hibernate OGM comes now with support for Apache CouchDB. CouchDB is a scalable document datastore which persists data as JSON documents and offers an HTTP API, fully embracing REST principles.
The storage strategy of the new dialect resembles that used for MongoDB. In particular we aimed for a very natural mapping of entities to documents in the datastore. E.g. properties are mapped as document fields, embeddables are mapped as nested documents etc. We're also leveraging CouchDB's built-in optimistic locking mechanism to detect concurrent updates, just as you would expect it.
The listing belows shows an entity and how it is represented as JSON document in CouchDB:
@Entity
public class News {
@Id
private String id;
@Version
@Generated
@Column(name="_rev")
private String revision;
private String title;
@Column(name="desc")
private String description;
//getters, setters ...
}
# JSON document
{
"_id": "News:id_:news-1_",
"_rev": "1-d1cd3b00a677a2e31cd0480a796e8480",
"$type": "entity",
"$table": "News",
"title": "On the merits of NoSQL",
"desc": "This paper discuss why NoSQL will save the world for good"
}
As you can see, the @Id attribute is mapped to CouchDB's reserved _id field, the same applies for the revision attribute which is mapped to _rev. The @Version and @Generated annotations advice OGM to handle the revision property as version attribute and use it for optimistic concurrency control. The @Column annotation can be used to map a property to a document field with another name.
To learn more about the CouchDB dialect and how to use it, refer to the reference guide. Note that the dialect is considered experimental at this time, so don't expect everything to work perfectly yet. Of course any feedback is highly welcome; maybe you even want to tackle one of the open issues) in this field?
Query improvements
We're very pleased to have progressed in the field of queries, addressing several long standing feature requests.
It's possible now to issue JP-QL queries via the EntityManager API which is great news for you if you're preferring JPA over using the native Hibernate API:
EntityManager em = ...;
List<Animal> giraffes = em.createQuery( "FROM Animal WHERE species = :species" )
.setParameter( "species", "Giraffe" )
.getResultList();
You also can work with named queries now:
@Entity
@NamedQuery(name = AnimalQueries.BY_SPECIES, query = "FROM Animal WHERE species = :species")
public class Animal { ... }
EntityManager em = ...;
List<Animal> giraffes = em.createNamedQuery( AnimalQueries.BY_SPECIES, Animal.class )
.setParameter( "species", "Giraffe" )
.getResultList();
Depending on the chosen backend, these queries will either be translated into Lucene Queries via Hibernate Search or into native queries of the backend (currently the case for MongoDB).
Option API
One big challenge Hibernate OGM has to deal with is how to expose store-specific functionality and configuration options in case the JPA semantics are not sufficient. Taking MongoDB as example, you might want to configure the write concern or a strategy for persisting association information.
Hibernate OGM now provides an extendible, type-safe and comprehensible mechanism for declaring such options. You can use annotations and a programmatic API. Dialect authors can plug in store-specific configuration options very easily, allowing users to specify these options in an intuitive and type-safe fashion. The following shows an example:
@Entity
@AssociationStorage(AssociationStorageType.ASSOCIATION_DOCUMENT)
public class Zoo {
@OneToMany
private Set<Animal> animals;
@OneToMany
private Set<Person> employees;
@OneToMany
@AssociationStorage(AssociationStorageType.IN_ENTITY)
private Set<Person> visitors;
//...
}
The @AssociationStorage annotation on the entity level expresses that all associations of the Zoo class should be persisted as separate association documents. Only the visitors association will be stored embedded within the corresponding Zoo document, as the local @AssociationStorage annotation takes precedence.
We try to share such configuration options between stores of one kind where feasible. E.g. the @AssocationStorage annotation is applicable to all document datastores (while e.g. an option such as @WriteConcern would be specific to MongoDB), simplifying the migration between stores. Neat, isn't it?
Now let's have a look at how you'd apply the same configuration using the programmatic API:
public class MyOptionConfigurator extends OptionConfigurator {
@Override
public void configure(Configurable configurable) {
configurable.configureOptionsFor( MongoDB.class )
.associationStorage( AssociationStorageType.ASSOCIATION_DOCUMENT )
.entity( Zoo.class )
.associationStorage( AssociationStorageType.IN_ENTITY )
.property( "visitors", ElementType.FIELD )
.associationStorage( AssociationStorageType.ASSOCIATION_DOCUMENT )
.associationDocumentStorage( AssociationDocumentType.COLLECTION_PER_ASSOCIATION );
}
}
All you need to do is to create an OptionConfigurator implementation, which provides access to the fluent configuration API. You can apply settings on a global level and then use entity() and property() to navigate to single entities and properties and apply options to the same. Again you can declare options specific to the store as well as options common to the family of store. Just don't forget to register your configurator when bootstrapping Hibernate OGM.
The work on options has been mainly behind the scenes in this release, with the shown options only being the first few examples for leveraging this new mechanism. You can expect to see more options specific to single stores or store families in future releases, providing you with all the flexibility you need to configure your datastore.
Streamlined configuration properties
The new option mechanism is an elegant way for specifying many options in a type-safe way. But plain properties in persistence.xml are just more appropriate for settings such as the host name of the store, user name etc. When working on the option API, it became apparent that several of our backend modules had the same or very similar configuration properties, but partly with different names and adhering to different naming conventions. So we took the chance to clean up the mess and re-organized the properties.
Properties common to all/most stores are named hibernate.ogm.datastore.* now, so e.g. there is hibernate.ogm.datastore.host, hibernate.ogm.datastore.username, hibernate.ogm.datastore.database etc. Properties specific to a single store are named hibernate.ogm.<datastore>.*, e.g. hibernate.ogm.mongodb.connection_timeout. Note that when programmatically bootstrapping a session factory or entity manager factory, you should refer to the properties using the constants declared on OgmProperties, InfinispanProperties etc.
While this change greatly increases consistency and removes redundancies, it requires existing applications to be adapted. So check out the reference guide to make sure you use the right names.
As always, your feedback around the new release is highly welcome. The complete change log can be found here. You can file bugs or feature requests in the issue tracker, ask questions in the forum or discuss ideas around the development of Hibernate OGM on our mailing list.