2

Entity

I have it entity with a property that is text[]:

    @Entity(name = "entityname")
@Table(name = "tablename")
@ToString
@TypeDefs({
  @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class),
  @TypeDef(name = "list-array", typeClass = ListArrayType.class)
})
public class EntityClass extends Audit
...

  @Type(type = "list-array")
  @Column(name = "participants", columnDefinition = "text[]")
  private List<String> participants;
  ....

Repository

I want to execute and findAll with a filter. This filter is Specification spec

data = entityRepository.findAll(filter, pageRequest);

The filter was implemented according to Specification:

public class Filter<T> implements Specification<T> {

  private final List<Condition> conditions = new ArrayList<>();

  public void addCondition(Condition condition) {
    this.conditions.add(condition);
  }

  private List<Predicate> buildPredicates(Root root, CriteriaQuery query, CriteriaBuilder cb) {
    List<Predicate> predicates = new ArrayList<>();
    for (Condition condition : conditions) {
      predicates.add(buildPredicate(condition, root, query, cb));
    }
    return predicates;
  }

  public Predicate buildPredicate(
      Condition condition, Root root, CriteriaQuery query, CriteriaBuilder cb) {
    if (!condition.getType().getValue().contains(condition.getComparison())) {
      throw new RuntimeException("UNSUPPORTED_COMPARISON_FOR_SPECIFIED_TYPE");
    }
    switch (condition.getComparison()) {
      case EQ:
        if (condition.getValue().getClass().isArray()) {
          final Predicate[] predicatesList =
              Arrays.stream((Object[]) condition.getValue())
                  .map(conditionValue -> cb.equal(root.get(condition.getField()), conditionValue))
                  .toArray(Predicate[]::new);
          return cb.or(predicatesList);
        }
        return cb.equal(root.get(condition.getField()), condition.getValue());
      case GT:
        if (condition.getType().equals(FilterFieldTypes.DATE)) {
          return cb.greaterThan(
              root.<Date>get(condition.getField()),
              new Date(condition.getValueAsNumber().longValue()));
        } else {
          return cb.gt(root.get(condition.getField()), condition.getValueAsNumber());
        }
      case GTE:
        if (condition.getType().equals(FilterFieldTypes.DATE)) {
          return cb.greaterThanOrEqualTo(
              root.<Date>get(condition.getField()),
              new Date(condition.getValueAsNumber().longValue()));
        } else {
          return cb.ge(root.get(condition.getField()), condition.getValueAsNumber());
        }
      case LT:
        if (condition.getType().equals(FilterFieldTypes.DATE)) {
          return cb.lessThan(
              root.<Date>get(condition.getField()),
              new Date(condition.getValueAsNumber().longValue()));
        } else {
          return cb.lt(root.get(condition.getField()), condition.getValueAsNumber());
        }
      case LTE:
        if (condition.getType().equals(FilterFieldTypes.DATE)) {
          return cb.lessThanOrEqualTo(
              root.<Date>get(condition.getField()),
              new Date(condition.getValueAsNumber().longValue()));
        } else {
          return cb.le(root.get(condition.getField()), condition.getValueAsNumber());
        }
      case FULL_TEXT:
        return cb.isTrue(cb.function("fts", Boolean.class, cb.literal(condition.getValue())));
      case JSONB_ARRAY_IN:
        return cb.isTrue(
            cb.function(
                "jsonb_extract_path_text", Boolean.class, cb.literal(condition.getValue())));
      case JSONB_PATH_EQ:
        return cb.isTrue(
            cb.function(
                "jsonb_array_contains",
                Boolean.class,
                cb.literal(condition.getField()),
                cb.literal(condition.getValue())));
      case IN:
        List<String> dataList = Arrays.asList(condition.getValue().toString());
        return cb.in(root.get(condition.getField())).value(dataList);

      default:
        throw new RuntimeException("UNSUPPORTED_COMPARISON");
    }
  }

  public int getConditionsCount() {
    return conditions.size();
  }

  @Override
  public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
    List<Predicate> predicates = buildPredicates(root, query, cb);
    return predicates.size() > 1 ? cb.and(predicates.toArray(Predicate[]::new)) : predicates.get(0);
  }
}

I am having problems with the implementation of my CASE IN:

      case IN:
        List<String> dataList = Arrays.asList(condition.getValue().toString());
        return cb.in(root.get(condition.getField())).value(dataList);

It produces the following error in it class:

public class ListArrayTypeDescriptor extends AbstractArrayTypeDescriptor<Object> {

...

    @Override
    public Object unwrap(Object value, Class type, WrapperOptions options) {
        if (value instanceof Object[]) {
            return value;
        } else if (value instanceof List) {
            return super.unwrap(((List) value).toArray(), type, options);
        } else {
            throw new UnsupportedOperationException("The provided " + value + " is not a Object[] or List!");
        }
    }
    
...

And the stack trace shows it message:

java.lang.UnsupportedOperationException: The provided d08d7785-1153-4bb3-b58c-6c79bf5a37f8 is not a Object[] or List!
    at com.vladmihalcea.hibernate.type.array.internal.ListArrayTypeDescriptor.unwrap(ListArrayTypeDescriptor.java:60)
    at 
  

Do you have an idea about that is wrong in the implementation of my CASE IN?

1 Answer 1

2

I was trying many options until that found it solution:

case ANY: List predicates = new ArrayList<>(); Expression delimiter = cb.literal(",");

    predicates.add(cb.like(
        cb.function(
            "array_to_string", String.class, root.get(condition.getField()), delimiter),
        "%" + condition.getValue().toString().toLowerCase() + "%"));
  return cb.and(predicates.toArray(new Predicate[0]));

I hope help if someone needs to implement "ANY" with criteriabuilder.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.