jpanullspring-data-jpaspecification-pattern

JPA Specification and null parameter in .where clause


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:


Solution

  • 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