protected <T> SearchResultsBean<T> find(SearchCriteriaBean criteria,
                                            Set<OrderByBean> uniqueOrderIdentifiers,
                                            Consumer<CriteriaBuilder<T>> builderCallback,
                                            Class<T> type,
                                            String typeAlias,
                                            boolean paginate) throws StorageException {
        try {
            // Set some default in the case that paging information was not included in the request.
            PagingBean paging = criteria.getPaging();
            if (paging == null) {
                paging = PagingBean.create(1, 20);
            }
            int page = paging.getPage();
            int pageSize = paging.getPageSize();
            int start = (page - 1) * pageSize;

            CriteriaBuilder<T> cb = criteriaBuilderFactory
                            .create(getActiveEntityManager(), type)
                            .from(type, typeAlias);

            // Apply filters from user-provided criteria.
            cb = applySearchCriteriaToQuery(typeAlias, criteria, cb, false);

            // Allow caller to modify the query, for example to add permissions constraints.
            builderCallback.accept(cb);

            if (paginate) {
                PaginatedCriteriaBuilder<T> paginatedCb = cb.page(start, pageSize);
                /*
                 * Add an orderBy of unique identifiers *last* in the query; this is required for pagination to work properly.
                 *
                 * The tuple formed by the fields in this orderBy clause MUST be unique, otherwise BlazePersistence will throw an exception.
                 *
                 * Without a unique tuple, the ordering may be unstable, which can cause pagination to behave unpredictably.
                 */
                for (OrderByBean uniqueOrder : uniqueOrderIdentifiers) {
                    if (!duplicateOrderBy(typeAlias, uniqueOrder, criteria.getOrderBy())) {
                        paginatedCb = paginatedCb.orderBy(uniqueOrder.getName(), uniqueOrder.isAscending());
                    }
                }

                PagedList<T> resultList = paginatedCb.getResultList();

                return new SearchResultsBean<T>()
                        .setTotalSize(Math.toIntExact(resultList.getTotalSize()))
                        .setBeans(resultList);
            } else {
                // Pagination sometimes generates #in SQL statements that H2 currently does not support due to composite key
                //    (x,y) IN (select x,y ... subquery) which works in all DBs except H2. Beware...
                for (OrderByBean order : uniqueOrderIdentifiers) {
                    cb = cb.orderBy(order.getName(), order.isAscending());
                }
                List<T> resultList = cb.getResultList();
                return new SearchResultsBean<T>()
                        .setTotalSize(Math.toIntExact(resultList.size()))
                        .setBeans(resultList);
            }
        } catch (Throwable t) {
            LOGGER.error(t.getMessage(), t);
            throw new StorageException(t);
        }
    }
Get a list of entities based on the provided criteria and entity type.
@param criteria
@param type
@throws StorageException if a storage problem occurs while storing a bean
manager/api/jpa/src/main/java/io/apiman/manager/api/jpa/AbstractJpaStorage.java