Resolving Elasticsearch 8.10.2 Compatibility in Spring Boot with Secure Transport Configuration
Upgrading from legacy iterations often results in dependancy mismatches within the classpath. A common scenario involves integrating version 8.x servers where legacy client libraries (like 7.x) cause NoSuchMethodError or class hierarchy issues, such as conflicts loading org.elasticsearch.client.RequestOptions.Builder. To resolve this, ensure the Java client version corresponds correctly with the server runtime.
Maven Configuration
Adjust the dependency versions to match the target environment without hardcoding conflicting jar paths. The client library should be distinct from the core version to avoid runtime crashes.
<dependencies>
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>8.10.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>x-pack-sql-jdbc</artifactId>
<version>8.10.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
</dependencies>
Note: Explicitly setting the client version to match the server major version prevents compatibility exceptions during startup.
Application Properties
Configure connection details including SSL certificate paths and authentication credentials in the YAML configuration file.
spring:
data:
elasticsearch:
connections:
rest:
- uris: "https://localhost:9200"
username: elastic
password: secure_password
ssl:
verification-mode: certificate
index: app_data_index
keystore-path: certs/http_ca.crt
Java Client Setup
Define a configuration class to initialize synchronous and asynchronous clients. Handle SSL context generation manually to accommodate self-signed certificates used by the security enabled cluster.
package com.example.config;
import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.ssl.SSLContextBuilder;
import org.elasticsearch.client.RestClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import javax.net.ssl.SSLContext;
import java.security.cert.CertificateFactory;
import java.security.KeyStore;
import java.io.InputStream;
@Configuration
public class ElasticsearchConfiguration {
private final String certName = "http_ca.crt";
private final HttpHost httpHost = new HttpHost("localhost", 9200, "https");
@Bean
public ElasticsearchTransport transport() throws Exception {
CredentialsProvider credProv = new BasicCredentialsProvider();
credProv.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "password"));
RestClient restClient = RestClient.builder(httpHost)
.setHttpClientConfigCallback(
builder -> builder
.setDefaultCredentialsProvider(credProv)
.setSSLContext(buildSslContext()))
.build();
return new RestClientTransport(restClient, new JacksonJsonpMapper());
}
private static SSLContext buildSslContext() throws Exception {
ClassPathResource resource = new ClassPathResource("http_ca.crt");
try (InputStream is = resource.getInputStream()) {
KeyStore trustStore = KeyStore.getInstance("PKCS12");
trustStore.load(null, null);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
trustStore.setCertificateEntry("ca", cf.generateCertificate(is));
return SSLContextBuilder.custom()
.loadTrustMaterial(trustStore, null)
.build();
}
}
@Bean
public ElasticsearchClient syncClient(transport) {
return new ElasticsearchClient(transport);
}
@Bean
public ElasticsearchAsyncClient asyncClient(transport) {
return new ElasticsearchAsyncClient(transport);
}
}
Integration Testing
Validate the connection by performing CRUD operations on indices using JUnit tests.
package com.example.test;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class IndexOperationTest {
@Autowired
private ElasticsearchClient client;
@Test
void verifyIndexLifecycle() throws Exception {
IndicesClient idxCli = client.indices();
String testIdx = "verify_test";
boolean exists = idxCli.exists(e -> e.index(testIdx)).value();
if (exists) {
idxCli.delete(d -> d.index(testIdx));
}
CreateIndexResponse res = idxCli.create(c -> c.index(testIdx));
System.out.println("Created: " + res.acknowledged());
GetIndexResponse getRes = idxCli.get(g -> g.index(testIdx));
System.out.println("Status: " + getRes.get(testIdx).status());
idxCli.delete(d -> d.index(testIdx));
}
}
External Database Connectivity
For SQL-based exploration of the document store, enable the trial license to utilize JDBC drivers. Execute the following request to activate full functionality for DBeaver or similar SQL clients.
POST /_license/start_trial?acknowledge=true&pretty
Once activated, configure your IDE database tool to connect using the Elastic JDBC plugin found in the plugins directory.