1. Introduction
One of the most powerful frameworks that Spring offers programmers for simplifying database interactions in Java applications is the Spring JPA (Java Persistence API). It provides a solid abstraction over JPA.
However, despite the ease of use, developers frequently encounter errors that can be challenging to diagnose and resolve. One such common issue is the “Unable to Locate Attribute with the Given Name” error.
In this tutorial, let’s examine the source of this issue before we investigate how to fix it.
2. Define Use Case
It always helps to have a practical use case to illustrate this article.
We create unique and eye-catching wearable gadgets. After a recent survey, our marketing team found that sorting products by sensor type, price, and popularity on our platform would help customers make better purchasing decisions by highlighting the most popular items.
3. Add Maven Dependencies
Let’s use an in-memory H2 database to create a Wearables table in our project into which we’ll populate sample data that we can use in our testing down the line.
To begin with, let’s add the following Maven dependencies:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.224</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.7.11</version>
</dependency>
4. Add Application Resources
So that we can test this repository, let’s create a few application property entries that help us create and populate a table called WEARABLES into an H2 in-memory database.
In our application’s main/resources folder, let’s create an application-h2.properties with the following entries:
# H2 configuration
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.hbm2ddl.auto=create-drop
# Spring Datasource URL
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
The below SQL that we will place in the main/resources folder called testdata.sql will help us create the wearables table in the H2 database with a bunch of pre-defined entries:
CREATE TABLE IF NOT EXISTS wearables (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
price DECIMAL(10, 2),
sensor_type VARCHAR(255),
popularity_index INT
);
DELETE FROM wearables;
INSERT INTO wearables (id, name, price, sensor_type, popularity_index)
VALUES (1, 'SensaWatch', '500.00', 'Accelerometer', 5);
INSERT INTO wearables (id, name, price, sensor_type, popularity_index)
VALUES (2, 'SensaBelt', '300.00', 'Heart Rate', 3);
INSERT INTO wearables (id, name, price, sensor_type, popularity_index)
VALUES (3, 'SensaTag', '120.00', 'Proximity', 2);
INSERT INTO wearables (id, name, price, sensor_type, popularity_index)
VALUES (4, 'SensaShirt', '150.00', 'Human Activity Recognition', 2);
5. Define WearableEntity Model
Let’s define our entity model WearableEntity. This model is our entity that defines the characteristics of a Wearable device:
@Entity
public class WearableEntity {
@Id @GeneratedValue
private Long Id;
@Column(name = "name")
private String Name;
@Column(name = "price")
private BigDecimal Price;
// e.g., "Heart Rate Monitor", "Neuro Feedback", etc.
@Column(name = "sensor_type")
private String SensorType;
@Column(name = "popularity_index")
private Integer PopularityIndex;
}
6. Define Query for Entity Filtering
Having introduced the above entity in the platform, let’s add a query to our database that enables our customers to filter WearableEntity, as per the new filter criteria in our persistence layer using the Spring JPA framework.
public interface WearableRepository extends JpaRepository<WearableEntity, Long> {
List<WearableEntity> findAllByOrderByPriceAscSensorTypeAscPopularityIndexDesc();
}
Let’s break down the above query to understand it better.
- findAllBy: Let’s use this method to retrieve all records that are or type WearableEntity
- OrderByPriceAsc: Let’s sort the results by price in ascending order
- SensorTypeAsc: After sorting by price, let’s sort by sensorType in ascending order
- PopularityIndexDesc: Finally, let’s sort the results by popularityIndex in descending order (as higher popularity might be preferred)
7. Test Repository via Integration Test
Let’s now check the behavior of the WearableRepository by introducing an integration test in our project:
public class WearableRepositoryIntegrationTest {
@Autowired
private WearableRepository wearableRepository;
@Test
public void testFindByCriteria() {
assertThat(wearableRepository.findAllByOrderByPriceAscSensorTypeAscPopularityIndexDesc()) .hasSize(4);
}
}
8. Running Integration Test
But upon running the integration test, we’ll immediately notice that it’s unable to load application context and fails with the following error:
Caused by: java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [price] on this ManagedType [com.baeldung.spring.data.jpa.filtering.WearableEntity]
9. Understanding the Root Cause
Hibernate uses naming conventions to map fields to database columns. Suppose the field names in an entity class don’t align with the corresponding column names or expected conventions. In that case, Hibernate will fail to map them, causing exceptions during query execution or schema validation.
In this example:
- Hibernate expects field names like name, price, or popularityIndex (in camelCase), but the entity incorrectly uses the field names Id, Name, SensorType, Price, and PopularityIndex (in PascalCase)
- When executing a query like findAllByOrderByPriceAsc(), Hibernate will try to map the SQL price column to the entity field. Since the field is named Price (with an uppercase “P”), it fails to locate the attribute, resulting in an IllegalArgumentException
10. Resolving the Error by Fixing the Entity
Let us now change the naming of the fields in our WearableEntity class from PascalCase to camelCase:
@Entity
@Table(name = "wearables")
public class WearableValidEntity {
@Id
@GeneratedValue
private Long id;
@Column(name = "name")
// use camelCase instead of PascalCase
private String name;
@Column(name = "price")
// use camelCase instead of PascalCase
private BigDecimal price;
@Column(name = "sensor_type")
// use camelCase instead of PascalCase
private String sensorType;
@Column(name = "popularity_index")
// use camelCase instead of PascalCase
private Integer popularityIndex;
}
Once we have made this change, let’s rerun the WearableRepositoryIntegrationTest. Voila! It instantly passes.
11. Conclusion
In this article, we’ve highlighted the importance of following JPA naming conventions to prevent runtime errors and ensure smooth data interactions. Adhering to best practices helps avoid field mapping issues and optimizes application performance.
As always, we can find the full code example over on GitHub.