The Java 6 APT annotation processing functionality is used in Querydsl for code generation in the JPA, JDO and Mongodb modules. This section describes various configuration options for the code generation and an alternative to APT usage.
By default Querydsl initializes only reference properties of the first two levels. In cases where
longer initialization paths are required, these have to be annotated in the domain
types via
com.mysema.query.annotations.QueryInit
annotations. QueryInit is used on properties where deep initializations are
needed. The following example demonstrates the usage.
@Entity class Event { @QueryInit("customer.address") Account account; } @Entity class Account { Customer customer; } @Entity class Customer { String name; Address address; // ... }
This example enforces the initialization of the account.customer path, when an Event path is initialized as a root path / variable. The path initialization format supports wildcards as well, e.g. "customer.*" or just "*".
The automatic path initialization replaces the manual one, which required the entity fields to be non-final. The declarative format has the benefit to be applied to all top level instances of a Query type and to enable the usage of final entity fields.
Automatic path initialization is the preferred initialization strategy, but manual initialization can be activated via the Config annotation, which is described below.
The serialization of Querydsl can be customized via Config annotations on packages and types. They customize the serialization of the annotated package or type.
The serialization options are
Table 3.1. Config options
Name | Description |
---|---|
entityAccessors | accessor methods for entity paths instead of public final fields (default: false) |
listAccessors | listProperty(int index) style methods (default: false) |
mapAccessors | mapProperty(Key key) style accessor methods (default: false) |
createDefaultVariable | generate the default variable (default: true) |
defaultVariableName | name of the default variable |
Below are some examples.
Customization of Entity type serialization:
@Config(entityAccessors=true) @Entity public class User { //... }
Customization of package content:
@Config(listAccessors=true) package com.mysema.query.domain.rel; import com.mysema.query.annotations.Config;
If you want to customize the serializer configuration globally, you can do this via the following APT options
Table 3.2. APT options
Name | Description |
---|---|
querydsl.entityAccessors | enable reference field accessors |
querydsl.listAccessors | enable accessors for direct indexed list access |
querydsl.mapAccessors | enable accessors for direct key based map access |
querydsl.prefix | override the prefix for query types(default: Q) |
querydsl.suffix | set a suffix for query types |
querydsl.packageSuffix | set a suffix for query type packages |
querydsl.createDefaultVariable | set whether default variables are created |
querydsl.unknownAsEmbeddable | set where unknown non-annotated classes should be treated as embeddable (default: false) |
querydsl.includedPackages | comma separated list of packages to be included into code generation (default: all) |
querydsl.includedClasses | comma separated list of class names to be included into code generation (default: all) |
querydsl.excludedPackages | comma separated list of packages to be excluded from code generation (default: none) |
querydsl.excludedClasses | comma separated list of class names to be excluded from code generation (default: none) |
Using the Maven APT plugin this works for example like this:
<project> <build> <plugins> ... <plugin> <groupId>com.mysema.maven</groupId> <artifactId>apt-maven-plugin</artifactId> <version>1.1.3</version> <executions> <execution> <goals> <goal>process</goal> </goals> <configuration> <outputDirectory>target/generated-sources/java</outputDirectory> <processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor> <options> <querydsl.entityAccessors>true</querydsl.entityAccessors> </options> </configuration> </execution> </executions> </plugin> ... </plugins> </build> </project>
Custom type mappings can be used on properties to override the derived Path type. This can be useful for example in cases where comparison and String operations should be blocked on certain String paths or Date / Time support for custom types needs to be added. Support for Date / Time types of the Joda time API and JDK (java.util.Date, Calendar and subtypes) is built in, but other APIs might need to be supported using this feature.
The following example demonstrates the usage:
@Entity public class MyEntity { @QueryType(PropertyType.SIMPLE) public String stringAsSimple; @QueryType(PropertyType.COMPARABLE) public String stringAsComparable; @QueryType(PropertyType.NONE) public String stringNotInQuerydsl; }
The value PropertyType.NONE
can be used to skip a property in the
query type generation. This case is different from @Transient or @QueryTransient
annotated properties, where properties are not persisted. PropertyType.NONE just
omits the property from the Querydsl query type.
To declare a static method as a delegate method add the QueryDelegate annotation with the corresponding domain type as a value and provide a method signature that takes the corresponding Querydsl query type as the first argument.
Here is a simple example from a unit test:
@QueryEntity public static class User { String name; User manager; }
@QueryDelegate(User.class) public static BooleanPath isManagedBy(QUser user, User other) { return user.manager.eq(other); }
And the generated methods in the QUser query type:
public BooleanPath isManagedBy(QUser other) { return com.mysema.query.domain.DelegateTest.isManagedBy(this, other); }
Delegate methods can also be used to extend built-in types. Here are some examples
public class QueryExtensions { @QueryDelegate(Date.class) public static BooleanExpression inPeriod(DatePath<Date> date, Pair<Date,Date> period) { return date.goe(period.getFirst()).and(date.loe(period.getSecond())); } @QueryDelegate(Timestamp.class) public static BooleanExpression inDatePeriod(DateTimePath<Timestamp> timestamp, Pair<Date,Date> period) { Timestamp first = new Timestamp(DateUtils.truncate(period.getFirst(), Calendar.DAY_OF_MONTH).getTime()); Calendar second = Calendar.getInstance(); second.setTime(DateUtils.truncate(period.getSecond(), Calendar.DAY_OF_MONTH)); second.add(1, Calendar.DAY_OF_MONTH); return timestamp.goe(first).and(timestamp.lt(new Timestamp(second.getTimeInMillis()))); } }
When delegate methods are declared for builtin types then subclasses with the proper delegate method usages are created:
public class QDate extends DatePath<java.sql.Date> { public QDate(BeanPath<? extends java.sql.Date> entity) { super(entity.getType(), entity.getMetadata()); } public QDate(PathMetadata<?> metadata) { super(java.sql.Date.class, metadata); } public BooleanExpression inPeriod(com.mysema.commons.lang.Pair<java.sql.Date, java.sql.Date> period) { return QueryExtensions.inPeriod(this, period); } } public class QTimestamp extends DateTimePath<java.sql.Timestamp> { public QTimestamp(BeanPath<? extends java.sql.Timestamp> entity) { super(entity.getType(), entity.getMetadata()); } public QTimestamp(PathMetadata<?> metadata) { super(java.sql.Timestamp.class, metadata); } public BooleanExpression inDatePeriod(com.mysema.commons.lang.Pair<java.sql.Date, java.sql.Date> period) { return QueryExtensions.inDatePeriod(this, period); } }
It is possible to create Querydsl query types for non annotated types by
creating @QueryEntities
annotations. Just place a QueryEntities annotation into a
package of your choice and the classes to mirrored in the value attribute.
To actually create the types use the com.mysema.query.apt.QuerydslAnnotationProcessor
.
In Maven you do it like this:
<project> <build> <plugins> ... <plugin> <groupId>com.mysema.maven</groupId> <artifactId>apt-maven-plugin</artifactId> <version>1.1.3</version> <executions> <execution> <goals> <goal>process</goal> </goals> <configuration> <outputDirectory>target/generated-sources/java</outputDirectory> <processor>com.mysema.query.apt.QuerydslAnnotationProcessor</processor> </configuration> </execution> </executions> </plugin> ... </plugins> </build> </project>
For cases where annotated Java sources
are not available, such as the usage of a different JVM
language such as Scala or Groovy or annotation addition via bytecode manipulation the
GenericExporter
class can be used to scan the classpath for annotated classes and
generate query types for them.
To make GenericExporter available add a dependency to the querydsl-codegen
module to your project, or to be more precise
com.mysema.querydsl:querydsl-codegen:${querydsl.version}
.
Below is an example for JPA
GenericExporter exporter = new GenericExporter(); exporter.setKeywords(Keywords.JPA); exporter.setEntityAnnotation(Entity.class); exporter.setEmbeddableAnnotation(Embeddable.class); exporter.setEmbeddedAnnotation(Embedded.class); exporter.setSupertypeAnnotation(MappedSuperclass.class); exporter.setSkipAnnotation(Transient.class); exporter.setTargetFolder(new File("target/generated-sources/java")); exporter.export(DomainClass.class.getPackage());
This will export all the JPA annotated classes in the package of the DomainClass class and subpackages to the target/generated-sources/java directory.
The goals generic-export, jpa-export and jdo-export of the querydsl-maven-plugin can be used for GenericExporter usage via Maven.
The different goals are mapped to the Querydsl, JPA and JDO annotations.
The configuration elements are
Table 3.3. Maven configuration
Type | Element | Description |
---|---|---|
File | targetFolder | target folder for generated sources |
boolean | scala | true, if Scala sources should be generated instead (default: false) |
String[] | packages | packages to be introspected for entity classes |
boolean | handleFields | true, if fields should be treated as properties (default: true) |
boolean | handleMethods | true, if getters should be treated as properties (default: true) |
String | sourceEncoding | charset encoding for the generated source files |
boolean | testClasspath | true, if the test classpath should be used instead |
Here is an example for JPA annotated classes
<project> <build> <plugins> ... <plugin> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-maven-plugin</artifactId> <version>${querydsl.version}</version> <executions> <execution> <phase>process-classes</phase> <goals> <goal>jpa-export</goal> </goals> <configuration> <targetFolder>target/generated-sources/java</targetFolder> <packages> <package>com.example.domain</package> </packages> </configuration> </execution> </executions> </plugin> ... </plugins> </build> </project>
This will export the JPA annotated classes of the com.example.domain
package and
subpackages to the target/generated-sources/java directory.
If you need to compile the generated sources directly after that, then you can use
the compile
goal for that.
<execution> <goals> <goal>compile</goal> </goals> <configuration> <sourceFolder>target/generated-sources/scala</targetFolder> </configuration> </execution>
The compile
goal has the following configuration elements
Table 3.4. Maven configuration
Type | Element | Description |
---|---|---|
File | sourceFolder | source folder with generated sources |
String | sourceEncoding | charset encoding of sources |
String | source | -source option for the compiler |
String | target | -target option for the compiler |
boolean | testClasspath | true, if the test classpath should be used instead |
Map | compilerOptions | options for the compiler |
All options except sourceFolder
are optional.
If you need Scala output of the classes, use a variant of the following configuration
<project> <build> <plugins> ... <plugin> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-maven-plugin</artifactId> <version>${querydsl.version}</version> <dependencies> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-scala</artifactId> <version>${querydsl.version}</version> </dependency> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>${scala.version}</version> </dependency> </dependencies> <executions> <execution> <goals> <goal>jpa-export</goal> </goals> <configuration> <targetFolder>target/generated-sources/scala</targetFolder> <scala>true</scala> <packages> <package>com.example.domain</package> </packages> </configuration> </execution> </executions> </plugin> ... </plugins> </build> </project>