Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emmanuelbernard/9090044 to your computer and use it in GitHub Desktop.
Save emmanuelbernard/9090044 to your computer and use it in GitHub Desktop.

CouchDB dialect, enhanced query support and more: Hibernate OGM 4.1.0.Beta1 is out

It's my great pleasure to announce the release of Hibernate OGM 4.1.0.Beta1! This version shines with:

  • a new dialect for CouchDB,
  • support for query execution via JPA,
  • a 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 and org.hibernate.ogm:hibernate-ogm-{infinispan|mongodb|...}:4.1.0.Beta1, depending on the backend you want to use.

We did move some packages around, 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 (you can find the complete change log here).

CouchDB dialect

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 API over HTTP, 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.

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 perfect 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.

So 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 when 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 readable 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 MyOptionConfigurer extends OptionConfigurer {

    @Override
    public void configure(Configurable configurable) {
        configurable.configureOptionsFor( MongoDB.class )
            .writeConcern( WriteConcernType.JOURNALED )
            .entity( Zoo.class )
                .associationStorage( AssociationStorageType.ASSOCIATION_DOCUMENT )
                .property( "visitors", ElementType.FIELD )
                    .associationStorage( AssociationStorageType.IN_ENTITY );
    }
}

All you need to do is to create an OptionConfigurer implementation, which provides access to the fluent configuration API. You can apply settings on a global level (writeConcern()) and 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 configurer 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 exmamples 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. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment