Home > OS >  Filter/ search Using Specifications gives different Results
Filter/ search Using Specifications gives different Results

Time:05-23

I am working on filter/Search endpoint for my API of demo Project using dynamic query. This is my Endpoint for filter.

 @GetMapping("/filter")
public ResponseEntity<List<ProductDto>> filterProducts(@RequestParam("name") String name,
        @RequestParam("expiryDatemin") String expiryDatemin, @RequestParam("expiryDatemax") String expiryDatemax,
        @RequestParam("type") String type, @RequestParam("quantitymin") String quantityin,
        @RequestParam("quantitymin") String quantitymax, @RequestParam("company") String company,
        @RequestParam("pricemin") String pricemin, @RequestParam("pricemax") String pricemax) {

    return new ResponseEntity<List<ProductDto>>(productgetservice.filterProducts(expiryDatemin, expiryDatemax, name,
            type, quantityin, quantitymax, company, pricemin, pricemax), HttpStatus.OK);

}

What i am trying to do is user can enter any of elements and only data that satisfies the filters should appear.

If user sends all values as null or empty it should return full data of table.

Like for variables having min max at end is to get data between those intervals.

If only min is entered then the all data above that should be sent and if only max is entered then all data below that condition should appear.

and my serviceImpl class method is as:

@Override
public List<ProductDto> filterProducts(String expiryDatemin, String expiryDatemax, String name, String type,
        String quantitymin, String quantitymax, String company, String pricemin, String pricemax) {

    List<Product> products = productrepository.findAll(where(ProductSpecifications
            .withExpiryDates(expiryDatemin, expiryDatemax).and(ProductSpecifications.withcompany(company))
            .and(ProductSpecifications.withPrices(pricemin, pricemax))
            .and(ProductSpecifications.withQuantity(quantitymin, quantitymax))
            .and(ProductSpecifications.withType(type))));

    return productsListToProductDto(products);

}

The Problem i am having is that when i send data with 'and' it always return an empty array as pay load. when i replace and with 'or' it returns entire data of the table as list.

Here is my Product Specifications class methods:

public static Specification<Product> withExpiryDates(String expiryDatemin, String expiryDatemax) {

    return (root, query, cb) -> {

        if ((expiryDatemax.isBlank() || expiryDatemax == null)
                && (expiryDatemin.isBlank() || expiryDatemin == null)) {
            return cb.conjunction();
        } else if ((expiryDatemax.isBlank() || expiryDatemax == null)) {
            return cb.greaterThanOrEqualTo(root.get("expiryDate"), LocalDate.parse(expiryDatemin));
        } else if ((expiryDatemin.isBlank() || expiryDatemin == null)) {
            return cb.lessThanOrEqualTo(root.get("expiryDate"), LocalDate.parse(expiryDatemax));
        } else {
            return cb.between(root.get("expiryDate"), LocalDate.parse(expiryDatemin),
                    LocalDate.parse(expiryDatemax));
        }
    };}

public static Specification<Product> withPrices(String pricelow, String pricemax) {

    return (root, query, cb) -> {

        if ((pricelow.isBlank() || pricelow == null) && (pricemax.isBlank() || pricemax == null)) {
            return cb.conjunction();
        } else if ((pricemax.isBlank() || pricemax == null)) {
            return cb.greaterThanOrEqualTo(root.get("price"), Double.valueOf(pricelow));
        } else if ((pricelow.isBlank() || pricelow == null)) {
            return cb.lessThanOrEqualTo(root.get("price"), Double.valueOf(pricemax));
        } else {
            return cb.between(root.get("price"), Double.valueOf(pricelow), Double.valueOf(pricemax));
        }
    };}

public static Specification<Product> withQuantity(String quantitymin, String quantitymax) {

    return (root, query, cb) -> {

        if ((quantitymin.isBlank() || quantitymin == null) && (quantitymax.isBlank() || quantitymax == null)) {
            return cb.conjunction();
        } else if ((quantitymax.isBlank() || quantitymax == null)) {
            return cb.greaterThanOrEqualTo(root.get("quantity"), Integer.valueOf(quantitymin));
        } else if ((quantitymin.isBlank() || quantitymin == null)) {
            return cb.lessThanOrEqualTo(root.get("quantity"), Integer.valueOf(quantitymax));
        } else {
            return cb.between(root.get("quantity"), Integer.valueOf(quantitymin), Integer.valueOf(quantitymax));
        }
    };

}

public static Specification<Product> withType(String type) {

    return (root, query, cb) -> {
        if (type == null) {
            return cb.conjunction();
        } else
            return cb.like(root.get("type"), type);
    };
}

public static Specification<Product> withname(String name) {
    return (root, query, cb) -> {
        if (name == null) {
            return cb.conjunction();
        } else
            return cb.like(root.get("name"), name);
    };
}

public static Specification<Product> withcompany(String company) {
    return (root, query, cb) -> {
        if (company == null) {
            return cb.conjunction();
        } else
            return cb.like(root.get("company"), company);
    };

}

Any help would be appreciated. i am fairly new to Spring/Spring boot and SpecificationAPI is very new to me.

CodePudding user response:

I made the following Changes and it worked For me fine.

  1. Replace return cb.conjunction(); with return null; in Specification class.

  2. Remove .isBlank() check from Specification Class.

  3. Add .and(ProductSpecifications.withName(name)) to filter Products Method in Service class.

  4. Add required=false to all your @RequestParam @RequestParam(required=false)

  • Related