'Spring Boot JPA - Entity failing due to calling getter method

Since upgrading from Spring Boot 2.2.x to 2.6.x (and Java 11 -> 17), our entity classes are having issues with some repository methods. We use UUID for our database ids, but also have strongly typed ids in the domain layer for type-safety. DB is Postgres.

Example (with some extra annotations, which don't solve the problem):

@Entity
@Access(AccessType.FIELD)
public class User {
  @Id private UUID id;
  
  @Transient
  public UserId id() {
    return new UserId(id);
  }
}

Our repository class:

public interface UserJPARepository extends CrudRepository<User, UUID> { }

Fails below:

repository.deleteById(userId.id());

with error:

org.springframework.dao.InvalidDataAccessApiUsageException: Provided id of the wrong type for class com.example.User. Expected: class java.util.UUID, got class com.example.CycleId; nested exception is java.lang.IllegalArgumentException: Provided id of the wrong type for class com.example..Cycle. Expected: class java.util.UUID, got class com.example.CycleId

The issue seems to be that JPA is using Reflection to determine that public UserId id() is the correct getter for the Id, but as this method converts the UUID to a UserId, it fails. Renaming the id() method fixes the issue, but this is not ideal.

Adding a breakpoint to my id() method, I can see the call originates from JpaMetamodalEntityInformation.getId:

if (idMetadata.hasSimpleId()) {
            return (ID) entityWrapper.getPropertyValue(idMetadata.getSimpleIdAttribute().getName());
}

The Transient and Access annotations don't help to resolve the issue.

Everything was working fine in Spring Boot 2.2. The upgrade has introduced the issue.



Solution 1:[1]

Your repository interface for deleteById requires an input parameter of type UUID, which is the ID type specified in your extends CrudRepository... statement. You are trying to call the method and pass a UserId object instead. Also, as you already pointed out, your function name of id() does collide with a getter naming convention for the property id.

Here are a few different ways you could solve the problem:

  • declare a deleteByUserId method on your repository interface

  • alter your repository interface declaration to use the key type of UserId instead of UUID

  • refactor your model to have an appropriately named getter and setter for the ID property to expose it

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 John Glenn