scholt
scholt

Reputation: 190

NoSuchMethodError when using HibernateSearch 6.0.6 with ElasticSearch 5.6

I am trying to add HibernateSearch 6.0.6.Final to a project currently using ElasticSearch 5.6, using https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/ as a guide.

Since the whole process of replacing/removing the direct calls to the ElasticSearch API from our code seems a little intimidating, I wanted to proceed iteratively, step by step.

First, I just added the dependencies for HibernateSearch 6.0.6.Final to our Maven pom.xml file, but left the ElasticSearch 5.6. dependencies in there (because of the tons of Java code still calling ElasticSearch 5.6. classes and methods directly), so the pom looks something like this:

<dependencies>
    ...
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>5.6.16</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.search</groupId>
        <artifactId>hibernate-search-mapper-orm</artifactId>
        <version>6.0.6.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.search</groupId>
        <artifactId>hibernate-search-backend-elasticsearch</artifactId>
        <version>6.0.6.Final</version>
    </dependency>
    ...
</dependencies>

According to the compatibility matrix at https://hibernate.org/search/releases/#compatibility-matrix, these versions should should work together. And indeed, I am still able to compile and run the code as before.

When I add some HibernateSearch mapping annotations to some of our beans, though, like this:

...
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.DocumentId;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
...

@MappedSuperclass
@Indexed
public abstract class BaseBean implements Serializable {

    @Id
    @DocumentId
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Integer id;

I get a NoSuchMethodeError with the following stack trace:

Caused by: java.lang.NoSuchMethodError: org.elasticsearch.client.Request.<init>(Ljava/lang/String;Ljava/lang/String;)V
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl.toRequest(ElasticsearchClientImpl.java:169)
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl.send(ElasticsearchClientImpl.java:113)
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl.lambda$submit$0(ElasticsearchClientImpl.java:82)
    at org.hibernate.search.util.common.impl.Futures.lambda$create$0(Futures.java:44)
    at java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:981)
    at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2124)
    at org.hibernate.search.util.common.impl.Futures.create(Futures.java:44)
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl.submit(ElasticsearchClientImpl.java:82)
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientUtils.tryGetElasticsearchVersion(ElasticsearchClientUtils.java:64)
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientUtils.getElasticsearchVersion(ElasticsearchClientUtils.java:53)
    at org.hibernate.search.backend.elasticsearch.impl.ElasticsearchLinkImpl.initVersion(ElasticsearchLinkImpl.java:200)
    at org.hibernate.search.backend.elasticsearch.impl.ElasticsearchLinkImpl.onStart(ElasticsearchLinkImpl.java:142)
...

Apparently, the org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl version shipped with HibernateSearch 6.0.6.Final isn't compatible with our ElasticSearch 5.6.16 after all, contrary to what the compatibility matrix for HibernateSearch suggests.

Since this is a HibernateSearch class, and not an ElasticSearch class, I am wondering why this error occurs at all. It can't be a conflict with another version of the same class in the classpath, right?

As expected, excluding the ElasticSearch dependencies from HibernateSearch like the following didn't help at all:

<dependencies>
    ...
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>5.6.16</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.search</groupId>
        <artifactId>hibernate-search-mapper-orm</artifactId>
        <version>6.0.6.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.search</groupId>
        <artifactId>hibernate-search-backend-elasticsearch</artifactId>
        <version>6.0.6.Final</version>
        <exclusions>
            <exclusion>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>elasticsearch-rest-high-level-client</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>elasticsearch-rest-client</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.elasticsearch</groupId>
                <artifactId>elasticsearch</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    ...
</dependencies>

So is there a way to explicitely tell HibernateSearch to use ElasticSearch 5.6.16 compatible methods and classes? Can this be configured in the hibernate.cfg.xml configuration file somehow?

I can't just update the ElasticSearch version in the pom.xml to 6.x or 7.x for testing, because there is a lot of code that needs to be adapted that wouldn't work with the newer versions of ElasticSearch. For now, I just want to compile and run the old code with the new annotations and then work from there, to complete the transition from ElasticSearch to HibernateSearch.

So any help or hint about how I can resolve this problem would be greatly appreciated!

Upvotes: 0

Views: 280

Answers (1)

yrodiere
yrodiere

Reputation: 9977

As explained here, the compatibility matrix gives you the compatibility of Hibernate Search with Elasticsearch server.

Elastic seems completely fine with introducing breaking changes in their client JARs; sometimes even in minor versions. As a result, any library that depends on these JARs (e.g. Hibernate Search) needs to target one and only one version of these JARs. Hibernate Search cannot be made compatible with multiple client JARs whose method definitions are different; at least not without a significant maintenance burden that I'm not ready to accept.

Long story short: don't try to override the version of the client JAR used by Hibernate Search; that can't end well. It would be like savagely downgrading your application to JPA 1.0 JARs; it's unlikely to work.

That being said, the new low-level REST client JARs are compatible with older Elasticsearch server versions. So you can use Elasticsearch low-level REST Client 7.10 with Elasticsearch server 5.6.

So you can migrate this way:

  1. Upgrade the client in your application to version 7.10 (while staying on Elasticsearch server 5.6).
  2. Add Hibernate Search 6.0 to your application.
  3. Some time later, upgrade to Elasticsearch server 7.10. Preferably soon, because Elasticsearch 5.6 has reached end-of-life a long time ago.

If you're using the high-level client JARs, though... it's only compatible with the same version of the Elasticsearch server, so you will have to migrate to Elasticsearch server 7.10 before you can migrate to Hibernate Search.

Upvotes: 1

Related Questions