4

I need to generate a query dynamically based on parameter passed and need to join three tables, getting below exception while building query with EntityManager CriteriaBuilder, same code structure is working if I convert it to Criteria but I want use CriteriaBuilder only.

        @Override
    @Transactional
    public List<DatapointReply> getAllByFilter(Map<String, List<Object>> filter, int maxResults,
            boolean matchAllFilters) {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<DatapointReply> criteriaQuery = criteriaBuilder.createQuery(DatapointReply.class);
        Root<PartDatapointReply> datapointReplyRoot = criteriaQuery.from(PartDatapointReply.class);
        Join<DatapointReply, Datapoint> datapointJoin = null;
        Join<PartDatapointReply, Part> partJoin = null;
        criteriaQuery.select(datapointReplyRoot);
        if (filter.containsKey("datapointkey")) {
            datapointJoin = datapointReplyRoot.join("datapoint");
        }
        if (filter.containsKey("partstatus") || filter.containsKey("partmodelnumber")) {
            partJoin = datapointReplyRoot.join("part");
        }

        List<Predicate> predicateList = new ArrayList<>();
        for (String searchKey : filter.keySet()) {
            List<Object> searchTerms = filter.get(searchKey);
            Predicate predicate = buildSearchCriterion(new String[searchTerms.size()], true, JunctionType.OR, datapointReplyRoot, criteriaBuilder,
                    "value");
            if (predicate != null) {
                predicateList.add(predicate);
            }
        }

        Predicate[] predicateArray = predicateList.toArray(new Predicate[predicateList.size()]);
        if (!predicateList.isEmpty() && matchAllFilters) {
            criteriaBuilder.and(predicateArray);
        } else if (!predicateList.isEmpty() && !matchAllFilters) {
            criteriaBuilder.or(predicateArray);
        }

        TypedQuery<DatapointReply> query = entityManager.createQuery(criteriaQuery);
        // Define the Max Results
        if (maxResults > SearchEngine.SEARCH_MAX_RESULTS_ALL) {
            query.setMaxResults(maxResults);
        }
        return query.getResultList();
    }


// Get Predicate based on parameter
private Predicate buildSearchCriterion(String[] values, boolean isWildcardSearch, JunctionType criteriaType,
            Root<PartDatapointReply> datapointReplyRoot, CriteriaBuilder criteriaBuilder, String... attributeNames) {

        // Build the Search Criteria as Single or Multiple Column Search
        Predicate finalCriterion = null;

        if (!isWildcardSearch) {

            List<Predicate> criteria = new ArrayList<>();
            for (String attributeName : attributeNames) {
                Predicate attributeCriterion = criteriaBuilder.in(datapointReplyRoot.get(attributeName)).value(values);
                criteria.add(attributeCriterion);
            }
            if (criteriaType == null || criteriaType == JunctionType.OR) {
                finalCriterion = criteriaBuilder.or(criteria.toArray(new Predicate[criteria.size()]));
            } else {
                finalCriterion = criteriaBuilder.and(criteria.toArray(new Predicate[criteria.size()]));
            }
        } else if (isWildcardSearch) {
            // Wildcard OR search on a single attribute
            // Search through each Search Term, ignoring white space, and add
            // each term to the Criteria Restrictions.

            List<Predicate> criteria = new ArrayList<>();
            for (String attributeName : attributeNames) {
                List<Predicate> attributeCriteria = new ArrayList<>();
                Predicate attributeCriterion;
                for (String value : values) {
                    Predicate valueCriterion;
                    // Wrap the Value in Wild Cards if it is a Wild Card Search
                    if (isWildcardSearch) {
                        value = "%" + value + "%";
                    }
                    valueCriterion = criteriaBuilder.like(criteriaBuilder.lower(datapointReplyRoot.get(attributeName)), value.toLowerCase());
                    attributeCriteria.add(valueCriterion);
                }
                attributeCriterion = criteriaBuilder.or(attributeCriteria.toArray(new Predicate[attributeCriteria.size()]));
                criteria.add(attributeCriterion);
            }
            if (criteriaType == null || criteriaType == JunctionType.OR) {
                finalCriterion = criteriaBuilder.or(criteria.toArray(new Predicate[criteria.size()]));
            } else {
                finalCriterion = criteriaBuilder.and(criteria.toArray(new Predicate[criteria.size()]));
            }
        }
        return finalCriterion;
    }

Getting below error message:

java.lang.IllegalArgumentException: Encountered array-valued parameter binding, but was expecting [java.lang.String (n/a)]
    at org.hibernate.query.spi.QueryParameterBindingValidator.validateArrayValuedParameterBinding(QueryParameterBindingValidator.java:142) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
    at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:49) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
    at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:27) ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
    at ```

1 Answers1

10

Changing type of values from String[] to Arrays.asList(values) in below lines will fix the problem.

Predicate attributeCriterion = criteriaBuilder.in(datapointReplyRoot.get(attributeName)).value(Arrays.asList(values));

  • yes it is. But may you provide link to documentation, where it is stated, that some java types are inappropriate to use as jpa parameter type? It would be very interesting – WeGa Mar 31 '20 at 12:52