Querying Collections

The querydsl-collections module can be used with generated query types or without. The first section describes usage without generated query types.

Usage Without Generated Query Types

To use querydsl-collections without generated query types, use the Querydsl alias feature.

Add the following static imports:

// needed for access of the Querydsl Collections API
import static com.querydsl.collections.CollQueryFactory.*;
// needed if you use the $-invocations
import static com.querydsl.core.alias.Alias.*;

Create an alias instance for the Cat class. Alias instances can only be created for non-final classes with an empty constructor.

The alias instance and its getter invocations are transformed into paths by wrapping them in dollar-method invocations. The call c.getKittens() is internally transformed into the property path c.kittens inside the dollar method.

Cat c = alias(Cat.class, "cat");
for (String name : select($(c.getName())).from($(c),cats)
  .where($(c.getKittens()).size().gt(0))
  .fetch()) {
    System.out.println(name);
}

The following example is a variation where the access to the list size happens inside the dollar-method invocation:

Cat c = alias(Cat.class, "cat");
for (String name : select($(c.getName())).from($(c),cats)
  .where($(c.getKittens().size()).gt(0))
  .fetch()) {
    System.out.println(name);
}

All non-primitive and non-final typed properties of aliases are aliases themselves. You may cascade method calls until you hit a primitive or final type in the dollar-method scope, e.g.:

$(c.getMate().getName())

is transformed into c.mate.name internally, but:

$(c.getMate().getName().toLowerCase())

is not transformed properly, since the toLowerCase() invocation is not tracked.

You may only invoke getters, size(), contains(Object), and get(int) on alias types. All other invocations throw exceptions.

Usage With Generated Query Types

The same query expressed with generated expression types:

QCat cat = new QCat("cat");
for (String name : select(cat.name).from(cat,cats)
  .where(cat.kittens.size().gt(0))
  .fetch()) {
    System.out.println(name);
}

When you use generated query types, you instantiate expressions instead of alias instances and use the property paths directly without any dollar-method wrapping.

Maven Integration

Add the following dependencies to your Maven project:

<dependency>
  <groupId>io.github.openfeign.querydsl</groupId>
  <artifactId>querydsl-collections</artifactId>
  <version>7.1</version>
</dependency>

If you are not using JPA you can generate expression types for your domain types by annotating them with com.querydsl.core.annotations.QueryEntity and configuring the maven-compiler-plugin:

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <generatedSourcesDirectory>target/generated-sources/java</generatedSourcesDirectory>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>io.github.openfeign.querydsl</groupId>
      <artifactId>querydsl-apt</artifactId>
      <version>7.1</version>
      <classifier>general</classifier>
    </dependency>
  </dependencies>
</plugin>

Hamcrest Matchers

Querydsl Collections provides Hamcrest matchers:

import static org.hamcrest.core.IsEqual.equalTo;
import static com.querydsl.collections.PathMatcher.hasValue;
import static org.junit.Assert.assertThat;

Car car = new Car();
car.setHorsePower(123);

assertThat(car, hasValue($.horsePower));
assertThat(car, hasValue($.horsePower, equalTo(123)));

Usage With the Eclipse Compiler for Java

If querydsl-collections is used with a JRE where the system compiler is not available, CollQuery instances can be configured to use the Eclipse Compiler for Java (ECJ) instead:

DefaultEvaluatorFactory evaluatorFactory = new DefaultEvaluatorFactory(
    CollQueryTemplates.DEFAULT,
    new ECJEvaluatorFactory(getClass().getClassLoader()));
QueryEngine queryEngine = new DefaultQueryEngine(evaluatorFactory);
CollQuery query = new CollQuery(queryEngine);