Description
It would make sense to add validation for Spring Data repository definitions, specifically to check that the declared repository ID type is assignable to (compatible with) the domain type. The validation should affect the repository definition and should be triggered by the presence of a repository declaration.
Consider the following declarations:
class Customer {
@Id String id;
}
interface CustomerRepository extends Repository<Customer, Long>{}
@RepositoryDefinition(domainClass = Customer.class, idClass = Long.class)
interface CustomerRepository {}
The ID type in the entity is String
while the repositories declare Long
. This code indicates a potential bug.
The validation should check whether the repository ID type can be assigned from the entity ID type or vice versa. Entities may declare a primitive type so the validation needs to consider primitive wrapper types, too.
Valid cases
class Customer {
@Id String id;
}
interface CustomerRepository extends Repository<Customer, CharSequence>{}
@RepositoryDefinition(domainClass = Customer.class, idClass = CharSequence.class)
interface CustomerRepository {}
class Customer {
@Id CharSequence id;
}
interface CustomerRepository extends Repository<Customer, String>{}
@RepositoryDefinition(domainClass = Customer.class, idClass = String.class)
interface CustomerRepository {}
class Customer {
@Id int id;
}
interface CustomerRepository extends Repository<Customer, Integer>{}
@RepositoryDefinition(domainClass = Customer.class, idClass = Integer.class)
interface CustomerRepository {}
Invalid cases
class Customer {
@Id String id;
}
interface CustomerRepository extends Repository<Customer, Long>{}
@RepositoryDefinition(domainClass = Customer.class, idClass = Long.class)
interface CustomerRepository {}
class Customer {
@Id String id;
}
interface CustomerRepository extends Repository<Customer, Number>{}
@RepositoryDefinition(domainClass = Customer.class, idClass = Number.class)
interface CustomerRepository {}
class Customer {
@Id Integer id;
}
interface CustomerRepository extends Repository<Customer, Double>{}
@RepositoryDefinition(domainClass = Customer.class, idClass = Double.class)
interface CustomerRepository {}
Advanced cases
Sometimes, entities do not declare an Id type so the validation is not possible. In such a case, the validation should be ignored.
class Customer {
String name;
}
interface CustomerRepository extends Repository<Customer, Integer>{}
@RepositoryDefinition(domainClass = Customer.class, idClass = Integer.class)
interface CustomerRepository {}
Types annotated with @NoRepositoryBean
indicate framework types and should not be validated. Their subtypes are (unless annotated with @NoRepositoryBean
) should be validated.
@NoRepositoryBean
interface CustomerRepository<T extends MyType, ID extends Serializable> Repository<T, ID>{}
@NoRepositoryBean
interface CrudRepository<T, ID> extends Repository<T, ID>
We've seen various levels of generics usage. While this is not the most common case, it would make sense to consider these cases for validation.
class Customer {
@Id String id;
}
interface CustomerRepository<T extends Customer, ID extends Long> extends Repository<T, ID>{}
@NoRepositoryBean
interface MyIntermediateRepository<T extends Customer, ID extends Number> extends Repository<T, ID>{}
interface MyConcreteRepository extends MyIntermediateRepository<Customer, Long>{}
@NoRepositoryBean
interface MyOtherIntermediateRepository1<T extends Customer> extends Repository<T, Long>{}
interface MyOtherConcreteRepository1 extends MyOtherIntermediateRepository1<Customer>{}
@NoRepositoryBean
interface MyOtherIntermediateRepository2<ID extends Number> extends Repository<Customer, ID>{}
interface MyOtherConcreteRepository2 extends MyOtherIntermediateRepository2<Long>{}