Red Hat

In Relation To

The Hibernate team blog on everything data.

Tenth bug-fix release for ORM 5.2

Posted by    |       |    Tagged as Hibernate ORM Releases

The Tenth bug-fix release for Hibernate ORM 5.2 has just been published. It is tagged at https://github.com/hibernate/hibernate-orm/releases/tag/5.2.10

The complete list of changes can be found here (or here for people without a Hibernate Jira account).

For information on consuming the release via your favorite dependency-management-capable build tool, see http://hibernate.org/orm/downloads/

The release bundles can be obtained from SourceForge or BinTray.

Accessing private state of Java 9 modules

Posted by    |       |    Tagged as Discussions

Data-centric libraries often need to access private state of classes provided by the library user.

An example is Hibernate ORM. When the @Id annotation is given on a field of an entity, Hibernate will by default directly access fields - as opposed to calling property getters and setters - to read and write the entity’s state.

Usually, such fields are private. Accessing them from outside code has never been a problem, though. The Java reflection API allows to make private members accessible and access them subsequently from other classes. With the advent of the module system in Java 9, rules for this will change a bit, though.

In the following we’ll explore the options authors of a library provided as a Java 9 module have to access private state of classes defined in other modules.

An example

As an example, let’s consider a simple method which takes an object - e.g. an instance of an entity type defined by the user - and a field name and returns the value of the object’s field of that name. Using reflection, this method could be implemented like this (for the sake of simplicity, we are ignoring the fact that a security manager could be present):

package com.example.library;

public class FieldValueAccessor {

    public Object getFieldValue(Object object, String fieldName) {
        try {
            Class<?> clazz = object.getClass();
            Field field = clazz.getDeclaredField( fieldName );
            field.setAccessible( true );
            return field.get( object );
        }
        catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
            throw new RuntimeException( e );
        }
    }
}

By calling Field#setAccessible() we can obtain the field’s value in the following, even if it had been declared private. The module descriptor for the library module is trivial, it just exports the package of the accessor class:

module com.example.library {
    exports com.example.library;
}

In a second module, representing our application, let’s define a simple "entity":

package com.example.entities;

public class MyEntity {

    private String name;

    public MyEntity(String name) {
        this.name = name;
    }

    // ...
}

And also a simple main method which makes use of the accessor to read a field from the entity:

package com.example.entities;

public class Main {
    public static void main(String... args) {
        FieldValueAccessor accessor = new FieldValueAccessor();
        Object fieldValue = accessor.getFieldValue( new MyEntity( "hey there" ), "name" );
        assert "hey there".equals( fieldValue );
    }
}

As this module uses the library module, we need to declare that dependency in the entity module’s descriptor:

module com.example.myapp {
    requires com.example.library;
}

With the example classes in place, let’s run the code and see what happens. It would have been fine on Java 8, but as of Java 9 we’ll see this exception instead:

java.lang.reflect.InaccessibleObjectException:
Unable to make field private final java.lang.String com.example.entities.MyEntity.name accessible:
module com.example.myapp does not "opens com.example.entities" to module com.example.library

The call to setAccessible() fails, as by default code in one module isn’t allowed to perform so-called "deep reflection" on code in another (named) module.

Open this module!

Now what can be done to overcome this issue? The error message is giving us the right hint already: the package with the type to reflect on must be opened to the module containing the code invoking setAccessible().

If a package has been opened to another module, that module can access the package’s types reflectively at runtime. Note that opening a package will not make it accessible to other modules at compile time; this would require the package to be exported instead (as in the case of the library module above).

There are several options for opening a package. The first is to make the module an open module:

open module com.example.myapp {
    requires com.example.library;
}

This opens up all packages in this module for reflection by all other modules (i.e. this would be the behavior as known from other module systems such as OSGi). In case you’d like some more fine-grained control, you can opt to open specific packages only:

module com.example.myapp {
    opens com.example.entities;
    requires com.example.library;
}

This will allow for deep reflection on the entities package, but not on other packages within the application module. Finally, there is the possibility to limit an opens clause to one or more specific target modules:

module com.example.myapp {
    opens com.example.entities to com.example.library;
    requires com.example.library;
}

That way the library module is allowed to perform deep reflection, but not any other module.

No matter which of these options we use, the library module can now make private fields of types in the entities package of the entities module accessible and subsequently read or write their value.

Opening up packages in one way or another lets library code written prior to Java 9 continue to function as before. It requires some implicit knowledge, though. I.e. application developers need to know which libraries need reflective access to which types so they can open up the right packages. This can become tough to manage in more complex applications with multiple libraries performing reflection.

Luckily, there’s a more explicit approach in the form of variable handles.

Can you handle the var?

Variable handles - defined by JEP 193 - are a very powerful addition to the Java 9 API, providing "read and write access to [variables] under a variety of access modes". Describing them in detail would go far beyond the scope of this post (refer to the JEP and this article if you would like to learn more). For our purposes let’s focus on their capability for accessing fields, representing an alternative to the traditional reflection-based approach.

So how could our FieldValueAccessor class be implemented using variable handles?

Var handles are obtained via the MethodHandles.Lookup class. If such lookup has "private access" to the entities module, it will let us access private fields of that module’s types. To get hold of such lookup, we let the client code pass in a lookup when bootstrapping the library code:

Lookup lookup = MethodHandles.lookup();
FieldValueAccessor accessor = new FieldValueAccessor( lookup );

In FieldValueAccessor#getFieldValue() we can now use the method MethodHandles#privateLookupIn() which will return a new lookup granting private access to the given entity instance. From that lookup we can eventually obtain a VarHandle which allows us to get the object’s field value:

public class FieldValueAccessor {

    private final Lookup lookup;

    public FieldValueAccessor(Lookup lookup) {
        this.lookup = lookup;
    }

    public Object getFieldValue(Object object, String fieldName) {
        try {
            Class<?> clazz = object.getClass();
            Field field = clazz.getDeclaredField( fieldName );

            MethodHandles.Lookup privateLookup = MethodHandles.privateLookupIn( clazz, lookup );
            VarHandle handle = privateLookup.unreflectVarHandle( field );

            return handle.get( object );
        }
        catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException( e );
        }
    }
}

Note that this only works if the original lookup has been created by code in the entities module.

This is because MethodHandles#lookup() is a caller sensitive method, i.e. the returned value will depend on the direct caller of that method. privateLookupIn() checks whether the given lookup is allowed to perform deep reflection on the given class. Thus a lookup obtained in the entities module will do the trick, whereas a lookup retrieved in the library module wouldn’t be of any use.

Which route to take?

Both discussed approaches let libraries access private state from Java 9 modules.

The var handle approach makes the requirements of the library module more explicit, which I like. Expecting a lookup instance during bootstrap should be less error-prone than the rather implicit requirement for opening up packages or modules.

Mails by the OpenJDK team also seem to suggest that - together with their siblings, method handles - var handles are the way to go in the long term. Of course it requires the application module to be cooperative and pass the required lookup. It remains to be seen how this could look like in container / app server scenarios, where libraries typically aren’t bootstrapped by the application code but by the server runtime. Injecting some helper code for obtaining the lookup object upon deployment may be one possible solution.

As var handles only are introduced in Java 9 you might want to refrain from using them if your library is supposed to run with older Java versions, too (actually, you can do both by building multi-release JARs). A very similar approach can be implemented in earlier Java versions using method handles (see MethodHandles.Lookup#findGetter()). Unfortunately, though, there’s no official way to obtain method handles with private access prior to Java 9 and the introduction of privateLookupIn​(). Ironically, the only way to get such handles is employing some reflection.

The final thing to note is that there may be a performance advantage to using var and method handles, as access checking is done only once when getting them (as opposed to every invocation). Some proper benchmarking would be in order, though, to see what’s the difference in a given use case.

As always, your feedback is very welcome. Which approach do you prefer? Or perhaps you’ve found yet other solution we’ve missed so far? Let us know in the comments below.

As the Bean Validation 2.0 spec is making good progress, you may want to try out the features of the new spec revision with your existing Java EE applications.

WildFly, as a compatible Java EE 7 implementation, comes with Bean Validation 1.1 and its reference implementation Hibernate Validator 5 out of the box. In the following we’ll show you how easy it is to upgrade the server’s modules to the latest Bean Validation release, using a patch file provided by Hibernate Validator.

Getting the patch files

First download the patch file of the Hibernate Validator version you want to upgrade to. The latest release of Hibernate Validator at this point is 6.0.0.Alpha2 which implements the 2.0.0.Alpha2 release of Bean Validation. You can simply fetch the patch file for this release from Maven Central. If you are interested in the latest 5.x release of Hibernate Validator - which is the current stable implementation of Bean Validation 1.1 - you’d grab this file instead.

Both patches can be applied to WildFly 10.1 instances. Generally, we provide patch files for the latest stable version of WildFly at the time of the Hibernate Validator release.

Applying and undoing the patch

Once you’ve downloaded the patch file, change to the installation directory of your WildFly instance and run the following command to apply the patch:

./bin/jboss-cli.sh --command="patch apply hibernate-validator-modules-6.0.0.Alpha2-wildfly-10.1.0.Final-patch.zip"

Now (re-)start WildFly and you can begin to experiment with the new features of Hibernate Validator 6 and Bean Validation 2.0, such as the validation of container elements (think List<@Email String> emails), support for the Java 8 date/time API or the new built-in constraints such as @NotEmpty or @Email.

The nice thing of the patch mechanism is that patches aren’t actually modifying the patched WildFly instance. Any modules contained in the patch are just added in a separate "overlays" directory.

So in case you want go back to the version of Hibernate Validator originally coming with the server, just run this command to undo the patch:

./bin/jboss-cli.sh --command="patch rollback --reset-configuration=true"

You can learn more about the WildFly patching infrastructure in general here and here.

Bonus: Fully automated update for integration tests

In case you are running integration tests for your applications using the fabulous Arquillian framework, you can add the following configuration to your pom.xml. This will first download and extract WildFly, then download the patch file and apply it to the unzipped server:

...
<properties>
    <wildfly.version>10.1.0.Final</wildfly.version>
    <wildfly.core.version>1.0.1.Final</wildfly.core.version>
    <hibernate.validator.version>6.0.0.Alpha2</hibernate.validator.version>
</properties>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>3.0.0</version>
            <executions>
                <execution>
                    <id>unpack-wildfly</id>
                    <phase>pre-integration-test</phase>
                    <goals>
                        <goal>unpack</goal>
                    </goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>org.wildfly</groupId>
                                <artifactId>wildfly-dist</artifactId>
                                <version>${wildfly.version}</version>
                                <type>tar.gz</type>
                                <overWrite>false</overWrite>
                                <outputDirectory>${project.build.directory}</outputDirectory>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
                <execution>
                    <id>copy-patch</id>
                    <phase>pre-integration-test</phase>
                    <goals>
                        <goal>copy</goal>
                    </goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>org.hibernate.validator</groupId>
                                <artifactId>hibernate-validator-modules</artifactId>
                                <version>${hibernate.validator.version}</version>
                                <classifier>wildfly-${wildfly.version}-patch</classifier>
                                <type>zip</type>
                                <outputDirectory>${project.build.directory}</outputDirectory>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.wildfly.plugins</groupId>
            <artifactId>wildfly-maven-plugin</artifactId>
            <version>1.1.0.Final</version>
            <dependencies>
                <!-- Contains the patch command -->
                <dependency>
                    <groupId>org.wildfly.core</groupId>
                    <artifactId>wildfly-patching</artifactId>
                    <version>${wildfly.core.version}</version>
                </dependency>
            </dependencies>
            <executions>
                <!-- Currently the WF Maven plug-in cannot apply offline commands,
                     although patch itself wouldn't require a running server;
                     see https://issues.jboss.org/projects/WFMP/issues/WFMP-11 -->
                <execution>
                    <id>start-wildfly-for-patching</id>
                    <phase>pre-integration-test</phase>
                    <goals>
                        <goal>start</goal>
                    </goals>
                </execution>
                <execution>
                    <id>apply-patch-file</id>
                    <phase>pre-integration-test</phase>
                    <goals>
                        <goal>execute-commands</goal>
                    </goals>
                    <configuration>
                        <fail-on-error>false</fail-on-error>
                        <commands>
                            <command>patch apply --path ${project.build.directory}/hibernate-validator-modules-${hibernate.validator.version}-wildfly-${wildfly.version}-patch.zip</command>
                        </commands>
                    </configuration>
                </execution>
                <execution>
                    <id>shutdown-wildfly-for-patching</id>
                    <phase>pre-integration-test</phase>
                    <goals>
                        <goal>shutdown</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <jbossHome>${project.build.directory}/wildfly-${wildfly.version}/</jbossHome>
            </configuration>
        </plugin>
    </plugins>
</build>
...

Applying this configuration will give you a WildFly instance with the latest release of Bean Validation and Hibernate Validator which you then can use as a deployment target for your integration tests, employing the latest Bean Validation 2.0 features. You can find a complete Maven project with a simple Arquillian test on GitHub in the hibernate-demos repository.

As you see it’s not difficult to upgrade WildFly 10 to Bean Validation 2.0, so don’t hesitate and give it a try. Your feedback on the new spec revision is always welcome on the mailing list or in the forum.

Hibernate Community Newsletter 7/2017

Posted by    |       |    Tagged as Discussions Hibernate ORM

Welcome to the Hibernate community newsletter in which we share blog posts, forum, and StackOverflow questions that are especially relevant to our users.

Upcoming events

Java Gruppen Danemark is hosting a High-Performance Hibernate webinar. If you want to participate, then you should register on Eventbrite.

Hibernate OGM will be at Devoxx UK 2017. If you want to learn more about Hibernate OGM and Infinispan, then you should definitely come to see Sanne’s presentation.

Articles

A very handy feature when working with JDBC batch updates is to find out which statement triggered a batch failure. Read this article for more info on this topic.

You can use Hibernate with CockroachDB. Check out this tutorial to see how easily you can integrate them.

Mapping the @OneToMany association is not as easy as you might think. Check out this article which shows you the best way to map a @OneToMany relationship.

Alon Segal shows you how to implement Multitenancy with Spring and Hibernate. Multitenancy is very handy when you need to support multiple customers on a single platform so that each customer is limited to its own tenant.

I read this article which describes a way to provide a JPA AttributeConverter to support Java 1.8 Data/Time types. However, this is not needed since Hibernate has been supported them for quite a while now.

For our Czech readers, Roman Pichlík wrote a very good article about all sorts of application performance issues, and the Open-Session in View is mentioned as well.

For our French readers, eXo platform has written an article that shows you how to integrate eXO with JPA and Hibernate.

Time to upgrade

Hibernate Validator 5.4.1 and 6.0.0 Alpha 2 are out.

GORM 6.1 has been released with support for Hibernate 5.2.

I’m honoured to confirm that I’ll be at Devoxx UK this May in London.

Come along in Gallery Hall at 12:55 on Thursday 11th of May to see a quick demo of Hibernate OGM used to migrate a JPA application from using a relational database to using a fast, scalable and highly available in memory data grid.

We announced support for storing data in Infinispan over the Hot Rod protocol in Hibernate OGM version 5.1, now is your chance to see it in action.

My slot is a "tools in action" and we’ll get straight to the point: find all details here.

Devoxx UK 2017 speaker button - Sanne Grinovero

New foray into serverless - announcing library shift

Posted by    |       |    Tagged as Discussions

Red Hat has been exploring serverless (aka FaaS) through the Fabric8 Funktion project. It has been long due for us to get serious on the subject. We are turning all of our libraries into services starting today. This is going to be a multi year effort but we are committed to it.

We thought hard and long about which service to start with. In our performance lab, we realized that the slowest and most expensive part of serverless functions was CPU branch misprediction. In a serverless approach, you want to squeeze as much operations per CPU cycle as possible. Any misprediction has huge consequences and kill any of the mechanical sympathy effort we put in libraries like vert.x.

In our experiments, we found that the optimal solution was to get rid of if branches in serverless functions. We are proud to introduce IF as a Service or IFaaS (pronounced aye face). Your code changes from:

user = retrieveUserProfile();
if ( user.isCustomer() ) {
    displayAds();
}
user.extractRevenu();

to

user = retrieveUserProfile();
if ( user.isCustomer(), "displayAdFunction" );
user.extractRevenu();

We have been using it for a year now and forked the javac compiler to convert each if branch into a proper if service call. But we also completely re shaped how we write code to pure linear code, changing all if primitives with their service call equivalent. This is great because it also fixed the tab vs space problem: we no longer have any indenting in our code. Two stones in one bird ! I cannot emphasize enough how much development speed we gained in our team by fighting less on each pull request against these tab bastards.

The good thing about this external if service is that you can add a sidecar proxy to cache and simulate branch predictions on OpenShift and scale then horizontally ad nauseam. This is a huge benefit compared to the hardcoded and embedded system that is a CPU. We typically change the branch implementation 3 to 5 times a day depending on user needs.

FAQ

Is else a function too?

Else is not part of the MVP but we have it working in the labs. We are currently struggling to implement for loops, more specifically nested ones. We have HTTP error 310: too many redirects errors.

Where can I download it ?

You can’t, it’s a service dummy. Go to <ifaas.io>.

Can I use it in Go?

Goggle did not accept our pull request. We have a fork called NoGo.

What is the pricing model?

The basic if service is and will remain free. We are working on added values with pro and enterprise plans.

Hibernate Validator 6 is going to be the Reference Implementation of Bean Validation 2.0. This Alpha2 release is coordinated with the 2.0.0.Alpha2 release of the Bean Validation specification.

It is also a playground used to validate future enhancements of the Bean Validation specification so feedback on the subjects presented here is very welcome!

Note that Hibernate Validator 6 requires JDK 8 or above.

If you missed the Alpha1 release, consulting its announcement might be beneficial to you before continuing your reading.

What’s new since Alpha1

Improved container element validation support

Container element validation support is the big new feature of Bean Validation 2.0 and it got some more love during this cycle.

Programmatic API and XML support

To obtain the equivalent of:

public class FishTank {

    private Optional<@Valid FishTankModel> model;

    private Map<@Size(min = 3, max = 10) String, @Min(1) Integer> fishCountByType;
}

it is now possible to declare container element type constraints and cascaded validation either via an XML mapping configuration (which is part of the Bean Validation 2.0 specification):

[...]
    <bean class="com.acme.FishTank" ignore-annotations="false">
        <field name="model">
            <containerElementType>
                <valid />
            </containerElementType>
        </field>
        <field name="fishCountByType">
            <containerElementType typeArgumentIndex="0">
                <constraint annotation="javax.validation.constraints.Size">
                    <element name="min">
                        <value>3</value>
                    </element>
                    <element name="max">
                        <value>10</value>
                    </element>
                </constraint>
            </containerElementType>
            <containerElementType typeArgumentIndex="1">
                <constraint annotation="javax.validation.constraints.Min">
                    <element name="value">
                        <value>1</value>
                    </element>
                </constraint>
            </containerElementType>
        </field>
    </bean>
[...]

or via the (implementation specific) programmatic API:

ConstraintMapping newMapping = config.createConstraintMapping();
newMapping
    .type( FishTank.class )
        .property( "model", FIELD )
            .containerElementType()
                .valid()
        .property( "fishCountByType", FIELD )
            .containerElementType( 0 )
                .constraint( new SizeDef().min( 3 ).max( 10 ) )
            .containerElementType( 1 )
                .constraint( new MinDef().value( 1 ) );

Other improvements

We also made a couple of more minor improvements:

  • the TYPE_ARGUMENT node type has been renamed to CONTAINER_ELEMENT (type argument don’t make sense for annotated array elements)

  • we allow per context custom value extractors

  • we allow value extractors to be contributed using the service loader mechanism

  • we allow to specify value extractors using XML configuration

  • we explore the parent classes and interfaces to search the ValueExtractor definition

Support for the new constraints added to Bean Validation 2.0

In the Alpha2 release of Bean Validation 2.0, we introduced the following new constraints:

  • @NotBlank: check that a char sequence is not blank (i.e. not null, and length of trimmed char sequence > 0)

  • @NotEmpty: check that an element (char sequence, collection, array) is not null and not empty

  • @Email: check that a char sequence is a valid email

  • @Positive: check that a number is positive

  • @Negative: check that a number is negative

We added support for these new constraints to Hibernate Validator.

Performance improvements

We started to run a few benchmarks on Hibernate Validator 6 and we fixed a few performance regressions.

6.0.0.Alpha2 is now significantly faster than 5.4, mostly thanks to the new ValueExtractor design.

Getting 6.0.0.Alpha2

To get the release with Maven, Gradle etc. use the GAV coordinates org.hibernate.validator:{hibernate-validator|hibernate-validator-cdi|hibernate-validator-annotation-processor}:6.0.0.Alpha2. Note that the group id has changed from org.hibernate (Hibernate Validator 5 and earlier) to org.hibernate.validator (from Hibernate Validator 6 onwards).

Alternatively, a distribution bundle containing all the bits is provided on SourceForge (TAR.GZ, ZIP).

Feedback, issues, ideas?

To get in touch, use the usual channels:

What’s next?

Bean Validation 2.0 and Hibernate Validator 6 are still under active development. We will release new alphas on a regular basis.

Hibernate Validator 5.4.1.Final

Posted by    |       |    Tagged as Hibernate Validator Releases

A bugfix release

Hibernate Validator 5.4.1.Final is a bugfix release, mostly for corner cases. 5.4.1.Final is a recommended upgrade for everyone.

Here are the most prominent bugfixes of this release:

  • HV-1088 - Fix a concurrency issue in validator initialization that you probably wouldn’t encounter in a normal usage - you’re supposed to use a shared ConstraintValidatorFactory which mitigates the issue

  • HV-1280 - Fix a class loading conflict with Xerces in modular environements (e.g. WildFly)

  • HV-1252 - Fix an issue with the annotation processor and JavaMoney support. Thanks go to Guillaume Husta for this one.

  • HV-1253 - A few TYPE_USE mentions had been mistakenly introduced in 5.4 when backporting from 6 (5.4 still supports Java 6)

We also integrated a new translation, Persian, thanks to Shahram Goodarzi.

And finally, we upgraded our build instructions for the latest JDK 9 early access build.

As usual, you can find the complete list of all addressed issues in the change log.

Getting 5.4.1.Final

To get the release with Maven, Gradle etc. use the GAV coordinates org.hibernate:{hibernate-validator|hibernate-validator-cdi|hibernate-validator-annotation-processor}:5.4.1.Final.

Alternatively, a distribution bundle containing all the bits is provided on SourceForge (TAR.GZ, ZIP).

Feedback, issues, ideas?

To get in touch, use the usual channels:

What’s next?

Bean Validation 2.0 and Hibernate Validator 6 are under active development. We will release a new alpha in the next few days.

As far as Bean Validation 2.0 is concerned, there are very interesting discussions going on about value extraction which is THE big BV 2.0 feature. Come and join us on Bean Validation website to define the future of Bean Validation.

Hibernate Community Newsletter 6/2017

Posted by    |       |    Tagged as Discussions Hibernate ORM

Welcome to the Hibernate community newsletter in which we share blog posts, forum, and StackOverflow questions that are especially relevant to our users.

Articles

Implementing the soft delete pattern with Hibernate is trivial. Check out this article for more details.

Sri Vikram Sundar wrote a very detailed tutorial about integrating Spring MVC, MySQL, and Hibernate.

Stefan Pröll wrote two articles about using Hibernate Search and Spring Boot:

Baeldung features an article about using the Hibernate-specific @Immutable annotation to mark entities that should never be modified, which allow Hibernate to enable some flush-time performance optimizations.

For our Portuguese readers, Rafael Ponte wrote a guide to controlling transactions programmatically in Legacy Systems using Java 8 Lambdas and the Template Pattern. For non-Portuguese readers, you can use Google Translate since most Romance languages are easily translated into English.

Time to upgrade

Hibernate ORM 5.1.5 and 5.2.9 have been released.

Ninth bug-fix release for ORM 5.2

Posted by    |       |    Tagged as Hibernate ORM Releases

The Ninth bug-fix release for Hibernate ORM 5.2 has just been published. It is tagged at https://github.com/hibernate/hibernate-orm/releases/tag/5.2.9

The complete list of changes can be found here (or here for people without a Hibernate Jira account).

For information on consuming the release via your favorite dependency-management-capable build tool, see http://hibernate.org/orm/downloads/

The release bundles can be obtained from SourceForge or BinTray.

back to top