Search code examples
spring-bootelasticsearchspring-data-elasticsearch

How to configure ElasticsearchRepositoryFactory to use a ElasticsearchRepository in a standalone program with ElasticsearchCustomConversions


I have a Spring Boot application with a working configuration where ElasticsearchCustomConversions are used. Works fine.

Inside this application I want to create some standalone src/test/java classes where I can test my ElasticsearchRepository logic. Standalone because starting Spring Boot every time is too time consuming.

I am able to use a ElasticsearchRepository in a standalone java program like:

public class ExampleRepositoryStandaloneTester {

private static ElasticsearchRepositoryFactory factoryBean;

static {
    ClientConfiguration clientConfiguration = ClientConfiguration.builder().connectedTo("localhost:9200").build();
    RestHighLevelClient client = RestClients.create(clientConfiguration).rest();
    ElasticsearchOperations elasticsearchOperations = new ElasticsearchRestTemplate(client);
    factoryBean = new ElasticsearchRepositoryFactory(elasticsearchOperations);
}

public static ProductRepository getProductRepository() {
    return factoryBean.getRepository(ProductRepository.class);
}

public static void main(String[] args) {
    System.out.println("Product count: " + getProductRepository().count());
}}

The count function is really going to my local docker Elastic instance and prints the Product count. So this works.

But, my model needs ElasticsearchCustomConversions and I cannot find a way to properly setup the ElasticsearchRepositoryFactory so that the conversion are configured and used.

Does anyone know how to do this?

  • Spring Boot v2.3.4.RELEASE
  • ​Spring Data Elasticsearch 4.0.4.RELEASE
  • Elasticsearch 7.6.2

Versions are dependency managed through a RedHat fuse version so I cannot (easily) upgrade to newer versions.

The following attempt fails with "No converter found capable of converting from type [java.lang.Boolean] to type [com.my.TrueFalseType]":

public class ExampleCustomConversionsTester {

static class ExampleConfigurator extends AbstractElasticsearchConfiguration {
    private RestHighLevelClient client;
    
    public ExampleConfigurator(RestHighLevelClient client) {
        ExampleConfigurator.this.client = client;
    }
    
    @Override
    public RestHighLevelClient elasticsearchClient() {
        return client;
    }
    
    @Override
    public ElasticsearchCustomConversions elasticsearchCustomConversions() {
        return new ElasticsearchCustomConversions(Collections.singletonList(new TrueFalseTypeConverter()));
    }

    @ReadingConverter
    static class TrueFalseTypeConverter implements Converter<Boolean, TrueFalseType> {
        @Override
        public TrueFalseType convert(Boolean value) {
            return TrueFalseType.fromValue(value.toString());
        }
    }
}

static {
    ClientConfiguration clientConfiguration = ClientConfiguration.builder().connectedTo("localhost:9200").build();
    RestHighLevelClient client = RestClients.create(clientConfiguration).rest();
    ExampleConfigurator cfg = new ExampleConfigurator(client);

    ElasticsearchOperations elasticsearchOperations = new ElasticsearchRestTemplate(cfg.elasticsearchClient());
    MappingElasticsearchConverter elasticsearchConverter = (MappingElasticsearchConverter) elasticsearchOperations.getElasticsearchConverter();
    elasticsearchConverter.setConversions(cfg.elasticsearchCustomConversions());
    factoryBean = new ElasticsearchRepositoryFactory(cfg.elasticsearchOperations(elasticsearchConverter));
}

private static ElasticsearchRepositoryFactory factoryBean;

public static ProductRepository getProductRepository() {
    return factoryBean.getRepository(ProductRepository.class);
}

public static void main(String[] args) {
    System.out.println("Product count: " + getProductRepository().count());
    Page<Product> page = getProductRepository().findProducts(PageRequest.of(0, 10));
}

}


Solution

  • After you set the conversions with

        elasticsearchConverter.setConversions(cfg.elasticsearchCustomConversions());
    

    you need to call

    elasticsearchConverter.afterPropertiesSet()
    

    as described in the Javadoc for the setConversions method. Normally Spring does this, but as you are not using Spring to setup the beans, you need to do this in your code.