Red Hat

In Relation To Gunnar Morling

In Relation To Gunnar Morling

It’s my pleasure to announce the release of Hibernate Validator 5.2.3.Final!

Wait, didn’t we already do another Hibernate Validator release earlier this month? That’s right, indeed we pushed out the first Alpha of the 5.3 family a couple of days ago. And normally, that’d mean that there would be no further releases of earlier version families.

But in this case we decided to do an exception from the rule as we noticed that Hibernate Validator couldn’t be used with Java 9 (check out issue HV-1048 if you are interested in the details). As we don’t want to keep integrators and users of Hibernate Validator from testing their own software on Java 9, we decided to fix that issue on the current stable release line (in fact we strongly encourage you to test your applications on Java 9 to learn as early as possible about any potential changes you might need to make).

While we were at it, we backported some further bugfixes from 5.3 to 5.2, amongst them one for ensuring compatability with the Google App Engine. As always, you can find the complete list of fixes in the changelog.

Where do I get it?

Use the GAV coordinates org.hibernate:{hibernate-validator|hibernate-validator-cdi|hibernate-validator-annotation-processor}:5.2.3.Final to fetch the release with Maven, Gradle etc. Alternatively, you can find distribution bundles containing all the bits on SourceForge (TAR.GZ, ZIP).

Found a bug? Have a feature request? Then let us know through the following channels:

Hibernate Validator 5.3.0.Alpha1 is out

Posted by Gunnar Morling    |       |    Tagged as Hibernate Validator Releases

It’s my pleasure to announce the first release of Hibernate Validator 5.3!

The overarching idea for the 5.3 timeline is to prototype several features which may potentially be standardized in the Bean Validation 2.0 specification. For instance we’ll work on a solution for the long-standing request for sorting the constraints on single properties.

If you’d like to see any specific features addressed in that prototyping work (and eventually included in BV 2.0), then please get in touch and let us know which are the most important things you are missing from the spec. We’ve compiled a first list of issues we are considering for inclusion in BV 2.0. For sure we cannot address all of them, so it’ll greatly help if you tell us what would be most helpful to you.

Dynamic payloads for constraints

To get things rolling, the Alpha 1 allows to you to enrich custom constraint violations with additional context data. Code examining constraint violations can access and interpret this data in a safer way than by parsing string-based constraint violation messages. Think of it as a dynamic variant of the existing Bean Validation payload feature.

As an example, let’s assume we have a constraint @Matches for making sure a long property matches a given value with some tolerance:

public static class Package {

    @Matches(value=1000, tolerance=100)
    public long weight;
}

If the annotated value is invalid, the resulting constraint violation should have a specific severity, depending on whether the value lies within the given tolerance or not. That severity value could then for instance be used for formatting the error specifically in a UI.

The definition of the @Matches constraint is nothing new, it’s just a regular custom constraint annotation:

@Retention(RUNTIME)
@Constraint(validatedBy = { MatchesValidator.class })
@Documented
public @interface Matches {

    public enum Severity { WARN, ERROR; }

    String message() default "Must match {value} with a tolerance of {tolerance}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    long value();
    long tolerance();
}

The constraint validator is where it’s getting interesting:

public class MatchesValidator implements ConstraintValidator<Matches, Long> {

    private long tolerance;
    private long value;

    @Override
    public void initialize(Matches constraintAnnotation) {
        this.value = constraintAnnotation.value();
        this.tolerance = constraintAnnotation.tolerance();
    }

    @Override
    public boolean isValid(Long value, ConstraintValidatorContext context) {
        if ( value == null ) {
            return true;
        }

        if ( this.value == value.longValue() ) {
            return true;
        }

        HibernateConstraintValidatorContext hibernateContext = context.unwrap(
                HibernateConstraintValidatorContext.class
        );
        hibernateContext.withDynamicPayload(
                Math.abs( this.value - value ) < tolerance ? Severity.WARN : Severity.ERROR
        );

        return false;
    }
}

In isValid() the severity object is set via HibernateConstraintValidatorContext#withDynamicPayload(). Note that the payload object must be serializable in case constraint violations are sent to remote clients, e.g. via RMI.

Validation clients may then access the dynamic payload like so:

HibernateConstraintViolation<?> violation = violations.iterator()
    .next()
    .unwrap( HibernateConstraintViolation.class );

if ( violation.getDynamicPayload( Severity.class ) == Severity.ERROR ) {
    // ...
}

What else is there?

Other features of the Alpha 1 releases are improved OSGi support (many thanks to Benson Margulies for this!), optional relaxation of parameter constraints (kudos to Chris Beckey!) and several bug fixes and improvements, amongst them support for cross-parameter constraints in the annotation processor (cheers to Nicola Ferraro!).

You can find the complete list of all addressed issues in the change log. To get the release with Maven, Gradle etc. use the GAV coordinates org.hibernate:{hibernate-validator|hibernate-validator-cdi|hibernate-validator-annotation-processor}:5.3.0.Alpha1. Alternatively, a distribution bundle containing all the bits is provided on on SourceForge (TAR.GZ, ZIP).

To get in touch, use the following channels:

Hibernate Validator 5.2.2 released

Posted by Gunnar Morling    |       |    Tagged as Hibernate Validator Releases

I am happy to announce the availability of Hibernate Validator 5.2.2.Final.

This release fixes several bugs, including a nasty regression around private property declarations in inheritance hierarchies and a tricky issue related to classloading in environments such as OSGi.

We also closed a gap in the API for constraint declaration which allows to ignore annotation-based constraints for specific methods, parameters etc.:

HibernateValidatorConfiguration config = Validation.byProvider( HibernateValidator.class ).configure();

ConstraintMapping mapping = config.createConstraintMapping();
mapping.type( OrderService.class )
    .method( "placeOrder", Item.class, int.class )
        .ignoreAnnotations( true )
        .parameter( 0 )
            .ignoreAnnotations( false );
config.addMapping( mapping );

Validator validator = config.buildValidatorFactory().getValidator();

Please refer to the change log for the complete list of all issues. You can get the release with Maven, Gradle etc. using the GAV coordinates org.hibernate:hibernate-validator::5.2.2.Final. Alternatively, a distribution bundle is provided on on SourceForge (TAR.GZ, ZIP).

Get in touch through the following channels:

Order, ooorder! Sorting results in Hibernate Search 5.5

Posted by Gunnar Morling    |       |    Tagged as Hibernate Search

"Order, ooorder!" - Sometimes not only the honourable members of the House of Commons need to be called to order, but also the results of Hibernate Search queries need to be ordered in a specific way.

To do so, just pass a Sort object to your full-text query before executing it, specifying the field(s) to sort on:

FullTextSession session = ...;
QueryParser queryParser = ...;

FullTextQuery query = session.createFullTextQuery( queryParser.parse( "summary:lucene" ), Book.class );
Sort sort = new Sort( new SortField( "title", SortField.Type.STRING, false ) );
query.setSort( sort );
List<Book> result = query.list();

As of Lucene 5 (which is what Hibernate Search 5.5 is based on), there is a big performance gain if the fields to sort on are known up front. In this case these fields can be stored as so-called "doc value fields", which is much faster and less memory-consuming than the traditional approach of index un-inverting.

For that purpose, Hibernate Search provides the new annotation @SortableField (and it’s multi-valued companion, @SortableFields) for tagging those fields that should be available for sorting. The following example shows how do it:

@Entity
@Indexed(index = "Book")
public class Book {

    @Id
    private Integer id;

    @Field
    @SortableField
    @DateBridge(resolution = Resolution.DAY)
    private Date publicationDate;

    @Fields({
        @Field,
        @Field(name = "sortTitle", analyze = Analyze.NO, store = Store.NO, index = Index.NO)
    })
    @SortableField(forField = "sortTitle")
    private String title;

    @Field
    private String summary;

    // constructor, getters, setters ...
}

@SortableField is used next to the known @Field annotation. In case a single field exists for a given property (e.g. publicationDate) just specifying the @SortableField annotation is enough to make that field sortable. If several fields exist (see the title property), specify the field name via @SortableField#forField().

Note that sort fields must not be analyzed. In case you want to index a given property analyzed for searching purposes, just add another, un-analyzed field for sorting as it is shown for the title property. If the field is only needed for sorting and nothing else, you may configure it as un-indexed and un-stored, thus avoid unnecessary index growth.

For using the configured sort fields when querying nothing has changed. Just specify a Sort with the required field(s):

FullTextQuery query = ...;
Sort sort = new Sort(
    new SortField( "publicationDate", SortField.Type.LONG, false ),
    new SortField( "sortTitle", SortField.Type.STRING, false )
);
query.setSort( sort );

Now what happens if you sort on fields which you have not explicitly declared as sortable, e.g. when migrating an existing application over to Hibernate Search 5.5? The good news is that the sort will be applied as expected from a functional perspective. Hibernate Search detects the missing sort fields and transparently falls back to index-univerting.

But be aware that this comes with a performance penalty (also it is quite memory-intensive as uninverting is RAM-only operation) and it even might happen that this functionality will be removed from Lucene in a future version altogether. Thus watch out for messages like the following in your log files and follow the advice to declare the missing sort fields:

WARN ManagedMultiReader:142 - HSEARCH000289: Requested sort field(s) summary_forSort are not configured for entity \
type org.hibernate.search.test.query.Book mapped to index Book, thus an uninverting reader must be created. You \
should declare the missing sort fields using @SortField.

When migrating an existing application, be sure to rebuild the affected index(es) as described in the reference guide.

With all the required sort fields configured, your search results with be in order, just as the British parliament members after being called to order by Mr. Speaker.

It’s my pleasure to announce the first Alpha release of Hibernate OGM 5!

This release is based on Hibernate ORM 5.0 Final which we released just last week. The update should be smooth in general, but you should be prepared for some changes if you are bootstrapping Hibernate OGM manually through the Hibernate API and not via JPA. If you are using Hibernate OGM on WildFly, you need to adapt your application to the changed module/slot name of the Hibernate OGM core module which has changed from org.hibernate:ogm to org.hibernate.ogm:main.

Check out the Hibernate OGM migration notes to learn more about migrating from earlier versions of Hibernate OGM to 5.x. Also the Hibernate ORM migration guide is a recommended read.

Experimental support for Redis

Hibernate OGM 5 brings tech preview support for Redis which is a high-performance key/value store with many interesting features.

A huge thank you goes out to community member Mark Paluch for this fantastic contribution! Originally started by Seiya Kawashima, Mark took up the work on this backend and delivered a great piece of work in no time. Looking forward to many more of his contributions to come!

The general mapping approach is to store JSON documents as values in Redis. For instance consider the following entity and embeddables:

@Entity
public class Account {

    @Id
    private String login;
    private String password;
    private Address homeAddress;

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

    private String street;
    private String city;
    private String zipCode;
    private String country;
    private AddressType type;

    // getters, setters etc.
}
@Embeddable
public class AddressType {

    private String name;

    // getters, setters etc.
}

This will be persisted into Redis as a JSON document like this under the key "Account:piere":

{
    "homeAddress": {
        "country": "France",
        "city": "Paris",
        "postalCode": "75007",
        "street": "1 avenue des Champs Elysees",
        "type": {
            "name": "main"
        }
    },
    "password": "like I would tell ya"
}

Refer to the Redis chapter of the reference guide to learn more about this new dialect and its capabilities. It is quite powerful already (almost all tests of the Hibernate OGM backend TCK pass) and there is support for using it in WildFly, too.

While JSON is a popular choice for storing structured data amongst Redis users, we will investigate alternative mapping approaches, too. Specifically, one interesting approach would be to store entity properties using Redis hashes. This poses some interesting challenges, though, e.g. regarding type conversion (only String values are supported in hashes) as well as handling of embedded objects and associations.

So if you are faced with the challenge of persisting object models into Redis, give this new backend a try and let us know what you think, open feature requests etc.

Improved mapping of Map properties

Map-typed entity properties are persisted in a more natural format now in MongoDB (and also with the new Redis backend). The following shows an example:

@Entity
public class User {

    @Id
    private String id;

    @OneToMany
    @MapKeyColumn(name = "addressType")
    private Map<String, Address> addresses = new HashMap<>();

    // getters, setters etc.
}

In previous versions of Hibernate OGM this would have been mapped to a MongoDB document like this:

{
    "id" : 123,
    "addresses" : [
        { "addressType" : "home", "addresses_id" : 456 },
        { "addressType" : "work", "addresses_id" : 789 }
    ]
}

This is not what one would expect from a document store mapping, though. Therefore Hibernate OGM 5 will create the following, more natural representation instead:

{
    "id" : 123,
    "addresses" : {
        "home" : 456,
        "work" : 789
    }
}

This representation is more concise and should improve interoperability with other clients working on the same database. If needed - e.g. for migration purposes - you can enforce the previous mapping through the hibernate.ogm.datastore.document.map_storage property. Check out the reference guide for the details.

The optimized mapping is currently only applied if the map key comprises a single column which is of type String. For other types, e.g. Long or composite map keys the previous mapping is used since JSON/BSON only supports field names which are strings.

An open question for us is whether other key column types should be converted into a string or not. If for instance the addresses map was of type Map<Long, Address> one could think of storing the map keys using field names such as "1", "2" etc. Let us know whether that’s something you’d find helpful or not.

Support for multi-get operations

One of the many optimizations in Hibernate ORM is batch fetching of lazily loaded entities. This is controlled using the @BatchSize annotation. So far, Hibernate OGM did not support batch fetching, resulting in more round trips to the datastore than actually needed.

This situation has been improved by introducing MultigetGridDialect which is an optional "capability interface" that Hibernate OGM backends can implement. If a backend happens to support this contract, the Hibernate OGM engine will take advantage of it and fetch entities configured for lazy loading in batches, resulting in a better performance.

At the moment the new Redis backend makes use of this, with the MongoDB and Neo4j backends following soon.

Upgrade to MongoDB driver 3.0

We have upgraded to version 3.0 of the MongoDB driver. Most users of Hibernate OGM should not be affected by this but down the road this will allow us for some nice performance optimizations and support of some new functionality.

Together with the driver update we have reorganized the connection-level options of the MongoDB backend. All String, int and boolean MongoDB client options can be configured now through the hibernate.ogm.mongodb.driver.* namespace:

hibernate.ogm.mongodb.driver.connectTimeout=10000
hibernate.ogm.mongodb.driver.serverSelectionTimeout=3000
hibernate.ogm.mongodb.driver.socketKeepAlive=true

These options will be passed on to MongoDB’s client builder as-is. Note that the previously existing option hibernate.ogm.mongodb.connection_timeout has been removed in favor of this new approach.

Where can I get it?

You can retrieve Hibernate OGM 5.0.0.Alpha1 via Maven etc. using the following coordinates:

  • org.hibernate.ogm:hibernate-ogm-core:5.0.0.Alpha1 for the Hibernate OGM core module

  • org.hibernate.ogm:hibernate-ogm-<%BACKEND%>:5.0.0.Alpha1 for the NoSQL backend you want to use, with <%BACKEND%> being one of "mongodb", "redis", "neo4j" etc.

Alternatively, you can download archives containing all the binaries, source code and documentation from SourceForge.

Als always we are looking forward to your feedback very much. The change log tells in detail what’s in there for you. Get in touch through the following channels:

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!

back to top