Download
Logo
Overview
News
Download
Motivation
Examples
Troubleshoot

The Anqu Method Pattern

The anqu method pattern for Java suggests to have a central method to access a @NamedQuery or @NamedNativeQuery. In short the pattern proposes the following construction for a given query:
Example

You may already be using this pattern in some variation - you could call it common sense. What is not shown is the method body containig the glue code to execute the query. It is cumbersome to implement and the API to use is one of the most general APIs you can think of. Nearly every parameter is either just Object or at best String. Writing that code is error-prone.

Building the bridge between the textual nature of the @NamedQuery statement and the modeled Java world early reduces risks and enables you to use compiler based tooling to increase coding comfort.

Driven by this the anqu method pattern consists of three principles:

Single Point of Transition:
Have a single method in your code to do the transition to the modeled Java world for a query. Do not repeat the glue code somewhere else and do not let this method do anything else.
Early Transition:
Do the transition from the query statement to the Java world as early/deep in your layers as possible.
Test the Contract:
Have tests to ensure that the three parts dealing with the query (the Java model, the query statement, and the glue code) always fit together.

If you use Eclipse as IDE, the anqu method plug-in can generate the Java method in a few mouse clicks. You get a specialized, typed, already implemented, and unit-tested API for every query. The plug-in helps to implement all steps mentioned above and has addtional features to increase productivity.

Please note that in the example above the EntityManager is provided as a parameter of a static method. Though this is optional/configurable, this variation is considered to be the earliest transition you can come up with.

Plug-In Capabilities

The following picture shows how the main functionalities of anqu method improve the typical workflow of creating and using a named (maybe native) query:

Plug-In Capabilities

anqu method generates access methods to named queries. The derived methods will encapsulate query creation and parameter preparation. The parameters of the query will be the parameters of the method - and they will be typed. In the most basic version the method will return the created query. You have to execute it yourself.

If you let anqu method try better, you can let it generate a method that not only creates and configures the query but also executes it. In case of a Select you will get a List as a result. anqu method will try to derive the type of objects in the List and provide a typed List. Deriving the return type is not always possible. You may end up with Object as best guess. In case of an update or delete you will get the number of affected rows as a result.

If you know that the query will at most return one result object, you can let anqu method generate a single/first result method. It will return null if there was no result.

Another possibility is to generate methods with pagination support. There will be additional parameters for starting point and page size.

anqu method can also generate JUnit 4 tests for the productive methods providing full code coverage and regression safety to some extend.

In addition to that the plug-in supports you in adding a @NamedQuery to an existing class. It will generate such an annotation and if there already is one, it will wrap around the necessary @NamedQueries annotation automatically.

Even writing the query statement can be omitted if the query name follows some simple rules. In this case just derived the statement from the query name. Most simple examples are "findByName" and "Xyz.deleteAll".

It is also possible to generate the glue code to access a @NamedQuery from a Spring Data or Apache DeltaSpike Data repository.

Mocking the EntityManager (and Query) in unit tests to avoid building a container environment is a common strategy. But programming the mocks is cumbersome. Anqu can create Mock Utility classes with static helper methods to program the EntityManager mock easily. Generate a Mock Utility specific for a query or create a generic Mock Utility for all queries, hence with a less comfortable API. If the query statement is simple enough to be derived from the query name, that query name is the only thing which has to be written by the programmer. All the other code can be generated.

Usage

Auto Completion

The most important features are now available via Eclipse auto completion. Functionality depends on the context:

Cursor Location Functionality
Outside a @NamedQuery annotation
Add @NamedQuery annotation to code.
Inside @NameQuery annotation, directly after dot/period in the name attibute
Get proposals for query names, e.g. findAll and find-methods for every field. Selecting a proposal also derives the statement and fills the query attribute.
Inside @NameQuery annotation, at first position of the query attribute
Derive the statement from the name attribute.
Anywhere else inside the @NameQuery annotation
Get proposals for query execution methods.

Adding a Named Query

To add a named query to an existing class open the context menu from the Java source code editor and select Anqu Method, then select New Named Query or New Named Native Query as shown below:

Add a NamedQuery with the context menu

A new and mostly empty @NamedQuery or @NamedNativeQuery annotation will appear in the source code ready to be edited.

Deriving Statements

In simple cases the name of the query is enough information to automatically derive the desired statement from it. Note that this only works for JP QL queries - not for native queries. Here is a short (reduced) description the grammar behind the recognition algorithm.

Semantics Keywords Comment
Select all objects
getAll, findAll, readAll, selectAll
No additions allowed
Delete all objects
deleteAll, delAll, removeAll
No additions allowed
Select objects
get, find, read, select
Combinable with restrictions and sorting
Delete objects
delete, del, remove
Combinable with restrictions
Field names
Camel case field name of the current entity, first character upper case.
E.g. NameOfStreet if there is a field String nameOfStreet in the entity class. Also works with cascading references such as StreetName if there is a field street of a class having a field name.
Update objects
update, set
E.g. setNameToNull, where name is a field of the current entity; Use 'and' to set more than one field: setNameToNullAndStreetToNull; Combinable with restrictions
Parameters for e.g. restrictions
Given + camel case parameter name
To distinguish between field references and intended parameters, parameters have to be prefixed bei Given
Restrictions
Where, By + field name; And, Or for chaining; Operators e.g. LessThan, EqualTo, IsNotNull and more!
Binary operators can cope with parameters and fields in both cases. Using By + field name indicates a query parameter for that field name.
Sorting
Order, Sort, Asc, Ascending, Desc, Descending, By
Various combinations such as OrderAscBy + field name or SortBy + field name + DescendingBy + other field name are possible. Sort and Order are not needed in cases like AscBy + field name

Generating Methods

To distinguish the created methods the terms productive methods and test methods are used in this section.

When creating methods, you need to set the cursor into the @NamedQuery or @NamedNativeQuery and open the context menu. Please note that just opening the context menu while the mouse pointer is over the query will not work. It really depends on where the cursor is in the editor.

Now choose Anqu Method and select the desired action in two steps:

Context menu

  1. What kind of method to generate
    • Method executing the query
    • Method executing the query, returning one (the first) result
    • Method creating the query and returning it
    • First/Max method executing the query - with firstResult and maxResults as parameters
    • First/Max method creating the query and returning it - with firstResult and maxResults as parameters
  2. Productive and/or test code and the target(s)
    • (Productive) Method to source file holding the query and tests as configured (see settings)
    • (Productive) Method to source file holding the query
    • (Productive) Method to clipboard
    • Tests as configured (see settings)
You can open the help page of this plug-in via the context menu as well as its preference page. See the next section on possible configurations.

Removing Code

You can remove a @NamedQuery, the corresponding glue code, the generated tests, and the generated MockUtility with this functionality. It is also possible to remove all the code but the @NamedQuery itself.

Remove menu

This will not remove code that has been generated into the clipboard and has been pasted somewhere. Only the following locations are cleaned up if present:

  • Glue code in the Entity (annotation and/or method are removed)
  • Test class in the same package on a 'one class per query' basis (source file is removed)
  • Test class in the same package on a 'one class for all queries' basis (methods are removed)
  • MockUtilty in the same package (source file is removed)

Settings

All settings described in this section are global. The ?-buttons give descriptions of the options.

Options for Generated Methods

Settings for the method

  • The modifier of generated methods is public static by default.
  • The insertion position of a method which is generated into source code.
  • Parameter order of generated methods is alphabetical by default. This can be changed to the order of appearance in the query. The EntityManager always is the first parameter in both cases.
  • If a method returning the query is generated, the method's name is this prefix followed by the query name.
  • Generated methods have English JavaDoc comments by default.
  • Generated code uses generics by default.
  • Generated code does not contain fully qualified names by default. This setting does not apply to static references on test code.
  • The EntityManager is expected to be a method parameter by default. The alternative is to expect a field to hold the EntityManager. For both cases the name of the parameter/expected field can be defined here.

Options for Test Code

Test settings

  • If the EntityManager is provided by a field, the generated test code needs to set this field to a mock. This can normally be done by reflection.
  • If the EntityManager is provided by a field and is not set by reflection (see above) an auxiliary method is needed. This method has to be implemented in every test class.
  • If the generated method is not static, the generated test code depends on an auxiliary method to get an instance of the class under test (to make the call on). The name of the expected method can be defined.
  • Test code can be generated to the clipboard or into a JUnit test file (existing or new).
  • If test code is generated to a file, the target source folder can be defined. It will not be created automatically.
  • If test code is generated to a file, the target class name can be chosen between {entity}Test.java and {entity}{method}Test.java where {entity} is the entity's class name and {method} is the generated productive method's name. This allows one test class per entity as well as one test class per method. The package will always be the package of the entity.
  • If test code is generated to a file, a query specific MockUtility class can automatically be created in the same package.

Suppression of Warnings

Warning settings

  • The generated code might cause warnings depending on the compiler settings of Eclipse. The anqu method plugin tries to overrule any potential warning by applying @SuppressWarning tags in the generated code. However too many suppressions also cause warnings. So it is possible to configure which warnings can appear and thus can by suppressed.

Deriving Statements

Derive Statements settings

  • The keyword style of generated statements can be defined.

Removing Code

Removal options

  • Bring up a confirmation dialog before removing a query and/or the generated code?

JPA Version Specific Features

JPA version activation

  • Activate repeatable annotations when adding a query. No wrapper annotation for @NamedQuery or @NamedNativeQuery will be generated. Instead a new @Named(Native)Query annotation will appear. Note that if there already is such a wrapper annotation, it will be used in any case.

Unit Tests

The generated test methods have the following goals:
  • Ensure that the productive method has not been changed
  • Ensure that the query has not been changed
  • Ensure that the relevant entity code has not been changed
  • 100% test coverage for the productive methods
Several test methods are generated for a single productive method. Of course all of them take part in the coverage goal (which is the only goal that can be reached for sure). Some tests try to protect the code from becoming inconsistent due to manual changes. This is based on some heuristics. Especially checking that the method's code is unchanged is done in a rather optimistic way. If a test fails, first thing to do is to check the query semantically. If it is correct, re-generate the productive method and the test methods. If a newly generated test fails, this plug-in has a bug.

For clarification: The generated test methods do not test the query's semantics, not even if the query is syntactically correct.

Mock Utilities

Anqu method can simplify mocking query executions by creating Mock Utility helper classes. A query specific Mock Utility class contains static methods to program a given EntityManager mock to return the provided values or to throw the provided RuntimeException.

Also a generic Mock Utility can be generated being able to mock any @NamedQuery execution. The API of the generic Mock Utility is powerful, yet not as comfortable to use as a query specific one. The generic utility is considered a fallback.

Naming Recommendations

This plug-in generates methods from queries just like 'Generate getters and setters' generates methods from fields. In both cases names have to be found. As a query's name has big impact on the name of the generated method, please consider the following recommendations:
  • Use a prefix when naming your queries to make the names unique (e.g. use class name as prefix)
  • Use a character that is not allowed in method names (e.g. fullstop, blank) to append a query name to the prefix
  • Let the query name (suffix) describe the effect of the query, that is make it sound like a method name
This plug-in will split the full query name and try to find the suffix using the assumption that the above recommendations have been met. You will get well named methods. Example: The query names "MyEntity.findByName", "MyEntity findByName" "MyEntity:findByName" will all result in a method named "findByName". If you generate a method to return the query object itself (without executing the query) the method's name will be prefixed by the text 'getQuery' or whatever you defined in the preferences.

Known Limitations

  • This plug-in is based on the JPA 2.0 specification. Special extensions like such of Hibernate are not supported explicitly.
  • The annotation attribute 'name' of the annotation @Entity is ignored, finding types is based on class names.
  • Test code can always be generated even if the visibility settings for the productive methods makes these methods unvisible to the test code.
  • Trying to create a single result method for an update or delete will create a normal method executing the query. Same holds for test generation. This is more a feature than a limitation.
  • Creating an first result/max results method for update or delete statement is possible but does not really make sense.
  • MockUtility classes do not work for JPA 1.0
  • For @NamedNativeQuery methods only @SqlResultSetMapping annotations in the entity class itself are considered.
  • In @NamedNativeQuery methods all parameters will be of type Object (sad but true, the are untyped).
  • Removing a @NamedNativeQuery does not remove a related SqlResultSetMapping.


top