32

I have a method that does a search with filters, so I'm using Specification to build a dynamic query:

public Page<Foo> searchFoo(@NotNull Foo probe, @NotNull Pageable pageable) {

        Specification<Foo> spec = Specification.where(null);  // is this ok?

        if(probe.getName() != null) {
            spec.and(FooSpecs.containsName(probe.getName()));
        }
        if(probe.getState() != null) {
            spec.and(FooSpecs.hasState(probe.getState()));
        }
        //and so on...

        return fooRepo.findAll(spec, pageable);
}

There is the possibility that there are no filters specified, so I would list everything without filtering. So having that in mind, how I should initialize spec ? Right now, the code above doesn't work as it always returns me the same result: all the registers of the table, no filtering have been aplied althought and operations have been made.

FooSpecs:

public class PrescriptionSpecs {

    public static Specification<Prescription> containsCode(String code) {
        return (root, criteriaQuery, criteriaBuilder) ->
            criteriaBuilder.like(root.get(Prescription_.code), "%" + code + "%");
    }

    // some methods matching objects...
    public static Specification<Prescription> hasContractor(Contractor contractor) {
        return (root, criteriaQuery, criteriaBuilder) ->
            criteriaBuilder.equal(root.get(Prescription_.contractor), contractor);
    }
    //... also some methods that access nested objects, not sure about this
    public static Specification<Prescription> containsUserCode(String userCode) {
        return (root, criteriaQuery, criteriaBuilder) ->
            criteriaBuilder.like(root.get(Prescription_.user).get(User_.code), "%" + userCode + "%");
    }
}
anat0lius
  • 2,145
  • 6
  • 33
  • 60
  • What kind of exception do you get? I think this should work. Please add the stack trace. Also, why do you ask "is this ok?" if you already know "the code above doesn't work" – Jens Schauder Jun 25 '18 at 12:42
  • @JensSchauder There is no error but it doesn't filter. I'm getting all the results of the table, always. I ask if its is ok because I'm not sure if it is, I didn't see an example like this. Moreover, when I debug, i see `spec` empty. – anat0lius Jun 25 '18 at 12:49
  • I see. Can you share the code for `FooSpecs`? – Jens Schauder Jun 25 '18 at 13:13
  • updated with FooSpecs (aka PrescriptionSpecs) – anat0lius Jun 25 '18 at 13:24
  • Hmm, looks ok to me. Do they work on their own, like in `fooRepo.findAll(containsUserCode("XXX"), pageable);`? – Jens Schauder Jun 25 '18 at 13:35
  • No, for now I only have this method (searchFoo). So doing `Specification.where(null)` is legit? I'm worried why while debuging I dont see the content of`spec`, the IDE is saying it's null. – anat0lius Jun 25 '18 at 13:40
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/173755/discussion-between-jens-schauder-and-anat0lius). – Jens Schauder Jun 25 '18 at 13:42

1 Answers1

37

Specification.where(null) works just fine. It is annotated with @Nullable and the implementation handles null values as it should.

The problem is that you are using the and method as if it would modify the Specification, but it creates a new one. So you should use

spec = spec.and( ... );
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • 1
    Let's say I have 5 fields, but because they all are null, the spec is left with the value of `Specification.where(null)`. Question: is there a way to check that spec equals to `Specification.where(null)` – Alan Sereb Aug 08 '19 at 16:04
  • 4
    @IlyaSerebryannikov please don't ask new questions in comments, ask them in questions. – Jens Schauder Aug 09 '19 at 07:19