6

I wrote two Specifications which return null if their parameter is null.

public static Specification<Prodotto> getProdottoByLineaSpec (String linea) { if (linea != null) { return (root, query, criteriaBuilder) -> { return criteriaBuilder.like((root.join("linea")).get("nome"), "%"+linea+"%"); }; } else return null; } public static Specification<Prodotto> getProdottoByIngSpec (String ing) { if (ing != null) { return (root, query, criteriaBuilder) -> { return criteriaBuilder.like(((root.join("listaQuoteIng")).join("ing")).get("nome"), "%"+ing+"%"); }; } else return null; } 

Then I created a third one that combines the previous ones with an and operator inside a where clause:

public static Specification<Prodotto> getProdottoByMainTraits (String linea, String ing) { return Specification.where(getProdottoByLineaSpec(linea).and(getProdottoByIngSpec(ing))); } 

Now, that's the funny part:

  • If ByLinea returns null, i get a nullPointerException from checkPackageAccess when resolving the where clause.
  • If ByIng returns null, it just gets ignored (like it should be) and the query matches just the other predicate.
  • If I switch the two predicates, putting ByIng as the first one and then ByLinea inside the where clause, everything works in every combination.

1 Answer 1

21

It is a good practice to avoid returning null from methods.

You can use criteriaBuilder.conjunction() to ignore null parameter Specification. It generates always true Predicate. There is an opposite method criteriaBuilder.disjunction()

public static Specification<Prodotto> getProdottoByLineaSpec (String linea) { return (root, query, criteriaBuilder) -> { if (linea == null) { return criteriaBuilder.conjunction(); } return criteriaBuilder.like( (root.join("linea")).get("nome"), "%" + linea + "%" ); } } 

P.S. You get NullPointerException if first Specification is null trying to access a method and. To be clear it looks like this

Specification.where(null.and(getProdottoByIngSpec(ing))); 

But if only second Specification is null this one works

Specification.where(getProdottoByLineaSpec(linea).and(null)); 

because and method parameter can be null

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

11 Comments

Thanks for your suggestion. I didn't know those methods. It actually works, you just got to call the lambda function inside else block else return (root, query, criteriaBuilder) -> criteriaBuilder.conjunction(); I upvote your answer, but wait to mark it as solution, because it doesn't explain why my original structure got no problem if I switch predicates order inside where clause.
It is my fault in else block. I wrote the code using phone. I have edited the answer.
The answer also contains NullPointerException cause explanation
Yesterday I was experiencing this strange behaviour: if I set ByIng as first predicate, and make it return null, i didn't get the problem! That was the thing that I couldn't understand. Now I just retried, and actually it throws the expected exception. Probably yesterday was tired, and made some mistake. Thean as a general rule, is it always better to make a Specification return conjunction/disjunction instead of null, when you want it to be nullable?
Yes, but clauses like 1=1 cost nothing
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.