Red Hat

In Relation To

The Hibernate team blog on everything data.

While the team has been busy implementing great new features such as the Elasticsearch integration for the next 5.6 release, some of you provided interesting feedback on our stable release.

The summary of the feedback I heard is that migrating to the new sorting requirements can be confusing, and there were some issues with our Faceting implementation.

Hibernate Search version 5.5.3.Final is available now, fixing the reported issues and improving the error messages around sorting.

The changelog is rather small, so this time I’ll post it verbatim:

  • HSEARCH-1917 - Cannot index null or empty values for faceted fields

  • HSEARCH-2082 - Documentation refers to @SortField when it should be @SortableField

  • HSEARCH-2085 - Typo in hibernate-search-engine logger

  • HSEARCH-2086 - Long and Date range faceting doesn’t honor hasZeroCountsIncluded

  • HSEARCH-2179 - Hanging during shutdown of SyncWorkProcessor

  • HSEARCH-2193 - LuceneBackendQueueTask does not release the Directory lock on update failures

  • HSEARCH-2200 - Typo in log message

  • HSEARCH-2240 - Parallel service lookup might fail to find the service

  • HSEARCH-2199 - Allows the use of CharFilter in the programmatic API of SearchMapping

  • HSEARCH-2084 - Upgrade to WildFly 10.0.0.Final

  • HSEARCH-2089 - Ensure the performance tests do not use the WildFly embedded version of Search

  • HSEARCH-1951 - Improve resulting error message when applying the wrong Sort Type

  • HSEARCH-2090 - Using the wrong header in the distribution/pom.xml

  • HSEARCH-2241 - Clarify deprecation of setFilter() method on FullTextQuery

Spot inefficient sorting operations easily in test suites

While Hibernate Search already would log a warning when forced to perform a query using a sub-optimal sorting strategy, that wasn’t making it very easy to spot mapping or usage mistakes.

Set this property:

    hibernate.search.index_uninverting_allowed = false

and you’ll have your tests fail with an exception rather than log warnings.

This property is not new in this release, but it’s worth reminding as it makes it much easier to validate your migrations from previous versions.

<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-search-orm</artifactId>
   <version>5.5.3.Final</version>
</dependency>
<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>5.0.6.Final</version>
</dependency>
<dependency>
   <groupId>org.apache.lucene</groupId>
   <artifactId>lucene-core</artifactId>
   <version>5.3.1</version>
</dependency>

What are we working on?

The Elasticsearch integration is almost feature complete, we expect to be able to release a Beta1 version in some weeks.

How to get this release

Everything you need is available on Hibernate Search’s web site. Download the full distribution from here, or get it from Maven Central using the above coordinates, and don’t hesitate to reach us in our forums or mailing lists.

Hibernate Community Newsletter 9/2016

Posted by Vlad Mihalcea    |       |    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

Presentations

Both Emmanuel and I have been presenting at Devoxx France, and we are going to share the videos once they are available. Meanwhile, you can checkout the slides for the High-Performance Hibernate presentation.

Emulating property literals with Java 8 method references

Posted by Gunnar Morling    |       |    Tagged as Discussions

One of the things library developers often miss in Java are property literals. In this post I’m going to show how to make creative use of Java 8 method references to emulate property literals, with the help of some byte code generation.

Akin to class literals (e.g. Customer.class), property literals would allow to refer to the properties of a bean class in a type-safe manner. This would be useful for designing APIs that run actions on specific bean properties or apply some means of configuration to them. E.g. consider the API for programmatic configuration of index mappings in Hibernate Search:

new SearchMapping().entity( Address.class )
    .indexed()
    .property( "city", ElementType.METHOD )
        .field();

Or the validateValue() method from the Bean Validation API for validating a value against the constraints of a single property:

Set<ConstraintViolation<Address>> violations = validator.validateValue( Address.class, "city", "Purbeck" );

In both cases a String is used to represent the city property of the Address class.

That’s error-prone on several levels:

  • The Address class might not have a property city at all. Or one could forget to update that String reference when renaming the property.

  • In the case of validateValue(), there is no way for making sure that the passed value actually satisfies the type of the city property.

Users of the APIs will only find out about these issues when actually running their application. Wouldn’t it be nice if instead the compiler and the language’s type system prevented such wrong usages from the beginning? If Java had property literals, that’d be exactly what you’d get (invented syntax, this does not compile!):

mapping.entity( Address.class )
    .indexed()
    .property( Address::city, ElementType.METHOD )
        .field();

And:

validator.validateValue( Address.class, Address::city, "Purbeck" );

The issues mentioned above would be avoided: Having a typo in a property literal would cause a compilation error which you’d notice right in your IDE. It’d allow to design the configuration API in Hibernate Search in a way to accept only properties of Address when configuring the Address entity. And in case of Bean Validation’s validateValue(), literals could help to ensure that only values can be passed, that are assignable to the property type in question.

Java 8 method references

While Java 8 has no real property literals (and their introduction isn’t planned for Java 9 either), it provides an interesting way to emulate them to some degree: method references. Having been introduced to improve the developer experience when using Lambda expressions, method references also can be leveraged as poor-man’s property literals.

The idea is to consider a reference to a getter method as a property literal:

validator.validateValue( Address.class, Address::getCity, "Purbeck" );

Obviously, this will only work if there actually is a getter. But if your classes are following JavaBeans conventions - which often is the case - that’s fine.

Now how would the definition of the validateValue() method look like? The key is using the new Function type:

public <T, P> Set<ConstraintViolation<T>> validateValue(Class<T> type, Function<? super T, P> property, P value);

By using two type parameters, we make sure that the bean type, the property and the value passed for the property all correctly match. So API-wise, we got what we need: It’s safe to use, and the IDE will even auto-complete method names after starting to write Address::. But how do we derive the property name from the Function in the implementation of validateValue()?

That’s where the fun begins, as the Function interface just defines a single method, apply(), wich runs the function against a given instance of T. That seems not exactly helpful, does it?

ByteBuddy to the rescue

As it turns out, applying the function actually does the trick! By creating a proxy instance of the T type, we have a target for invoking the method and can obtain its name in the proxy’s method invocation handler.

Java comes with support for dynamic proxies out of the box, but that’s limited to proxying interfaces only. As our API should work with any kind of bean, also actual classes, I’m going to use a neat tool called ByteBuddy instead. ByteBuddy provides an easy-to-use DSL for creating classes on the fly which is exactly what we need.

Let’s begin by defining an interface which just allows to store and obtain the name of a property we obtained from a method reference:

public interface PropertyNameCapturer {

    String getPropertyName();

    void setPropertyName(String propertyName);
}

Now let’s use ByteBudy to programmatically create a proxy class which is assignable to the type of interest (e.g. Address) and PropertyNameCapturer:

public <T> T /* & PropertyNameCapturer */ getPropertyNameCapturer(Class<T> type) {
    DynamicType.Builder<?> builder = new ByteBuddy()                                       (1)
            .subclass( type.isInterface() ? Object.class : type );

    if ( type.isInterface() ) {                                                            (2)
        builder = builder.implement( type );
    }

    Class<?> proxyType = builder
        .implement( PropertyNameCapturer.class )                                           (3)
        .defineField( "propertyName", String.class, Visibility.PRIVATE )
        .method( ElementMatchers.any() )                                                   (4)
            .intercept( MethodDelegation.to( PropertyNameCapturingInterceptor.class ) )
        .method( named( "setPropertyName" ).or( named( "getPropertyName" ) ) )             (5)
            .intercept( FieldAccessor.ofBeanProperty() )
        .make()
        .load(                                                                             (6)
             PropertyNameCapturer.class.getClassLoader(),
             ClassLoadingStrategy.Default.WRAPPER
        )
        .getLoaded();

    try {
        @SuppressWarnings("unchecked")
        Class<T> typed = (Class<T>) proxyType;
        return typed.newInstance();                                                        (7)
    }
    catch (InstantiationException | IllegalAccessException e) {
        throw new HibernateException(
            "Couldn't instantiate proxy for method name retrieval", e
        );
    }
}

The code may appear a bit dense, so let me run you through it. First we obtain a new ByteBuddy instance (1) which is the entry point into the DSL. It is used to create a new dynamic type that either extends the given type (if it is a class) or extends Object and implements the given type if it is an interface (2).

Next, we let the type implement the PropertyNameCapturer interface and add a field for storing the name of the specified property (3). Then we say that invocations to all methods should be intercepted by PropertyNameCapturingInterceptor (we’ll come to that in a moment) (4). Only setPropertyName() and getPropertyName() (as declared in the PropertyNameCapturer interface) should be routed to write and read access of the field created before (5). Finally, the class is built, loaded (6) and instantiated (7).

That’s all that’s needed to create the proxy type; Thanks to ByteBuddy, this is done in a few lines of code. Now let’s take a look at the interceptor we configured before:

public class PropertyNameCapturingInterceptor {

    @RuntimeType
    public static Object intercept(@This PropertyNameCapturer capturer, @Origin Method method) {         (1)
        capturer.setPropertyName( getPropertyName( method ) );                                           (2)

        if ( method.getReturnType() == byte.class ) {                                                    (3)
            return (byte) 0;
        }
        else if ( ... ) { } // ... handle all primitve types
            // ...
        }
        else {
            return null;
        }
    }

    private static String getPropertyName(Method method) {                                               (4)
        final boolean hasGetterSignature = method.getParameterTypes().length == 0
                && method.getReturnType() != null;

        String name = method.getName();
        String propName = null;

        if ( hasGetterSignature ) {
            if ( name.startsWith( "get" ) && hasGetterSignature ) {
                propName = name.substring( 3, 4 ).toLowerCase() + name.substring( 4 );
            }
            else if ( name.startsWith( "is" ) && hasGetterSignature ) {
                propName = name.substring( 2, 3 ).toLowerCase() + name.substring( 3 );
            }
        }
        else {
            throw new HibernateException( "Only property getter methods are expected to be passed" );    (5)
        }

        return propName;
    }
}

intercept() accepts the Method being invoked as well as the target of the invocation (1). The annotations @Origin and @This are used to designate the respective parameters so ByteBuddy can generate the correct invocations of intercept() into the dynamic proxy type.

Note that there is no strong dependency from this interceptor to any types of ByteBuddy, meaning that ByteBuddy is only needed when creating that dynamic proxy type but not later on, when actually using it.

Via getPropertyName() (4) we then obtain the name of the property represented by the passed method object and store it in the PropertyNameCapturer (2). If the given method doesn’t represent a getter method, an exception is raised (5). The return value of the invoked getter is irrelevant, so we just make sure to return a sensible "null value" matching the property type (3).

With that, we got everything in place to get hold of the property represented by a method reference passed to validateValue():

public <T, P> Set<ConstraintViolation<T>> validateValue(Class<T> type, Function<? super T, P> property, P value) {
    T capturer = getPropertyNameCapturer( type );
    property.apply( capturer );
    String propertyName = ( (PropertyLiteralCapturer) capturer ).getPropertyName();

    // perform validation of the property value...
}

When applying the function to the property name capturing proxy, the interceptor will kick in, obtain the property name from the Method object and store it in the capturer instance, from where it can be retrieved finally.

And there you have it, some byte code magic lets us make creative use of Java 8 method references for emulating property literals.

That said, having real property literals as part of the language (dreaming for a moment, maybe Java 10?) would still be very beneficial. It’d allow to deal with private properties and, hopefully, one could refer to property literals from within annotations. Real property literals also would be more concise (no "get" prefix) and it’d generally feel a tad less hackish ;)

Hibernate Community Newsletter 8/2016

Posted by Vlad Mihalcea    |       |    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

Presentations

We are getting closer and closer to the final release of Hibernate OGM 5.

This release includes support for Redis Cluster and a new dialect to store data within Redis hashes; java.util.UUID are now using the native uuid type in Apache Cassandra; more queries are now supported using the MongoDB CLI syntax.

This release is also aligned to the Hibernate 5 family and it will work with Hibernate ORM 5, Hibernate Search 5.5 and the latest WildFly 10. Check the previous post for more details about it.

The migration notes contains more information about migrating from earlier versions of Hibernate OGM to 5.x.

Have a look at the change log for a list of everything included in this release.

Redis Cluster support

Enabling the support for Redis Cluster is a matter of setting the following property to true:

hibernate.ogm.redis.cluster = true

When this property is enabled, data will be stored across Redis cluster nodes according to the Redis key distribution model on the hash slot of the key of each entity.

Check the documentation for more details about the configuration options for Redis in Hibernate OGM.

Redis hash mapping

When using this mapping, data is stored using key-values pairs using Redis hashes. The benefit of this approach is that it allows partial updates.

You can enable this dialect setting the following property:

hibernate.ogm.datastore.grid_dialect = org.hibernate.ogm.datastore.redis.RedisHashDialect

This will map the following entity:

@Entity
public class News {

    @Id
    private String id;

    @Version
    @Column(name="version")
    private int version;

    private String title;

    private String description;

    //getters, setters ...
}

with the following properties:

version     = 1
title       = On the merits of NoSQL
description = This paper discuss why NoSQL will save the world for good

A huge thanks to community member Mark Paluch, responsible for both these great improvements in the Redis area. Note that these features are both experimental for the time being.

Additional MongoDB native CLI queries support

Thanks to the contribution of Thorsten Möller, Hibernate OGM now supports more type of queries using the MongoDB CLI syntax: findOne, findAndModify, insert, remove and update.

Here an example showing how you can use them:

OgmSession session = ...

String nativeQuery = "db.OscarWilde.findAndModify({"
        + "'query': {'author': 'oscarwilde'}, "
        + "'update': { '$set': { 'author': 'Oscar Wilder' } }, "
        + "'new': true "
        + "})";

Query query = session.createNativeQuery( nativeQuery ).addEntity( OscarWilde.class );
List<OscarWilde> result = query.list();

You can find more details in the documentation about experimental support of native MongoDB queries.

What’s coming next?

We are working on the Neo4j remote dialect and we are focused on releasing a stable version of Hibernate OGM 5.

Where can I get it?

You can get Hibernate OGM 5.0.0.CR1 via Maven etc. using the following coordinates:

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

  • org.hibernate.ogm:hibernate-ogm-<%BACKEND%>:5.0.0.CR1 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.

How can I get in touch?

You can get in touch through the following channels:

We are looking forward to hear your feedback!

Hibernate Community Newsletter 7/2016

Posted by Vlad Mihalcea    |       |    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

Having fixed several issues and tasks since the previous milestone, it’s time to publish our third milestone towards Elasticsearch integration: Hibernate Search version 5.6.0.Alpha3 is now available!

Migration from Hibernate Search 5.5.x

Even if you’re not interested in the new Elasticsearch support, you might want to try out this version as it benefits from Apache Lucene 5.5.0.

If you ignore the new features and want to simply use Lucene in embedded mode the migration is easy, and as usual we are maintaining notes regarding relevant API changes in the Migration Guide to Hibernate Search 5.6.

Elasticsearch support progress

  • you can now use the Analyzers from Elasticsearch

  • Multiple operations will now be sent to Elasticsearch as a single batch to improve both performance and consistency

  • Spatial indexing and querying is now feature complete

  • We’ll wait for Elasticsearch to be "green" before attempting to use it at boot

  • Many improvements in the query translation

  • Error capture and reporting was improved

  • the Massindexer is working now, but is not yet using efficient bulk operations

  • the Elasticsearch extensions are now included in the WildFly modules

How to get this release

Everything you need is available on Hibernate Search’s web site.

Get it from Maven Central using the above coordinates.

Downloads from Sourceforge are available as well.

Feedback

Feedback always welcome!

Please let us know of any problem or suggestion by creating an issue on JIRA, or by sending an email to the developer’s developer’s mailing lists, or posting on the forums.

We also monitor Stack Overflow; when posting on SO please use the tag hibernate-search.

Hibernate ORM 5.0.9.Final

Posted by Gail Badner    |       |    Tagged as Hibernate ORM Releases

Hibernate ORM 5.0.9.Final has just been tagged and published.

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

In addition, the 5.0 Migration Guide has been updated to document migration issues when moving from earlier 5.0 releases to 5.0.8.

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.

In this post, I’d like you to meet Martin, who, in spite of his young age, has been very active in the Hibernate Search project development, implementing some interesting extensions or helping with pull request reviewing.

Because I’d love to see more university students getting involved with open source software, I took this opportunity and interviewed Martin about this experience.

  1. Hi, Martin. You are one of the youngest contributors we’ve ever had. Can you please introduce yourself?

    Hi, Vlad. I am a 22-year-old Master’s Degree student at University of Bayreuth, Germany and have been interested in Hibernate Search and Fulltext Search (Lucene, Solr) for quite some time now. I am also a firm believer of Open Source and have actually always wanted to become a contributor of a tool (or software) many other developers use in their projects. Knowing that a piece of code you wrote is running in other systems is quite the rewarding feeling.

  2. I understand that you took part in the Google Summer of Code event. Can you tell us a little bit about this program?

    Yes, I took part in last year Google Summer of Code program and was mentored by Sanne Grinovero while working on adapting Hibernate Search to work with any JPA provider. It gave me the opportunity to dive more deeply into the codebase as it allowed me to concentrate on nothing but my project work-wise. In general Google Summer of Code is one of the best learning experiences any student that wants to get into Open Source can have.

  3. Contributing to an open-source project is a great learning experience. Has this activity helped you improve your skills?

    Definitely. While building new features or tracking down bugs, you encounter loads of different pieces of code you have to work through. With that comes learning new technologies and APIs. Also, the general process of submitting JIRA issues, discussing them and implementing the solutions is something you can learn while working on an open source project. Trying out the process yourself is invaluable and cannot be compared to just learning them on paper. This is also something I always tell to new coders: Try it out or you will not get it 100%.

  4. Do you think the entry barrier is high for starting contributing to an open source project? How should we encourage students to getting involved with open source?

    In the case of the Hibernate team, I can only say that it was quite easy to get into contact with the other developers. I just got onto IRC and asked questions about problems I had. They helped me with every question I had, so I stuck around. Then, I started reporting issues or making feature requests and was immediately incorporated into discussions. So no, the barrier is not high (at least for me in the case of the Hibernate team).

    I think open source needs to be encouraged more at a university level. I think many students don’t realize what they are missing. Yes, open standards are encouraged and teaching uses open APIs all over the place, but universities tend to keep much of the work that is suitable for open source behind closed doors (btw: I don’t think that closed source is always a bad thing, but it sometimes is in the way of innovation).

  5. What are your plans for the future?

    Firstly, I want to finish my Masters degree at University. I haven’t fully decided yet, whether I want to stay at University or not. Time will tell, I guess. Secondly, I want to keep contributing to Hibernate Search and finish merging the features of last years Google Summer of Code into the core code base.

Thank you, Martin, and keep up the good work.

back to top