Lusi
Lusi

Reputation: 401

spring data jpa dynamic query which has IN clause

I want to create dynamic query in spring data jpa. Doing many search I can implement it, but I came across a problem when I add IN operator in where clause. I need to check id IN (longlist) Here is my entity class

@Entity
@Table(name = "view_detail")
public class ViewDetailDom {

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;

private String name;

@Column(name = "user_id")
private Long userId;

private String description;

Here is specification builder class and specification class

public class ViewDetailSpecificationsBuilder {

private final List<SearchCriteria> params;

public ViewDetailSpecificationsBuilder() {
    params = new ArrayList<SearchCriteria>();
}

public ViewDetailSpecificationsBuilder with(String key, Operation operation, Object value) {
    params.add(new SearchCriteria(key, operation, value));
    return this;
}

public Specification<ViewDetailDom> build() {
    if (params.size() == 0) {
        return null;
    }

    List<Specification<ViewDetailDom>> specs = new ArrayList<Specification<ViewDetailDom>>();
    for (SearchCriteria param : params) {
        specs.add(new ViewDetailSpecification(param));
    }

    Specification<ViewDetailDom> result = specs.get(0);
    for (int i = 1; i < specs.size(); i++) {
        result = Specifications.where(result).and(specs.get(i));
    }
    return result;
}

}



public class ViewDetailSpecification implements Specification<ViewDetailDom> {

private SearchCriteria criteria = new SearchCriteria();

public ViewDetailSpecification(SearchCriteria searchCriteria) {
    this.criteria.setKey(searchCriteria.getKey());
    this.criteria.setOperation(searchCriteria.getOperation());
    this.criteria.setValue(searchCriteria.getValue());
}

@Override
public Predicate toPredicate(Root<ViewDetailDom> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
    String value = criteria.getValue().toString().replaceAll(" ", "%");
    if (criteria.getOperation() != null && criteria.getOperation() != Operation.DEFAULT) {
        if (criteria.getOperation() == Operation.GREATHERTHANEQUALTO) {
            return builder.greaterThanOrEqualTo(root.<String>get(criteria.getKey()), value);
        } else if (criteria.getOperation() == Operation.LESSTHANEQUALTO) {
            return builder.lessThanOrEqualTo(root.<String>get(criteria.getKey()), value);
        } else if (criteria.getOperation() == Operation.EQUAL) {
            return builder.equal(root.<String>get(criteria.getKey()), value);
        } else if (criteria.getOperation() == Operation.IN) {
            Path<Long> view = root.<Long>get(criteria.getKey());
            return view.in(criteria.getValue());
        }
    } else {
        if (root.get(criteria.getKey()).getJavaType() == String.class) {
            return builder.like(builder.lower(root.<String>get(criteria.getKey())),
                    "%" + value.toLowerCase() + "%");
        } else {
            return builder.equal(root.get(criteria.getKey()), value);
        }
    }
    return null;
}

}

This method creates specification builder:

public ViewDetailSpecificationsBuilder createSearchSpecifications(ViewSearch view) {
    ViewDetailSpecificationsBuilder builder = new ViewDetailSpecificationsBuilder();
    if (StringUtils.isNotBlank(view.getName())) {
        builder.with("name", Operation.DEFAULT, view.getName());
    }
    if (StringUtils.isNotBlank(view.getDescription())) {
        builder.with("description", Operation.DEFAULT, view.getDescription());
    }

    return builder;
}

And finally I do this:

ViewDetailSpecificationsBuilder builder = createSearchSpecifications(view);
builder.with("userId", Operation.DEFAULT, userSessionHelper.getUserId());
builder.with("id", Operation.IN, viewids);
Specification<ViewDetailDom> spec = builder.build();
viewDetailDao.findAll(spec);

But I am getting following error:

"Unaware how to convert value [[5, 7, 8] : java.util.ArrayList] to requested type [java.lang.Long]; nested exception is java.lang.IllegalArgumentException: Unaware how to convert value [[5, 7, 8] : java.util.ArrayList] to requested type [java.lang.Long]"

Upvotes: 1

Views: 1820

Answers (2)

VicML
VicML

Reputation: 11

In kotlin I have the same error, I change the ArrayList to Array, with this code:

fun values(): Array<String> {
    val elems = arrayListOf<String>()
    return elems.toTypedArray()
}

Try you convert ArrayList to array, for java see: make arrayList.toArray() return more specific types

Upvotes: 1

Lusi
Lusi

Reputation: 401

I have resolved this problem in this way:

ViewDetailSpecification class:

if (criteria.getOperation() == Operation.IN) {
            final List<Predicate> orPredicates = new ArrayList<Predicate>();
            List<Long> viewIds = (List<Long>) criteria.getValue();
            for (Long viewid : viewIds) {
                orPredicates.add(builder.or(builder.equal(root.<String>get(criteria.getKey()), viewid)));
            }
            return builder.or(orPredicates.toArray(new Predicate[orPredicates.size()]));
        }

Upvotes: 1

Related Questions