Объединение ответов:
https://stackoverflow.com/a/16911313
https://stackoverflow.com/a/47793003
Я создал этот метод:
public String getIdAttribute(EntityManager em, String fullClassName) {
Class<? extends Object> clazz = null;
try {
clazz = Class.forName(fullClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Metamodel m = em.getMetamodel();
IdentifiableType<T> of = (IdentifiableType<T>) m.managedType(clazz);
return of.getId(of.getIdType().getJavaType()).getName();
}
, тогда у меня есть менеджер сущностейinjected
@PersistenceContext
private EntityManager em;
Я получаю первичный ключ корневого объекта следующим образом:
String rootFullClassName = root.getModel().getJavaType().getName();
String primaryKeyName = getIdAttribute(em, rootFullClassName);
и получаю первичные ключи, на которые ссылаются такие атрибуты:
return (Specification<T>) (root, query, builder) -> {
Set<Attribute<? super T, ?>> attributes = root.getModel().getAttributes();
for (Attribute a: attributes) {
if(a.isAssociation()) {
Path rootJoinGetName = root.join(a.getName());
String referencedClassName = rootJoinGetName.getJavaType().getName();
String referencedPrimaryKey = getIdAttribute(em, referencedClassName);
//then I can use it to see if it is equal to a value (e.g
//filtering actors by movies with id = 1 - in
//this case referencedPrimaryKey is "id")
Predicate p = rootJoinGetName.get(referencedPrimaryKey).in(1);
}
}
}
Таким образом, мне не нужно заранее знать тип первичного ключа / ссылочного ключа, так как он может быть получен с помощью метамодели Entity Manager.Приведенный выше код можно использовать с CriteriaQuery, а также со спецификациями.