protected <T, T1> PageRequestId<T> findWithSpecification(
      String requestId,
      EntityManager entityManager,
      Pageable pageable,
      Filter2<T, T1> filter,
      Class<T> type,
      Class<T1> type1) {
    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    long total;
    {
      CriteriaQuery<Long> cqTotal = builder.createQuery(Long.class);
      Root<T1> root = cqTotal.from(type1);
      if (filter != null) {
        Predicate predicate = filter.toPredicate(root, cqTotal, builder);
        if (predicate != null) cqTotal.where(predicate);
      }
      cqTotal.select(builder.count(root));
      total = entityManager.createQuery(cqTotal).getSingleResult();
    }

    CriteriaQuery<T> cq = builder.createQuery(type);
    Root<T1> root = cq.from(type1);
    if (filter != null) {
      Predicate predicate = filter.toPredicate(root, cq, builder);
      if (predicate != null) cq.where(predicate);
    }
    cq.select(filter.getSelection(root, cq, builder));
    if (pageable.getSort() != null) {
      List<Order> orders = new LinkedList<Order>();
      for (Iterator<org.springframework.data.domain.Sort.Order> itr = pageable.getSort().iterator();
          itr.hasNext(); ) {
        org.springframework.data.domain.Sort.Order order = itr.next();
        String sx[] = order.getProperty().split("\\.");
        Path<Object> p = root.get(sx[0]);
        for (int i = 1, il = sx.length; i < il; i++) p = p.get(sx[i]);
        if (order.isAscending()) {
          orders.add(builder.asc(p));
        } else {
          orders.add(builder.desc(p));
        }
      }
      cq.orderBy(orders);
    }
    TypedQuery<T> qry = entityManager.createQuery(cq);
    qry.setFirstResult(pageable.getOffset()).setMaxResults(pageable.getPageSize());
    return new PageRequestIdImpl<T>(qry.getResultList(), pageable, total, requestId);
  }