Red Hat

In Relation To Gunnar Morling

In Relation To Gunnar Morling

Map me if you can - Advanced embeddable mappings

Posted by Gunnar Morling    |       |    Tagged as Hibernate ORM

The other day I came across an interesting mapping challenge which I thought may be worth sharing. If you are a seasoned JPA user, it will probably be nothing new to you, but those not as experienced may find it helpful :)

TL;DR - JPA let’s you override database columns for embedded objects but also for collections of embedded objects; @AttributeOverride and @AssocationOverride can be used for that.

Let’s assume the following entity model representing a person and their home and business address:

Entity model

The interesting part is that Person has two associations with Address, one with the "homeAddress" role and another one with the "businessAddress" role. Address in turn has one ore more address lines.

When mapping these types with JPA, Person naturally becomes an entity. As there is a composition relationship between Person and Address, the latter is mapped with @Embeddable. The same goes for AddressLine, which also is an @Embeddable, contained within an element collection owned by Address.

So you’d end up with these classes:

@Entity
public class Person {

    @Id
    private long id;
    private String name;
    private Address homeAddress;
    private Address businessAddress;

    // constructor, getters and setters...
}
@Embeddable
public class Address {

    private boolean active;

    @ElementCollection
    private List<AddressLine> lines = new ArrayList<AddressLine>();

    // constructor, getters and setters...
}
@Embeddable
public class AddressLine {

    private String value;

    // constructor, getters and setters...
}

@AttributeOverride

Let’s fire up a session factory with these types (this uses the brand-new bootstrapping API coming in Hibernate ORM 5) and see how that goes:

StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
    .applySetting( AvailableSettings.SHOW_SQL, true )
    .applySetting( AvailableSettings.FORMAT_SQL, true )
    .applySetting( AvailableSettings.HBM2DDL_AUTO, "create-drop" )
    .build();

SessionFactory sessionFactory = new MetadataSources( registry )
    .addAnnotatedClass( Person.class )
    .buildMetadata()
    .buildSessionFactory();

Hum, that did not go too well:

org.hibernate.MappingException: Repeated column in mapping for entity:
org.hibernate.bugs.Person column: active (should be mapped with insert="false" update="false")

Of course this makes sense; As Address is embedded twice within Person, its properties must be mapped to unique column names within the Person table. The @AttributeOverride annotation can be used for that:

@Entity
public class Person {

    @Id
    private long id;
    private String name;

    @AttributeOverride(name = "active", column = @Column(name = "home_address_active"))
    private Address homeAddress;

    @AttributeOverride(name = "active", column = @Column(name = "business_address_active"))
    private Address businessAddress;

    // constructor, getters and setters...
}

With that, the session factory boots successfully. But let’s take a look at the tables that get created:

create table Person (
    id bigint not null,
    business_address_active boolean,
    home_address_active boolean,
    name varchar(255),
    primary key (id)
)

create table Person_lines (
    Person_id bigint not null,
    "value" varchar(255)
)

@AssociationOverride

The Person table looks alright, but there is only a single table for the address lines. That’s a problem as it means there is no way to tell apart the lines of the business address from the lines of the home address when reading back a person from the database.

So what to do? @AttributeOverride is of no help this time, as it’s not a single column which needs to be re-defined but an entire table. But luckily, @AttributeOverride has a companion, @AssociationOverride. This annotation can be used to configure the required tables in this case:

@Entity
public class Person {

    @Id
    private long id;
    private String name;

    @AttributeOverride(name = "active", column = @Column(name = "home_address_active"))
    @AssociationOverride(name = "lines", joinTable = @JoinTable(name = "Person_HomeAddress_Line"))
    private Address homeAddress;

    @AttributeOverride(name = "active", column = @Column(name = "business_address_active"))
    @AssociationOverride(name = "lines", joinTable = @JoinTable(name = "Person_BusinessAddress_Line"))
    private Address businessAddress;

    // constructor, getters and setters...
}

Et voilà, now you’ll get the DDL for creating the Person table and two different tables for the address lines:

create table Person (
    id bigint not null,
    business_address_active boolean,
    home_address_active boolean,
    name varchar(255),
    primary key (id)
)

create table Person_BusinessAddress_Line (
    Person_id bigint not null,
    "value" varchar(255)
)

create table Person_HomeAddress_Line (
    Person_id bigint not null,
    "value" varchar(255)
)

Welcome back to our tutorial series “NoSQL with Hibernate OGM”!

In this part you will learn how to use Hibernate OGM from within a Java EE application running on the WildFly server. Using the entity model you already know from the previous parts of this tutorial, we will build a small REST-based application for managing hikes. In case you haven’t read the first two installments of this series, you can find them here:

In the following you will learn how to prepare WildFly for using it with Hibernate OGM, configure a JPA persistence unit, create repository classes for accessing your data and providing REST resources on top of these. In this post we will primarily focus on the aspects related to persistence, so some basic experience with REST/JAX-RS may help. The complete source code of this tutorial is hosted on GitHub.

Preparing WildFly

The WildFly server runtime is based on the JBoss Modules system. This provides a modular class-loading environment where each library (such as Hibernate OGM) is its own module, declaring the list of other modules it depends on and only “seeing” classes from those other dependencies. This isolation provides an escape from the dreaded “classpath hell”.

ZIP files containing all the required modules for Hibernate OGM are provided on SourceForge. Hibernate OGM 4.2 - which we released yesterday - supports WildFly 9, so download hibernate-ogm-modules-wildfly9-4.2.0.Final.zip for that. If you are on WildFly 8, use Hibernate OGM 4.1 and get hibernate-ogm-modules-wildfly8-4.1.3.Final.zip instead.

Unzip the archive corresponding to your WildFly version into the modules directory of the application server. If you prefer that the original WildFly directories remain unchanged, you also can unzip the Hibernate OGM modules archive to any other folder and configure this as the “module path” to be used by the server. To do so, export the following two environment variables, matching your specific environment:

export JBOSS_HOME=/path/to/wildfly
export JBOSS_MODULEPATH=$JBOSS_HOME/modules:/path/to/ogm/modules

In case you are working with the Maven WildFly plug-in, e.g. to launch WildFly during development, you’d achieve the same with the following plug-in configuration in your POM file:

...
<plugin>
    <groupId>org.wildfly.plugins</groupId>
    <artifactId>wildfly-maven-plugin</artifactId>
    <version>1.1.0.Alpha1</version>
    <configuration>
        <jboss-home>/path/to/wildfly</jboss-home>
        <modules-path>/path/to/ogm/modules</modules-path>
    </configuration>
</plugin>
...

Setting up the project

Start by creating a new Maven project using the “war” packaging type. Add the following to your pom.xml:

...
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.hibernate.ogm</groupId>
            <artifactId>hibernate-ogm-bom</artifactId>
            <type>pom</type>
            <version>4.2.0.Final</version>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
...

This makes sure you get matching versions of Hibernate OGM’s modules and any (optional) dependencies. Then add the dependency to the Java EE 7 API and one of the Hibernate OGM backend modules, e.g. Infinispan, JBoss’ high-performance, distributed key/value data grid (any other such as hibernate-ogm-mongodb or the brand-new hibernate-ogm-cassandra module would work as well):

...
<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.hibernate.ogm</groupId>
        <artifactId>hibernate-ogm-infinispan</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>
...

The provided scope makes these dependencies available for compilation but prevents them from being added to the resulting WAR file. That it because the Java EE API is part of WildFly already, and Hibernate OGM will be contributed through the modules you unzipped before.

Just adding these modules to the server doesn’t cut it, though. They also need to be registered as a module dependency with the application. To do so, add the file src/main/webapp/WEB-INF/jboss-web.xml with the following contents:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure
    xmlns="urn:jboss:deployment-structure:1.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <deployment>
        <dependencies>
            <module name="org.hibernate" slot="ogm" services="import" />
            <module name="org.hibernate.ogm.infinispan" services="import" />
            <module name="org.hibernate.search.orm" services="import" />
        </dependencies>
    </deployment>
</jboss-deployment-structure>

This will make Hibernate OGM core and the Infinispan backend as well as Hibernate Search available to your application. The latter will be used to run JP-QL queries in a bit.

Adding entity classes and repositories

With the basic project infrastructure in place, it’s time to add the entity classes and repository classes for accessing them. The entity types are basically the same as seen in part 1, only now they are annotated with @Indexed in order to allow them to be queried via Hibernate Search and Lucene:

@Entity
@Indexed
public class Person {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

    private String firstName;
    private String lastName;

    @OneToMany(
        mappedBy = "organizer",
        cascade = { CascadeType.PERSIST, CascadeType.MERGE },
        fetch = FetchType.EAGER
    )
    private Set<Hike> organizedHikes = new HashSet<>();

    // constructors, getters and setters...
}
@Entity
@Indexed
public class Hike {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

    private String description;
    private Date date;
    private BigDecimal difficulty;

    @ManyToOne
    private Person organizer;

    @ElementCollection(fetch = FetchType.EAGER)
    @OrderColumn(name = "sectionNo")
    private List<HikeSection> sections;

    // constructors, getters and setters...
}
@Embeddable
public class HikeSection {

    private String start;
    private String end;

    // constructors, getters and setters...
}

In order to use these entities, a JPA persistence unit must be defined. To do so, create the file src/main/resources/META-INF/persistence.xml:

<?xml version="1.0" encoding="utf-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
    version="1.0">

    <persistence-unit name="hike-PU" transaction-type="JTA">
        <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>

            <class>org.hibernate.ogm.demos.ogm101.part3.model.Person</class>
            <class>org.hibernate.ogm.demos.ogm101.part3.model.Hike</class>

            <properties>
                <property name="hibernate.ogm.datastore.provider" value="INFINISPAN" />
                <property name="hibernate.ogm.datastore.database" value="hike_db" />
                <property name="hibernate.ogm.datastore.create_database" value="true" />
            </properties>
    </persistence-unit>
</persistence>

Here we define a persistence unit named “hike-PU”. Infinispan is a fully transactional datastore, and using JTA as transaction type allows the persistence unit to participate in container-managed transactions. Specifying HibernateOgmPersistence as the provider class enables Hibernate OGM (instead of Hibernate ORM), which is configured with some properties for the setting backend (INFINISPAN in this case), database name etc.

Note that it actually should not be required to specify the entity types in persistence.xml when running in a Java EE container such as WildFly. Instead they should be picked up automatically. When using Hibernate OGM this unfortunately is needed at the moment. This a known limitation (see OGM-828) which we hope to fix soon.

The next step is to implement repository classes for accessing hike and organizer data. As an example, the following shows the PersonRepository class:

@ApplicationScoped
public class PersonRepository {

    @PersistenceContext
    private EntityManager entityManager;

    public Person create(Person person) {
        entityManager.persist( person );
        return person;
    }

    public Person get(String id) {
        return entityManager.find( Person.class, id );
    }

    public List<Person> getAll() {
        return entityManager.createQuery( "FROM Person p", Person.class ).getResultList();
    }

    public Person save(Person person) {
        return entityManager.merge( person );
    }

    public void remove(Person person) {
        entityManager.remove( person );
        for ( Hike hike : person.getOrganizedHikes() ) {
            hike.setOrganizer( null );
        }
    }
}

The implementation is straight-forward; by means of the @ApplicationScoped annotation, the class is marked as application-scoped CDI bean (i.e. one single instance of this bean exists throughout the lifecycle of the application). It obtains a JPA entity manager through dependency injection and uses the same to implement some simple CRUD methods (Create, Read, Update, Delete).

Note how the getAll() method uses a JP-QL query to return all person objects. Upon execution this query will be transformed into an equivalent Lucene index query which will be run through Hibernate Search.

The hike repository looks very similar, so it’s omitted here for the sake of brevity. You can find its source code on GitHub.

Exposing REST services

JAX-RS makes building REST-ful web services a breeze. It defines a declarative programming model where you annotate plain old Java classes to provide implementations for the GET, POST, PUT etc. operations of an HTTP endpoint.

Describing JAX-RS in depth is beyond the scope of this tutorial, e.g. refer to the Java EE 7 tutorial if you would like to learn more. Let’s just have a look at the some methods of a resource class for managing persons as an example:

@Path("/persons")
@Produces("application/json")
@Consumes("application/json")
@Stateless
public class Persons {

    @Inject
    private PersonRepository personRepository;

    @Inject
    private ResourceMapper mapper;

    @Inject
    private UriMapper uris;

    @POST
    @Path("/")
    public Response createPerson(PersonDocument request) {
        Person person = personRepository.create( mapper.toPerson( request ) );
        return Response.created( uris.toUri( person ) ).build();
    }

    @GET
    @Path("/{id}")
    public Response getPerson(@PathParam("id") String id) {
        Person person = personRepository.get( id );
        if ( person == null ) {
            return Response.status( Status.NOT_FOUND ).build();
        }
        else {
            return Response.ok( mapper.toPersonDocument( person ) ).build();
        }
    }

    @GET
    @Path("/")
    public Response listPersons() {  }

    @PUT
    @Path("/{id}")
    public Response updatePerson(PersonDocument request, @PathParam("id") String id) {  }

    @DELETE
    @Path("/{id}")
    public Response deletePerson(@PathParam("id") String id) {  }
}

The @Path, @Produces and @Consumes annotations are defined by JAX-RS. They bind the resource methods to specific URLs, expecting and creating JSON based messages. @GET, @POST, @PUT and @DELETE configure for which HTTP verb each method is responsible.

The @Stateless annotation defines this POJO as a stateless session bean. Dependencies such as the PersonRepository can be obtained via @Inject-based dependency injection. Implementing a session bean gives you the comfort of transparent transaction management by the container. Invocations of the methods of Persons will automatically be wrapped in a transaction, and all the interactions of Hibernate OGM with the datastore will participate in the same. This means that any changes you do to managed entities - e.g. by persisting a new person via PersonRepository#create() or by modifying a Person object retrieved from the entity manager - will be committed to the datastore after the method call returns.

Mapping models

Note that the methods of our REST service do not return and accept the managed entity types themselves, but rather specific transport structures such as PersonDocument:

public class PersonDocument {

    private String firstName;
    private String lastName;
    private Set<URI> organizedHikes;

    // constructors, getters and setters...
}

The reasoning for that is to represent the elements of associations (Person#organizedHikes, Hike#organizer) in form of URIs, which enables a client to fetch these linked resources as required. E.g. a GET call to http://myserver/ogm-demo-part3/hike-manager/persons/123 may return a JSON structure like the following:

{
    "firstName": "Saundra",
    "lastName": "Johnson",
    "organizedHikes": [
        "http://myserver/ogm-demo-part3/hike-manager/hikes/456",
        "http://myserver/ogm-demo-part3/hike-manager/hikes/789"
    ]
}

The mapping between the internal model (e.g. entity Person) and the external one (e.g. PersonDocument) can quickly become a tedious and boring task, so some tool-based support for this is desirable. Several tools exist for this job, most of which use reflection or runtime byte code generation for propagating state between different models.

Another approach for this is pursued by MapStruct, which is a spare time project of mine and generates bean mapper implementations at compile time (e.g. with Maven or in your IDE) via a Java annotation processor. The code it generates is type-safe, fast (it's using plain method calls, no reflection) and dependency-free. You just need to declare Java interfaces with mapping methods for the source and target types you need and MapStruct will generate an implementation as part of the compilation process:

@Mapper(
    // allows to obtain the mapper via @Inject
    componentModel = "cdi",

    // a hand-written mapper class for converting entities to URIs; invoked by the generated
    // toPersonDocument() implementation for mapping the organizedHikes property
    uses = UriMapper.class
)
public interface ResourceMapper {

    PersonDocument toPersonDocument(Person person);

    List<PersonDocument> toPersonDocuments(Iterable<Person> persons);

    @Mapping(target = "date", dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
    HikeDocument toHikeDocument(Hike hike);

    // other mapping methods ...
}

The generated implementation can then be used in the Persons REST resource to map from the internal to the external model and vice versa. If you would like to learn more about this approach for model mappings, check out the complete mapper interface on GitHub or the MapStruct reference documentation.

Wrap-up

In this part of our tutorial series you learned how to add Hibernate OGM to the WildFly application server and use it to access Infinispan as the data storage for a small REST application.

WildFly is a great runtime environment for applications using Hibernate OGM, as it provides most of the required building blocks out of the box (e.g. JPA/Hibernate ORM, JTA, transaction management etc.), tightly integrated and ready to use. Our module ZIP allows to put the Hibernate OGM modules into the mix very easily, without the need for re-deploying them each time with your application. With WildFly Swarm there is also support for the micro-services architectural style, but we’ll leave it for another time to show how to use Hibernate OGM with Wildfly Swarm (currently JPA support is still lacking from WildFly Swarm).

You can find the sources of the project on GitHub. To build the project run mvn clean install (which executes an integration test for the REST services using Arquillian, an exciting topic on its own). Alternatively, the Maven WildFly plug-in can be used to fire up a WildFly instance and deploy the application via mvn wildfly:run, which is great for manual testing e.g. by sending HTTP requests through curl or wget.

If you have any questions, let us know in the comments below or send us a Tweet to @Hibernate. Also your wishes for future parts of this tutorial are welcome. Stay tuned!

I am pleased to announce the release of Hibernate OGM 4.2.0.CR1.

The new version comes to you with initial support for Apache Cassandra, several improvements around JP-QL queries, support for MongoDB 3, MongoDB replica sets, new built-in types and much more.

You can download Hibernate OGM 4.2.0.CR1 from SourceForge or via Maven, Gradle etc., using the following GAV coordinates:

  • org.hibernate.ogm:hibernate-ogm-core:4.2.0.CR1 for the Hibernate OGM engine and
  • org.hibernate.ogm:hibernate-ogm-<%DATASTORE%>:4.2.0.CR1, depending on the backend you want to use.

Preview for Apache Cassandra support

Cassandra is a highly performant and scalable datastore of the BigTable family. The request for supporting it dates back to the early days of Hibernate OGM. So it’s a great pleasure to finally have this puppy out. Many thanks to all that worked on this journey: Michaël Figuière, Khanh Maudoux, John Worrell and Jonathan Halliday!

To use the Cassandra backend, add the hibernate-ogm-cassandra module to your classpath and specify the following properties for your persistence unit:

hibernate.ogm.datastore.provider = cassandra_experimental
hibernate.ogm.datastore.database = my_keyspace
hibernate.ogm.datastore.host = cassandra.example.com

The Cassandra backend is in “tech preview” state at this moment. We still have lots of work left on our plates (e.g. clustering support, alternative association persistence options, queries, documentation), but we think we have the right foundation now. Be warned that mapping details still may change. Still this is the right time for you to give this new backend a first try and let us know about your experiences with it.

Any feature requests, error reports and other feedback are very welcome. Especially any thoughts on the proposed mapping of domain model elements to Cassandra structures are of great interest for us.

Query improvements

We spent some more time to improve support for mapping JP-QL queries either to native NoSQL queries or full-text queries executed via Hibernate Search + Lucene.

You can now use types like enums or Date as query parameters:

List<Movie> movies = entityManager.createQuery( "SELECT m FROM Movie m WHERE m.genre IN (:genre)", Movie.class )
    .setParameter( "genre", EnumSet.of( Genre.DRAMA, Genre.COMEDY ) )
    .getResultList();

As you would expect it, the given parameter values are converted into the corresponding type used in the datastore and passed to the query engine.

Mapping fix for element collections with nested embeddables

This release fixes a bug related to the mapping of nested embeddables stored within element collections. This affects the supported document stores as well as Neo4j. E.g. consider the following entity model:

@Entity
public class Account {

    @ElementCollection
    List<Address> addresses;
}

@Embeddable
public class Address {
    String street;
    String city;
    AddressType type;
}

@Embeddable
public class AddressType {
    String name;
}

Previously, this would have been stored as follows e.g. in MongoDB:

{
    "_id" : "account-1",
    "addresses" : [
        {
            "street" : "Piazza del Colosseo, 1",
            "city" : "Rome",
            "name" : "work" <-- “flattened” representation of the nested embeddable
        },
        ...
    ]
}

Whereas it really should be mapped like this:

{
    "_id" : "account-1",
    "addresses" : [
        {
            "street" : "Piazza del Colosseo, 1",
            "city" : "Rome",
            “type” : {
                "name" : "work"
            }
        },
        ...
    ]
}

This is the mapping applied as of this new release. Note that you need to take care of existing records should have been working with such a model. Also please check out the migration notes for the details.

We don’t take such mapping changes lightly and try to avoid them as much as we can. As this really was a mapping error, we decided to fix it as soon as possible; in the future we also may provide compatibility options or some sort of migration tooling in similar situations.

Support for MongoDB 3 and MongoDB replica sets

We now also support MongoDB 3. In particular the new SCRAM-SHA-1 authentication strategy is working now. Migration should be smooth.

But the biggest improvement is support for replica sets. To quote MongoDB’s documentation, a replica set “is a group of mongod processes that maintain the same data set”. By using replica sets, your data is stored redundantly and protected against node failures through automatic fail-over between replica set members.

To support the notion of replica sets, Hibernate OGM’s “host” configuration option has been enhanced and now allows to specify a comma-separated list of hosts and host:port tuples:

hibernate.ogm.datastore.host=db1.example.com,db2.example.com,db3.example.com:29019

With this configuration Hibernate OGM would connect to three MongoDB nodes, using the default port 27017 for the nodes db1 and db2 and the explicitly given port 29019 for node db3.

Currently the MongoDB backend is the only one supporting several nodes, but other backends will follow, e.g. Cassandra.

New built-in types for boolean mapping

Requested by a user in our forum, we now support all the boolean mapping types known from Hibernate ORM: YesNoType (maps to character/String “Y” or “N”), TrueFalseType (maps to “T” or “F”) and NumericBooleanType (maps to 1 or 0).

You can use these types by means of the @Type annotation like so:

// maps as boolean; default   
private boolean myBoolean;

@Type(type = "true_false")
private boolean myBoolean;

@Type(type = "yes_no")
private boolean myBoolean;

@Type(type = "numeric_boolean")
private boolean myBoolean;

Any feedback to the 4.2.0.CR1 release is highly welcome. The change log tells in detail what's in there for you. Finally, some more useful links:

Hibernate OGM times 2: 4.1.3 and 4.2 Beta1 released

Posted by Gunnar Morling    |       |    Tagged as Hibernate OGM

I am happy to announce the release of Hibernate OGM 4.1.3 Final and 4.2.0.Beta1!

The former brings several usability improvements, bug fixes and component upgrades, whereas the latter comes with new query features, an error handling API for non-transactional datastores and more.

The releases can be obtained as ZIP or TAR.GZ from SourceForge (4.1.3.Final, 4.2.0.Beta1) or via Maven, Gradle etc., using the following GAV coordinates:

  • org.hibernate.ogm:hibernate-ogm-core:4.1.3.Final or org.hibernate.ogm:hibernate-ogm-core:4.2.0.Beta1 for the Hibernate OGM engine and
  • org.hibernate.ogm:hibernate-ogm-<%DATASTORE%>:4.1.3.Final or org.hibernate.ogm:hibernate-ogm-<%DATASTORE%>:4.2.0.Beta1, depending on the backend you want to use.

Note that from 4.2 onwards, Hibernate OGM requires Java 7. We aimed at Java 6 compatibility for as long as possible, but with more and more of our backends and components requiring Java 7 (e.g. Neo4j and Lucene), we felt that it was time to move on and take advantage of the Java 7 goodies for the Hibernate OGM code base as well.

Let's dive into some of the new functionality of the 4.2 Beta1 release.

Query improvements

We continued our quest for extensive query capabilities and enabled more JP-QL constructs, namely queries on element collections. For example consider the following entity Order which contains an element collection of its order lines:

@Entity
public class Order {

    @Id
    @GeneratedValue
    private long id;

    @ElementCollection
    private List<OrderLine> orderLines = new ArrayList<>();

    // getter, setters etc. ...
}

@Embeddable
public class OrderLine {

    private String item;
    private BigDecimal price;

    // getter, setters etc. ...
}

To obtain a list of all orders which contain a wooden toy train order line, you could run the following JP-QL query:

List<Order> toyTrainOrders = entityManager
    .createQuery( "FROM Order o JOIN o.orderLines ol WHERE ol.item LIKE '%wooden toy train%'" )
    .getResultList();

As with other JP-QL queries, Hibernate OGM will convert the query string into a native query for MongoDB and Neo4j. For the other backends a Lucene-based full-text query will be created.

Note that the JOIN syntax at this point is only supported for element collections, i.e. you cannot create join queries for arbitrary associations to other entities. The reason is that most NoSQL stores don't support joins between different tables/collections, therefore such query can't be translated in a sensible way. An exception are graph databases such as Neo4j where joins can be converted into queries based on relationships (which is what actually happens for the element collection case), but we are not quite there yet :)

API for retrieving all executed and failed datastore operations

Hibernate ORM collects all write operations internally and propagates them to the database in most cases only upon transaction commit (in addition, changes will also be flushed prior to query execution or upon explicite flush() calls). This enables many optimizations such as batched inserts. Hibernate OGM follows this approach and also uses transaction boundaries for demarcating units of work and triggering writes to the datastore.

While this naturally works great with transactional NoSQL stores such as Infinispan or Neo4j, it poses some challenges on non-transactional datastores. The 4.2 release therefore provides the initial draft of an API which notifies you upon failed datastore operations, letting you take appropriate action such as e.g. logging all previously applied operations or retrying a failed operation.

In order to not let this release announcement grow too big, there is a separate post just dedicated to this new API.

Support for Fongo

Fongo ("Fake Mongo") is a very nice tool when it comes to testing MongoDB applications. It provides a pure in-memory implementation of the MongoDB Java API which allows to test MongoDB-based applications without starting up an actual MongoDB instance.

Thanks to community member Alex Soto, you can use Fongo now also for testing your Hibernate OGM based application. To do so, simply add the following dependencies to your project (assuming you work with Maven and have added the Hibernate OGM BOM to the dependencyManagement block of your POM file):

<dependencies>
    <dependency>
        <groupId>org.hibernate.ogm</groupId>
        <artifactId>hibernate-ogm-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>com.github.fakemongo</groupId>
        <artifactId>fongo</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Then specify "fongodb" as the Hibernate OGM datastore provider, e.g. via a persistence unit property in META-INF/persistence.xml:

<persistence-unit name="example-PU" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
    <properties>
        <property name="hibernate.ogm.datastore.provider" value="fongodb"/>
    </properties>
</persistence-unit>

Hibernate OGM will now use Fongo rather than a real MongoDB server as the backend. As said, this can be quite handy when testing your application, just do not forget to switch to a real datastore when deploying to production ;-)

Usability improvements

Finally, let's take a quick look at two nice usability improvements which you already get with the update to 4.1.3.

The first is a better support for the RESOURCE_LOCAL transaction type when working with stores such as MongoDB under Java SE. As described above, Hibernate OGM relies on transaction demarcation to gather data changes and write them to the datastore in an optimized way. This used to require a JTA implementation on the classpath, also if the underlying datastore actually is not transactional. This is obsolete now, i.e. you can work with RESOURCE_LOCAL and MongoDB, CouchDB etc. without any further dependencies.

If you work with Hibernate OGM and Hibernate Search, you will be happy to learn that the creation of full-text queries became easier. It is not necessary any longer to configure the database retrieval method for each and every FullTextQuery, instead this happens automatically on a global level now when bootstrapping the Hibernate OGM engine.

One of the fundamental principles of Hibernate/JPA is that any writes done through the Session/EntityManager APIs are collected in the persistence context and are only written to the database upon transaction commit. If needed, you can enforce the flushing of changes by explicitly invoking the flush() method. Also Hibernate may trigger a flush automatically, e.g. prior to executing a query. This strategy allows to perform many optimizations, e.g. only persisting the final state of an entity changed several times, make use of batched inserts and others.

Hibernate OGM follows this approach and uses transaction boundaries for demarcating units of work and triggering writes to the datastore. Naturally, this works just fine on transactional NoSQL stores such as Infinispan or Neo4j, but it poses some challenges on stores without full transactional semantics.

For instance consider a method of a stateless EJB (which automatically runs within a container-managed transaction) which inserts three entities. If an error occurs when inserting the last entity, the other two will already have been written. When using a non-transactional datastore, there is no way to rollback these already applied changes. Depending on the specific use case, this may be acceptable; But in other cases it is desirable to take some action, for example retrying the failed insertion or performing compensating writes for the succeeded insertions, effectively undoing them.

This is where our new error handling API comes in. It allows you to get notified upon failed datastore operations or transaction rollback attempts, providing you with the executed and failed operation(s). This e.g. enables you to:

  • log all applied operations
  • retry a failed operation (e.g. after timeouts)
  • make an attempt to compensate applied changes (by executing an inverse operation)

An example error handler

Let’s take a look at an example:

public class ExampleErrorHandler implements ErrorHandler {

    @Override
    public void onRollback(RollbackContext context) {
        // write all applied operations to a log file
        for ( GridDialectOperation appliedOperation : context.getAppliedGridDialectOperations() ) {
            switch ( appliedOperation.getType() ) {
                case INSERT_TUPLE:
                    EntityKeyMetadata entityKeyMetadata = appliedOperation.as( InsertTuple.class ).getEntityKeyMetadata();
                    Tuple tuple = appliedOperation.as( InsertTuple.class ).getTuple();

                    // write EKM and tuple to log file...
                    break;
                case REMOVE_TUPLE:
                    // ...
                    break;
                case ...
                    // ...
                    break;
            }
        }
    }

    @Override
    public ErrorHandlingStrategy onFailedGridDialectOperation(FailedGridDialectOperationContext context) {
        // Ignore this exception and continue
        if ( context.getException() instanceof TupleAlreadyExistsException ) {
            GridDialectOperation failedOperation = context.getFailedOperation();
            // write to log ...

            return ErrorHandlingStrategy.CONTINUE;
        }
        // But abort on all others
        else {
            return ErrorHandlingStrategy.ABORT;
        }
    }
}

The onRollback() method - which is called when the transaction (or unit of work) is rolled back (either by the user or by the container) - shows how to iterate over all datastore operations applied prior to the rollback attempt, examine their specific type and e.g. write them to a log file.

The onFailedGridDialectOperation() method is called for each specific datastore operation failing. It lets you decide whether to continue - ignoring the failure - or abort the operation. If ABORT is returned, the causing exception will be re-thrown, eventually causing the current transaction to be rolled back. If CONTINUE is returned, that exception will be ignored, causing the current transaction to continue.

The decision whether to abort or continue can be based on the specific exception type or on the grid dialect operation which caused the failure. In the example all exceptions of type TupleAlreadyExistsException are ignored (meaning we don't care about duplicate records being inserted into the datastore), whereas all other exceptions cause the current unit of work to be aborted. You also could react to datastore-specific exceptions such as MongoDB’s MongoTimeoutException, if needed.

Having created the ErrorHandler implementation, it needs to be registered with Hibernate OGM. You can do so for instance using a persistence unit property in META-INF/persistence.xml:

<property name="hibernate.ogm.error_handler" value="com.example.ExampleErrorHandler"/>

Feedback needed!

In its current form the API lays the ground for manually performing tasks such as retrying, logging and similar. But we envision a more automated approach in future versions, e.g. for automatic retries of failed operations.

Of course this API can and will not bring transactional guarantees to datastores which don't support them natively. If you find yourself frequently in a situation where you wish for transactional "all or nothing" semantics, you might consider to move to a datastore which actually provides this functionality. But you also may look into more suitable mapping approaches. For instance embeddables and element collections are a great way for ensuring atomicity of an entity and dependent structures on document stores such as MongoDB or CouchDB, as they will be mapped to a single, hierarchically structured document which can updated with a single datastore call.

At this point, the API is considered experimental and will evolve in future releases. For this, your input is very important to us! Let us know what you would like to do with such an API and what functionality should be added. Just tweet to @Hibernate or send a mail to our development list. If you like, you also may add comments to the JIRA issues addressing further development of the API: OGM-775 ("Introduce RETRY error handling strategy"), OGM-776 ("Provide means for executing compensating actions") and OGM-777 ("Expose more context information via error handler contexts").

Any feedback is greatly appreciated!

It’s my pleasure to announce the release of Hibernate OGM 4.1.2!

This maintenance release fixes several bugs, e.g. around JP-QL, using Hibernate OGM in SaaS environments or mapping byte[] properties on CouchDB. We also clarified several issues in the reference guide. Many thanks to everyone test-driving Hibernate OGM and reporting bugs (and feature requests) to us!

As always you can get this release as ZIP or TAR.GZ from SourceForge or use the following GAV coordinates with your preferred build tool:

  • org.hibernate.ogm:hibernate-ogm-core:4.1.2.Final for the Hibernate OGM engine and
  • org.hibernate.ogm:hibernate-ogm-<%DATASTORE%>:4.1.2.Final, depending on the backend you want to use.

While preparing another release for fixing some more issues in Hibernate OGM 4.1, we take in parallel the first steps towards Hibernate OGM 4.2. You can expect many improvements in the field of JP-QL queries, support for custom types, an SPI for logging executed/failed operations on non-transactional NoSQL stores and much more. The first 4.2 Alpha will be out soon.

Finally, some useful links:

NoSQL with Hibernate OGM 101: Persisting your first entities

Posted by Gunnar Morling    |       |    Tagged as Hibernate OGM

The first final version of Hibernate OGM is out and we’ve recovered a bit from the release frenzy. So we thought it’d be a good idea to begin the new year with a tutorial-style blog series, which shows how to get started with Hibernate OGM and what it can do for you. Just in case you missed the news, Hibernate OGM is the newest project under the Hibernate umbrella and allows you to persist entity models in different NoSQL stores via the well-known JPA.

We’ll cover these topics in the following weeks:

  • Persisting your first entities (this instalment)
  • Querying for your data
  • Running on WildFly
  • Running with CDI on Java SE
  • Store data into two different stores in the same application

If you’d like us to discuss any other topics, please let us know. Just add a comment below or tweet your suggestions to us.

In this first part of the series we are going to set up a Java project with the required dependencies, create some simple entities and write/read them to and from the store. We’ll start with the Neo4j graph database and then we’ll switch to the MongoDB document store with only a small configuration change.

Project set-up

Let’s first create a new Java project with the required dependencies. We’re going to use Maven as a build tool in the following, but of course Gradle or others would work equally well.

Add this to the dependencyManagement block of your pom.xml:

...
<dependencyManagement>
    <dependencies>
        ...
        <dependency>
            <groupId>org.hibernate.ogm</groupId>
            <artifactId>hibernate-ogm-bom</artifactId>
            <type>pom</type>
            <version>4.1.1.Final</version>
            <scope>import</scope>
        </dependency>
            ...
    </dependencies>
</dependencyManagement>
...

This will make sure that you are using matching versions of the Hibernate OGM modules and their dependencies. Then add the following to the dependencies block:

...
<dependencies>
    ...
    <dependency>
        <groupId>org.hibernate.ogm</groupId>
        <artifactId>hibernate-ogm-neo4j</artifactId>
    </dependency>
    <dependency>
        <groupId>org.jboss.jbossts</groupId>
        <artifactId>jbossjta</artifactId>
    </dependency>
    ...
</dependencies>
...

The dependencies are:

  • The Hibernate OGM module for working with an embedded Neo4j database; This will pull in all other required modules such as Hibernate OGM core and the Neo4j driver. When using MongoDB, you’d swap that with hibernate-ogm-mongodb.
  • JBoss' implementation of the Java Transaction API (JTA), which is needed when not running within a Java EE container such as WildFly

The domain model

Our example domain model is made up of three classes: Hike, HikeSection and Person.

There is a composition relationship between Hike and HikeSection, i.e. a hike comprises several sections whose life cycle is fully dependent on the Hike. The list of hike sections is ordered; This order needs to be maintained when persisting a hike and its sections.

The association between Hike and Person (acting as hike organizer) is a bi-directional many-to-one/one-to-many relationship: One person can organize zero ore more hikes, whereas one hike has exactly one person acting as its organizer.

Mapping the entities

Now let’s map the domain model by creating the entity classes and annotating them with the required meta-data. Let’s start with the Person class:

@Entity
public class Person {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private long id;

    private String firstName;
    private String lastName;

    @OneToMany(mappedBy = "organizer", cascade = CascadeType.PERSIST)
    private Set<Hike> organizedHikes = new HashSet<>();

    // constructors, getters and setters...
}

The entity type is marked as such using the @Entity annotation, while the property representing the identifier is annotated with @Id.

Instead of assigning ids manually, Hibernate OGM can take care of this, offering several id generation strategies such as (emulated) sequences, UUIDs and more. Using a UUID generator is usually a good choice as it ensures portability across different NoSQL datastores and makes id generation fast and scalable. But depending on the store you work with, you also could use specific id types such as object ids in the case of MongoDB (see the reference guide for the details).

Finally, @OneToMany marks the organizedHikes property as an association between entities. As it is a bi-directional entity, the mappedBy attribute is required for specifying the side of the association which is in charge of managing it. Specifying the cascade type PERSIST ensures that persisting a person will automatically cause its associated hikes to be persisted, too.

Next is the Hike class:

@Entity
public class Hike {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

    private String description;
    private Date date;
    private BigDecimal difficulty;

    @ManyToOne
    private Person organizer;

    @ElementCollection
    @OrderColumn(name = "sectionNo")
    private List<HikeSection> sections;

    // constructors, getters and setters...
}

Here the @ManyToOne annotation marks the other side of the bi-directional association between Hike and Organizer. As HikeSection is supposed to be dependent on Hike, the sections list is mapped via @ElementCollection. To ensure the order of sections is maintained in the datastore, @OrderColumn is used. This will add one extra "column" to the persisted records which holds the order number of each section.

Finally, the HikeSection class:

@Embeddable
public class HikeSection {

    private String start;
    private String end;

    // constructors, getters and setters...
}

Unlike Person and Hike, it is not mapped via @Entity but using @Embeddable. This means it is always part of another entity (Hike in this case) and as such also has no identity on its own. Therefore it doesn’t declare any @Id property.

Note that these mappings looked exactly the same, had you been using Hibernate ORM with a relational datastore. And indeed that’s one of the promises of Hibernate OGM: Make the migration between the relational and the NoSQL paradigms as easy as possible!

Creating the persistence.xml

With the entity classes in place, one more thing is missing, JPA's persistence.xml descriptor. Create it under src/main/resources/META-INF/persistence.xml:

<?xml version="1.0" encoding="utf-8"?>

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0">

    <persistence-unit name="hikePu" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>

        <properties>
            <property name="hibernate.ogm.datastore.provider" value="neo4j_embedded" />
            <property name="hibernate.ogm.datastore.database" value="HikeDB" />
            <property name="hibernate.ogm.neo4j.database_path" value="target/test_data_dir" />
        </properties>
    </persistence-unit>
</persistence>

If you have worked with JPA before, this persistence unit definition should look very familiar to you. The main difference to using the classic Hibernate ORM on top of a relational database is the specific provider class we need to specify for Hibernate OGM: org.hibernate.ogm.jpa.HibernateOgmPersistence.

In addition, some properties specific to Hibernate OGM and the chosen back end are defined to set:

  • the back end to use (an embedded Neo4j graph database in this case)
  • the name of the Neo4j database
  • the directory for storing the Neo4j database files

Depending on your usage and the back end, other properties might be required, e.g. for setting a host, user name, password etc. You can find all available properties in a class named <BACK END>Properties, e.g. Neo4jProperties, MongoDBProperties and so on.

Saving and loading an entity

With all these bits in place its time to persist (and load) some entities. Create a simple JUnit test shell for doing so:

public class HikeTest {

    private static EntityManagerFactory entityManagerFactory;

    @BeforeClass
    public static void setUpEntityManagerFactory() {
        entityManagerFactory = Persistence.createEntityManagerFactory( "hikePu" );
    }

    @AfterClass
    public static void closeEntityManagerFactory() {
        entityManagerFactory.close();
    }
}

The two methods manage an entity manager factory for the persistence unit defined in persistence.xml. It is kept in a field so it can be used for several test methods (remember, entity manager factories are rather expensive to create, so they should be initialized once and be kept around for re-use).

Then create a test method persisting and loading some data:

@Test
public void canPersistAndLoadPersonAndHikes() {
    EntityManager entityManager = entityManagerFactory.createEntityManager();

    entityManager.getTransaction().begin();

    // create a Person
    Person bob = new Person( "Bob", "McRobb" );

    // and two hikes
    Hike cornwall = new Hike(
            "Visiting Land's End", new Date(), new BigDecimal( "5.5" ),
            new HikeSection( "Penzance", "Mousehole" ),
            new HikeSection( "Mousehole", "St. Levan" ),
            new HikeSection( "St. Levan", "Land's End" )
    );
    Hike isleOfWight = new Hike(
            "Exploring Carisbrooke Castle", new Date(), new BigDecimal( "7.5" ),
            new HikeSection( "Freshwater", "Calbourne" ),
            new HikeSection( "Calbourne", "Carisbrooke Castle" )
    );

    // let Bob organize the two hikes
    cornwall.setOrganizer( bob );
    bob.getOrganizedHikes().add( cornwall );

    isleOfWight.setOrganizer( bob );
    bob.getOrganizedHikes().add( isleOfWight );

    // persist organizer (will be cascaded to hikes)
    entityManager.persist( bob );

    entityManager.getTransaction().commit();

    // get a new EM to make sure data is actually retrieved from the store and not Hibernate's internal cache
    entityManager.close();
    entityManager = entityManagerFactory.createEntityManager();

    // load it back
    entityManager.getTransaction().begin();

    Person loadedPerson = entityManager.find( Person.class, bob.getId() );
    assertThat( loadedPerson ).isNotNull();
    assertThat( loadedPerson.getFirstName() ).isEqualTo( "Bob" );
    assertThat( loadedPerson.getOrganizedHikes() ).onProperty( "description" ).containsOnly( "Visiting Land's End", "Exploring Carisbrooke Castle" );

    entityManager.getTransaction().commit();

    entityManager.close();
}

Note how both actions happen within a transaction. Neo4j is a fully transactional datastore which can be controlled nicely via JPA’s transaction API. Within an actual application one would probably work with a less verbose approach for transaction control. Depending on the chosen back end and the kind of environment your application runs in (e.g. a Java EE container such as WildFly), you could take advantage of declarative transaction management via CDI or EJB. But let’s save that for another time.

Having persisted some data, you can examine it, using the nice web console coming with Neo4j. The following shows the entities persisted by the test:

Hibernate OGM aims for the most natural mapping possible for the datastore you are targeting. In the case of Neo4j as a graph datastore this means that any entity will be mapped to a corresponding node.

The entity properties are mapped as node properties (see the black box describing one of the Hike nodes). Any not natively supported property types will be converted as required. E.g. that’s the case for the date property which is persisted as an ISO-formatted String. Additionally, each entity node has the label ENTITY (to distinguish it from nodes of other types) and a label specifying its entity type (Hike in this case).

Associations are mapped as relationships between nodes, with the association role being mapped to the relationship type.

Note that Neo4j does not have the notion of embedded objects. Therefore, the HikeSection objects are mapped as nodes with the label EMBEDDED, linked with the owning Hike nodes. The order of sections is persisted via a property on the relationship.

Switching to MongoDB

One of Hibernate OGM's promises is to allow using the same API - namely, JPA - to work with different NoSQL stores. So let’s see how that holds and make use of MongoDB which, unlike Neo4j, is a document datastore and persists data in a JSON-like representation. To do so, first replace the Neo4j back end with the following one:

...
<dependency>
    <groupId>org.hibernate.ogm</groupId>
    <artifactId>hibernate-ogm-mongodb</artifactId>
</dependency>
...

Then update the configuration in persistence.xml to work with MongoDB as the back end, using the properties accessible through MongoDBProperties to give host name and credentials matching your environment (if you don’t have MongoDB installed yet, you can download it here):

...
<properties>
    <property name="hibernate.ogm.datastore.provider" value="mongodb" />
    <property name="hibernate.ogm.datastore.database" value="HikeDB" />
    <property name="hibernate.ogm.datastore.host" value="mongodb.mycompany.com" />
    <property name="hibernate.ogm.datastore.username" value="db_user" />
    <property name="hibernate.ogm.datastore.password" value="top_secret!" />
</properties>
...

And that’s all you need to do to persist your entities in MongoDB rather than Neo4j. If you now run the test again, you’ll find the following BSON documents in your datastore:

# Collection "Person"
{
    "_id" : "50b62f9b-874f-4513-85aa-c2f59015a9d0",
    "firstName" : "Bob",
    "lastName" : "McRobb",
    "organizedHikes" : [
        "a78d731f-eff0-41f5-88d6-951f0206ee67",
        "32384eb4-717a-43dc-8c58-9aa4c4e505d1"
    ]
}
# Collection Hike
{
    "_id" : "a78d731f-eff0-41f5-88d6-951f0206ee67",
    "date" : ISODate("2015-01-16T11:59:48.928Z"),
    "description" : "Visiting Land's End",
    "difficulty" : "5.5",
    "organizer_id" : "50b62f9b-874f-4513-85aa-c2f59015a9d0",
    "sections" : [
        {
            "sectionNo" : 0,
            "start" : "Penzance",
            "end" : "Mousehole"
        },
        {
            "sectionNo" : 1,
            "start" : "Mousehole",
            "end" : "St. Levan"
        },
        {
            "sectionNo" : 2,
            "start" : "St. Levan",
            "end" : "Land's End"
        }
    ]
}
{
    "_id" : "32384eb4-717a-43dc-8c58-9aa4c4e505d1",
    "date" : ISODate("2015-01-16T11:59:48.928Z"),
    "description" : "Exploring Carisbrooke Castle",
    "difficulty" : "7.5",
    "organizer_id" : "50b62f9b-874f-4513-85aa-c2f59015a9d0",
    "sections" : [
        {
            "sectionNo" : 1,
            "start" : "Calbourne",
            "end" : "Carisbrooke Castle"
        },
        {
            "sectionNo" : 0,
            "start" : "Freshwater",
            "end" : "Calbourne"
        }
    ]
}

Again, the mapping is very natural and just as you’d expect it when working with a document store like MongoDB. The bi-directional one-to-many/many-to-one association between Person and Hike is mapped by storing the referenced id(s) on either side. When loading back the data, Hibernate OGM will resolve the ids and allow to navigate the association from one object to the other.

Element collections are mapped using MongoDB's capabilities for storing hierarchical structures. Here the sections of a hike are mapped to an array within the document of the owning hike, with an additional field sectionNo to maintain the collection order. This allows to load an entity and its embedded elements very efficiently via a single round-trip to the datastore.

Wrap-up

In this first instalment of NoSQL with Hibernate OGM 101 you’ve learned how to set up a project with the required dependencies, map some entities and associations and persist them in Neo4j and MongoDB. All this happens via the well-known JPA API. So if you have worked with Hibernate ORM and JPA in the past on top of relational databases, it never was easier to dive into the world of NoSQL.

At the same time, each store is geared towards certain use cases and thus provides specific features and configuration options. Naturally, those cannot be exposed through a generic API such as JPA. Therefore Hibernate OGM lets you make usage of native NoSQL queries and allows to configure store-specific settings via its flexible option system.

You can find the complete example code of this blog post on GitHub. Just fork it and play with it as you like.

Of course storing entities and getting them back via their id is only the beginning. In any real application you’d want to run queries against your data and you’d likely also want to take advantage of some specific features and settings of your chosen NoSQL store. We’ll come to that in the next parts of this series, so stay tuned!

It’s my pleasure to announce the first maintenance release of Hibernate OGM 4.1! This version makes a few more data types usable for your entity properties (float, short, char), comes with several component upgrades (Hibernate ORM 4.3.8 and Infinispan 7.0.3) and fixes some bugs.

The latter were discovered by helpful users who gave Hibernate OGM a spin after 4.1 was out in December. Kudos to everyone testing the library and reporting bugs or feature requests, that’s much appreciated!

We see an increased interest in Hibernate OGM by means of questions in the forum. Keep those coming; specifically we’re looking forward to your feature proposals, so we know which functionality we should implement next to provide the most value for you. We are also monitoring the hibernate-ogm tag on Stack Overflow. So if that’s more your kind of thing, ask your question there and we’ll come up with an answer.

To give the new release a try, either download the release bundle from SourceForge or use these GAV coordinates with your preferred build tool:

  • org.hibernate.ogm:hibernate-ogm-core:4.1.1.Final for the Hibernate OGM engine and
  • org.hibernate.ogm:hibernate-ogm-<%DATASTORE%>:4.1.1.Final, depending on the backend you want to use.

Also let me use the opportunity to say a big Thank You to our community member Ajay Bhat who contributed the support for the new data types!

Finally, some useful links:

It’s my great pleasure to announce the release of Hibernate OGM 4.1.0.Beta7! The release brings support for MongoDB’s object id, a clarification of what are our public API/SPI packages as well as several bugfixes and many other improvements.

Use the following GAV coordinates with tools such as Maven, Gradle etc.:

  • org.hibernate.ogm:hibernate-ogm-core:4.1.0.Beta7 for the Hibernate OGM engine and
  • org.hibernate.ogm:hibernate-ogm-<%DATASTORE%>:4.1.0.Beta7, depending on the backend you want to use.

Alternatively, there is a release bundle containing Hibernate OGM and all its dependencies available for download from SourceForge.

Support for MongoDB’s object id

When talking about Hibernate OGM, one of the most requested features we heard was support for the native object id type in MongoDB. Finally we got around to implementing this feature.

You can map object ids either directly via MongoDB’s org.bson.types.ObjectId type or using a String. The following shows an example:

@Entity
public class GolfPlayer {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Type(type = "objectid")
        private String id;

        // Alternatively, the following could be used:
        // @Id
        // @GeneratedValue(strategy = GenerationType.IDENTITY)
        // private ObjectId id;

        private String name;

        private double handicap;

        //...
}

The @GeneratedValue annotation causes the id to be automatically generated by MongoDB upon insertion of the entity, similar to e.g. AUTO_INCREMENT columns in MySQL. The @Type annotation makes sure the string is mapped as an object id rather than as plain string. So a GolfPlayer document could e.g. look like this:

{
    "_id" : ObjectId("542ac33630043ffe5bcb4efa"),
    "name" : "Alexis",
    "handicap" : 9.7
}

Also related to MongoDB is a nice improvement around JP-QL queries. You can now refer to properties of embeddable objects in your queries:

@Entity
@NamedQuery(name = PersonsByCity, query = "FROM Person p WHERE p.address.city = :pCity")
public class Person {

        @Id
        private ObjectId id;

        @Embedded
        private Address address;

        // ...
}

Here, the named query refers to the city property of the embedded address object.

API/SPI package restructuring

As we’re on our road to the 4.1.0.Final release, we spent a fair amount of time for clearly separating the OGM code base into API, SPI and internal packages. Our goal is to make clear what is supported in the long term and what is not.

API packages (application programming interface) are all those packages which are intended to be accessed by users of Hibernate OGM, i.e. people building applications on top of it. Any package which does not have “spi” or “impl” in its name is an API package. Note that there are only very few API packages in Hibernate OGM. Most of the time you will work with the JPA (javax.persistence.* packages) or the “classic” API from Hibernate ORM.

SPI packages (service provider interface) are packages which contain contracts to be used and/or implemented by authors of custom grid dialects. So if for instance you would write a dialect for your favorite NoSQL store (btw. you should consider to contribute it to OGM), then you would access the SPI packages. They have a “spi” in their name. In order to clearly separate API and SPI, we had to rename several packages and move some types around. So existing custom dialects need to be adapted to this new structure. Good news is that it basically is enough to do a “re-organize imports” in your favorite IDE to adapt to most of the changes. We aim at a stable SPI (and of course API as well) with the 4.1 Final release.

Finally, there are internal packages of the Hibernate OGM engine which are not intended for usage by users nor dialect implementors. You can recognize those by the “impl” in their name. Internal packages and types may be changed, removed etc. without notice. So if you think there is a specific internal type which you need to access, please let us know so we can decide what to do and e.g. promote it to API or SPI.

Please refer to the migration notes to learn more about the package changes in this release.

Useful links

As always we’re very interested in your feedback. Here are some helpful links for you:

So give it a try and let us know how you like this release!

The Hibernate team is very happy to announce the release of another Beta of Hibernate OGM 4.1!

Progress has been made with respect to query execution and the Neo4j dialect. Also we do provide a so-called Bill of Materials POM now which the Maven users out there will appreciate (details below).

The GAV coordinates to be used with Maven, Gradle etc. are:

  • org.hibernate.ogm:hibernate-ogm-core:4.1.0.Beta6 for the OGM engine and
  • org.hibernate.ogm:hibernate-ogm-<%DATASTORE%>:4.1.0.Beta6, depending on the backend you want to use.

Alternatively you can fetch a release bundle containing Hibernate OGM and all its dependencies from SourceForge.

Please note that this new release requires Hibernate ORM 4.3.6.Final or later.

Query improvements

We've reworked major parts of the integration with the query execution machinery from ORM. This enables quite a few improvements in the field of JP-QL as well as native queries.

One is support for polymorphic queries also on those backends which don't use Hibernate Search for querying (Neo4j and MongoDB). This means queries targetting a super-class will return instances of any mapped sub-class as well.

Furthermore, Hibernate OGM now shows the same behavior with respect to auto-flushing you already know from Hibernate ORM. That is, if you submit a query, all pending changes to entities of the effected types will be flushed to the data store in order to ensure queries don't return any stale data. Whereas this works nicely on stores supporting full transaction semantics (namely, Neo4j), some care must be taken on stores with limited or non-existing rollback capabilities. Refer to the reference guide to learn more about the details.

In addition we took measures to cache native queries derived from JP-QL queries. Note that this requires Hibernate ORM 4.3.6.Final or newer. Generally we strive for compatibility with a complete minor release family (4.3.x), but in this case we need to make use of some advanced SPIs only introduced in 4.3.6. The module ZIP we provide for WildFly contains an updated ORM module as well. This will be added along side the existing ORM module, which remains unchanged.

More natural association mappings in Neo4j

As part of our ongoing work on the Neo4j dialect, associations are mapped to relationships finally the way you'd expect it. There used to be redundant properties on associations which are gone now. Only actual association properties are stored on relationships, e.g. the order of the elements of an ordered list. The following shows an example:

Here we have an entity Father with an ordered collection of Child entities which is mapped by a relationship to each Child node. The birthorder attribute (the name has been given via @OrderColumn) is stored as property on the relationships, just as it naturally makes sense.

On a tangent, we've updated to Neo4j 2.1.3.

Simplified version management

Another big usage improvement for Maven users comes in form of our new Bill of Material POM (BOM). This POM defines a set of matching versions of the Hibernate OGM modules and their dependencies, such as Hibernate ORM, Hibernate Search or the different datatstore connectors.

All you need to do is to add this BOM to the dependencyManagement block of your project POM using the special import scope:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.hibernate.ogm</groupId>
            <artifactId>hibernate-ogm-bom</artifactId>
            <version>4.1.0.Beta6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Then you can declare dependencies to Hibernate OGM or any of the related modules without specifying a version, which you will get automatically from the BOM:

<dependencies>
    <dependency>
        <groupId>org.hibernate.ogm</groupId>
        <artifactId>hibernate-ogm-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-search-orm</artifactId>
    </dependency>
    <dependency>
        <groupId>org.hibernate.javax.persistence</groupId>
        <artifactId>hibernate-jpa-2.1-api</artifactId>
    </dependency>
    ...
</dependencies>

To update to a new version of Hibernate OGM, simply update the referenced version of the BOM. This in turn will give you updated versions of any dependencies as required.

Your feedback matters

As we're approaching the Final release of Hibernate OGM 4.1 soon, your feedback matters more than ever! You can use the following tools to get in touch:

back to top