JPAstreamer Predicates
In JPAstreamer, the concept of fields and predicates is of central importance to achieve optimal performance. If you haven’t already, we recommend reading the chapter How JPAstreamer Works, to understand how fields are used by the JPAstreamer renderer to obtain optimized JPA queries.
What is a Predicate?
Predicate<T>
is a functional Java interface. An instance implementing this interface has a boolean function test
that takes a parameter of type T
and returns either true
or false
. JPAstreamer uses such predicates as arguments for Stream operations i.e. filter()
and sort()
.
Here is an example that uses a Predicate<String>
to return true
if the String
begins with an "A" and false
otherwise:
Predicate<String> startsWithA = (String s) -> s.startsWith("A");
Stream.of("Snail", "Ape", "Bird", "Ant", "Alligator")
.filter(startsWithA)
.forEachOrdered(System.out::println);
This will print all animals that starts with "A": Ape, Ant and Alligator because the filter
operator will only pass forward those elements where its Predicate
returns true
.
The official JavaDoc contains more information about the interface Predicate<T>. |
Fields
The fields included as part of the JPAstreamer metamodel (described here) can be used to produce Predicates
that are related to the field.
Here is an example of how a StringField
can be used in conjuction with a Film
object:
jpaStreamer.stream(Film.class)
.filter(Film$.title.startsWith("A"))
.forEachOrdered(System.out::println);
In this example, the StringField
's method Film$.title::startsWith
creates and returns a Predicate<Film>
that, when tested with a Film
, will return true
if and only if that Film
has a title
that starts with an "A" (otherwise it will return false
).
When run, the code above will produce the following output:
Film { filmId = 1, title = ACADEMY DINOSAUR, description = ...
Film { filmId = 2, title = ACE GOLDFINGER, description = ...
...
It would be possible to express the same semantics using a standard anonymous lambda:
films.stream()
.filter(f -> f.getTitle().startsWith("A"))
.forEachOrdered(System.out::println);
but JPAstreamer would not be able to recognize and optimize such vanilla lambdas. This means JPAstreamer is forced to pull in the entire Film table and then apply the predicates in the JVM. Because of this, developers are highly encouraged to use the provided Fields
when obtaining predicates because these predicates will always be recognizable by the JPAstreamer query optimizer.
Do this: filter(Film$.title.greaterOrEqual("He"))
|
Don’t do this: filter(f → "He".compareTo(f.getTitle()) ⇐ 0)
|
Field types
JPAstreamer uses a variety of field types to represent the attributes of the entity-classes. This is partly due to the fact that different types are compatible with different operations, but also for performance reasons.
Below is a table describing how attribute types are mapped to fields.
Attribute type | Field type |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The following chapters will describe how to get predicates from different Field
types and how these predicates can be combined and negated.
-
Reference Predicates describes what predicates can be obtained from
ReferenceField
-
Comparable Predicates describes what predicates can be obtained from
ComparableField
-
Primitive Predicates describes what predicates can be obtained from all primitive fields i.e.
IntField
andDoubleField
-
String Fields describes what predicates can be obtained from
StringField