Announcement Announcement Module
Collapse
No announcement yet.
Why can't a Spring Data Specification return a null Predicate? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Why can't a Spring Data Specification return a null Predicate?

    Why can't a Spring Data Specification return a null Predicate? Would't it be sensible to not add it to criteria query if Specification.toPredicate returns null?

    I have the following use case:

    String q = "<some search query>" // this can be something like "Davy Jones" or "31-12-2011"
    Page<Receipt> page = receiptRepository.findAll(where(receiptDateEquals( q)).or(customerNameContains(q)), pageable);

    Think about q as a generic query string submitted via a web search form.
    Then in the receiptDateEquals specification I'm converting the search query to a date, if it succeeds fine and return the appropriate predicate, otherwise return no predicate / null.

    It's off course debatable if I should the date conversion in the specification or in the controller itself.
    I would like to opt for a central place in the specification itself so calling controller actions don't have to take care.

    That's why I wonder why the Sepcifciation.toPredicate can'y just return null if needed.

  • #2
    I'm now just returning a Predicate which basically checks if date = null which also works.
    But I don't know if this works in all databases as it might return the receipts which have an actual null date (= null vs is null).
    That's why I think it would be better to return null from toPredicate method.


    public static Specification<Receipt> receiptDateEquals(final Date date) {
    return new Specification<Receipt>() {
    @Override
    public Predicate toPredicate(Root<Receipt> receipt, CriteriaQuery<?> query, CriteriaBuilder builder) {
    return builder.equal(receipt.<Date> get("receiptDate"), date);
    }
    };
    }

    public static Specification<Receipt> receiptDateEquals(final String str) {
    return new Specification<Receipt>() {
    @Override
    public Predicate toPredicate(Root<Receipt> receipt, CriteriaQuery<?> query, CriteriaBuilder builder) {
    Date date = null;
    try {
    date = DateUtils.parseDateStrictly(str, "dd-MM-yyyy");
    } catch (Exception e) {
    // ignore
    }
    return receiptDateEquals(date).toPredicate(receipt, query, builder);
    }
    };
    }

    Comment


    • #3
      Generally, they can as SimpleJpaRepository only applies the where clause if the predicate handed into the method is not null. This is just to be safe if people violate the contract defined in Specification. Does it really make sense to delay the Date parsing that much? Passing data around as Strings is not a good idea in general so why not parse the date upfront and only apply the entire specification if it's a valid date. Otherwise you essentially write

      Code:
      .findAll(where(receiptDateEquals(yourString)));
      and would get *all* data back in case the given String is incorrect. This is not only problematic from a debugging perspective, I'd argue it's just not what you defined you want to get back, because if the date is invalid there are essentially *no* results with that "date". This leads to the more abstract questions how to deal with null specifications and the predicates generated in turn. I don't think that transparently dropping them is an appropriate approach as your sample above shows.

      PS: You might wanna use [ code ] tags when posting larger snippets of code as otherwise the stuff is very hard to read.

      Comment


      • #4
        Hi Oliver,

        I understand the 'contract' point, and it's fair point.

        Comment

        Working...
        X