SpEL
Spring Data Elasticsearch
Spring Boot
@Document Annotation
IndexName Parsing

SpEL used in Document indexName with spring data elasticsearch and spring boot is not being parsed

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Spring Data Elasticsearch lets you map Java classes to Elasticsearch indices using the @Document annotation. A frustrating issue many developers encounter is that Spring Expression Language (SpEL) expressions placed inside the indexName property of @Document are not evaluated at runtime — the literal expression string ends up as the index name instead. This article explains why this happens and how to fix it.

How @Document and indexName Work

The @Document annotation binds an Elasticsearch index to a Java entity class. You specify metadata such as the index name, shard count, and replica count. A typical usage looks like this:

java
1@Document(indexName = "products", shards = 1, replicas = 0)
2public class Product {
3    @Id
4    private String id;
5    private String name;
6    private double price;
7}

When you want the index name to be configurable — for example, varying by environment — you might try embedding a SpEL expression that reads from application properties:

java
1@Document(indexName = "#{@environment.getProperty('elasticsearch.index.name')}")
2public class Product {
3    @Id
4    private String id;
5    private String name;
6}

The expectation is that Spring resolves the expression at startup and substitutes the actual property value. However, in many setups, the raw SpEL string is used verbatim as the index name, causing Elasticsearch errors.

Why SpEL Is Not Parsed

The root cause is that Spring Data Elasticsearch does not evaluate SpEL expressions in the @Document annotation in all versions. The annotation processing happens at a stage where the SpEL evaluation context may not be available, or the specific version of the library simply does not support SpEL in that attribute.

There is an important distinction between SpEL expressions (#{...}) and property placeholders (${...}). Property placeholders are resolved by the Spring PropertySourcesPlaceholderConfigurer, which runs early in the application context lifecycle. SpEL expressions require a full BeanExpressionResolver context, which may not be wired into the annotation processor used by Spring Data Elasticsearch.

Solutions

Solution 1: Use Property Placeholders Instead of SpEL

The simplest fix is to switch from SpEL syntax to property placeholder syntax. Property placeholders are resolved reliably during bean initialization:

java
1@Document(indexName = "${elasticsearch.index.name}")
2public class Product {
3    @Id
4    private String id;
5    private String name;
6}

Then in your application.yml:

yaml
elasticsearch:
  index:
    name: products-dev

This approach works consistently across Spring Data Elasticsearch versions because ${...} placeholders are handled by a different, earlier-stage resolver.

Solution 2: Use a Custom ElasticsearchOperations Bean

If you need true dynamic index naming that goes beyond simple property substitution, you can configure the index name programmatically:

java
1@Configuration
2public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
3
4    @Value("${elasticsearch.index.name}")
5    private String indexName;
6
7    @Override
8    public RestHighLevelClient elasticsearchClient() {
9        return new RestHighLevelClient(
10            RestClient.builder(new HttpHost("localhost", 9200, "http"))
11        );
12    }
13}

Solution 3: Upgrade Spring Data Elasticsearch

Later versions of Spring Data Elasticsearch (4.x and above) have improved support for SpEL evaluation in annotation attributes. If you are on an older version, upgrading may resolve the issue entirely. Check the official changelog for your version to confirm SpEL support in @Document.

xml
1<dependency>
2    <groupId>org.springframework.data</groupId>
3    <artifactId>spring-data-elasticsearch</artifactId>
4    <version>4.4.6</version>
5</dependency>

Understanding the Resolution Order

Spring processes configurations in a specific order. Property placeholders (${...}) are resolved during the BeanFactoryPostProcessor phase, which happens before beans are fully initialized. SpEL expressions (#{...}) are resolved later, during the BeanPostProcessor phase. Since annotation metadata is read early, SpEL may not yet have the context it needs. This timing mismatch is the fundamental reason SpEL fails in @Document on older versions.

Common Pitfalls

  • Confusing ${...} with #{...}: Property placeholders and SpEL expressions use different syntax and are resolved at different lifecycle stages. Using the wrong one is the most frequent cause of this issue.
  • Missing property source configuration: Even with ${...}, if your application.properties or application.yml file does not define the referenced key, the placeholder is left unresolved and becomes a literal index name.
  • Assuming all annotations support SpEL: Not every Spring annotation evaluates SpEL expressions. Always verify support in the documentation for the specific annotation and library version you are using.
  • Hardcoding index names in production: Without externalized configuration, you cannot vary the index name per environment, leading to dev and production data colliding in the same index.
  • Ignoring version compatibility: SpEL support in @Document has changed across Spring Data Elasticsearch releases. Relying on behavior from one version without checking your actual dependency version causes silent failures.

Summary

  • The @Document annotation's indexName attribute does not always evaluate SpEL expressions, depending on the Spring Data Elasticsearch version.
  • Property placeholders (${...}) are resolved earlier in the Spring lifecycle than SpEL (#{...}) and are the reliable choice for dynamic index names.
  • Upgrading to Spring Data Elasticsearch 4.x or later improves SpEL support in annotations.
  • Always externalize index names through application.yml or environment variables to keep configurations portable across environments.
  • When in doubt, test the resolved index name at startup by logging the value from ElasticsearchOperations or checking the Elasticsearch cluster directly.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions