It is a bit tricky, depending on the JPA 2 implementation you use, this one works for EclipseLink 2.4.1, but doesn't for Hibernate, here a generic CriteriaQuery count for EclipseLink:
public static Long count(final EntityManager em, final CriteriaQuery<?> criteria)
{
final CriteriaBuilder builder=em.getCriteriaBuilder();
final CriteriaQuery<Long> countCriteria=builder.createQuery(Long.class);
countCriteria.select(builder.count(criteria.getRoots().iterator().next()));
final Predicate
groupRestriction=criteria.getGroupRestriction(),
fromRestriction=criteria.getRestriction();
if(groupRestriction != null){
countCriteria.having(groupRestriction);
}
if(fromRestriction != null){
countCriteria.where(fromRestriction);
}
countCriteria.groupBy(criteria.getGroupList());
countCriteria.distinct(criteria.isDistinct());
return em.createQuery(countCriteria).getSingleResult();
}
The other day I migrated from EclipseLink to Hibernate and had to change my count function to the following, so feel free to use either as this is a hard problem to solve, it might not work for your case, it has been in use since Hibernate 4.x, notice that I don't try to guess which is the root, instead I pass it from the query so problem solved, too many ambiguous corner cases to try to guess:
public static <T> long count(EntityManager em,Root<T> root,CriteriaQuery<T> criteria)
{
final CriteriaBuilder builder=em.getCriteriaBuilder();
final CriteriaQuery<Long> countCriteria=builder.createQuery(Long.class);
countCriteria.select(builder.count(root));
for(Root<?> fromRoot : criteria.getRoots()){
countCriteria.getRoots().add(fromRoot);
}
final Predicate whereRestriction=criteria.getRestriction();
if(whereRestriction!=null){
countCriteria.where(whereRestriction);
}
final Predicate groupRestriction=criteria.getGroupRestriction();
if(groupRestriction!=null){
countCriteria.having(groupRestriction);
}
countCriteria.groupBy(criteria.getGroupList());
countCriteria.distinct(criteria.isDistinct());
return em.createQuery(countCriteria).getSingleResult();
}