The Syntax of the JDO Query Filter


The selection logic of the JDO query is expressed in the filter string, which uses terms, operators, and query methods to create a Boolean expression. For every object in the extent or collection of candidates, if the Boolean expression of the filter string evaluates to true for that object and the object is an instance of the query's candidate class, the object is included in the results collection. If the filter string is not specified, or if it is specified as the empty string, it defaults to true. In this case, every candidate that is an instance of the candidate class satisfies the query filter.

The Terms of JDOQL

The most frequently used term of a query filter is the name of a persistent field in the query's candidate class, which is always an application data class. In the simple case, the field name is compared to another term. The examples that follow use the field names defined in the classes Foo and Bar, shown in Listing 2-1.

Listing 2-1: The Persistent Fields of the Foo and Bar Classes

start example
 public class Foo    {    private String    name;    private int       number;    private Bar       specialBar;    private HashSet   myChildren; // collection of Foo elements    private HashSet   allMyBars;  // collection of Bar elements    ...    } public class Bar    {    private int size;    ...    } 
end example

Note

You might want to bookmark Listing 2-1, as the Foo and Bar classes are used for many examples in this chapter.

If Foo is the candidate class, then the names of the fields in Foo can be used directly in the query filter. The following query filter selects all the Foo objects where its number is 5 and its name is "Mars":

 "number == 5 && name == \"Mars\"" 

Note that the query filter is a string and is, therefore, quoted. Any strings contained within it must be quoted as well, and for that reason, their quotation marks must be escaped. The query filter can use field names that are private as well as any other level of accessibility.

Although the filter looks very similar to a Java expression, the use of the equality (==) operator to compare name to "Mars" is not a Java idiom. In Java, the expression

 name == "Mars" 

can be false even when name contains the string value "Mars". In Java, the equality operator compares JVM identity, but when comparing strings, it is usually the string values, not the JVM identities, that should be compared. The following expression shows the Java idiom that compares string values:

 name.equals("Mars") 

The use of the equality operator in the query filter works because JDOQL has different semantics than the Java language. In JDOQL the equality operators (==, !=) compare the values of embedded objects and the JDO identities of application data objects. (You may recall from Chapter 1 that embedded objects do not have a JDO identity.)

The keywords this and null can also be terms in the filter expression. The keyword this refers to the candidate that is being evaluated. Using Foo as the candidate class, the following query filter selects all the Foo objects whose specialBar field is not null:

 "specialBar != null" 

Reference fields can be navigated within the query filter by using the field access (.) operator, as in the following example that finds all Foo objects with a special Bar object whose size is 2:

 "specialBar.size == 2" 

In a query filter, if a reference is null, then any subexpression using the reference evaluates to false. For that reason, the check for the null value in the following example is unnecessary:

 "specialBar != null && specialBar.size == 2" 

In general, the root terms of a JDO query filter expression or subexpression must be one of the following:

  • One of the four keyword literals: null, this, true, or false

  • A literal numeric, character, or string value (for example, 42, 3.14, 'c', or "John Smith")

  • The name of a persistent field in the candidate class, or of a persistent field reached from these by one or more field access (.) operators (for example, specialBar or specialBar.size)

  • A declared variable or parameter or a persistent field reachable from these by one or more field access operators

Parameters and variables are covered in the sections that follow. Literal string values are contained within double quotes that must be escaped within the query filter string, as the preceding examples show. Literal numeric values may be integer or floating point.

The final static members of a class would be a wonderful addition to the list of terms for JDOQL. Although the 1.0 specification allows this feature, it does not require it.

The Operators of JDOQL

The terms of JDOQL can be used to build Boolean expressions using the operators shown in Table 2-1. Most of the operators of the Java language are listed in Table 2-1.

Table 2-1: JDOQL Operators

Operator

Description

==

Equal

!=

Not equal

>

Greater than

<

Less than

>=

Greater than or equal

<=

Less than or equal

&

Boolean AND

&&

Conditional Boolean AND

|

Boolean OR

||

Conditional Boolean OR

!

Boolean NOT

~

Integral bitwise complement

+

Addition or string concatenation

-

Subtraction or unary sign inversion

*

Multiply by

/

Divide by

()

Explicitly delimit subexpression

(type)

Cast to type

.

Field access

The XOR (^) operator is not on the list. Although JDO 1.0 is inconsistent on this point, JDO 1.0.1 does not include the XOR operator.

The semantics of the operators are similar to, but not identical to, their counterparts in the Java language. The equality operators (==, !=) test JDO identity for application data classes and perform the semantic equivalent of the equals method for the supported system classes. The equality operators never test JVM identity. String concatenation (+) occurs only between strings and does not support the string + primitive construct of the Java language. Strings can be compared with the ordering operators (<, <=, >, >=). JDO leaves it to the implementation and the datastore to determine whether this is a lexicographic or locale-specific comparison. Whether the string comparisons are case sensitive also depends on the implementation.

The equality operators and the ordering operators accept both numeric primitives and the Number types (Byte, Integer, Float, Double, Long, Short, BigDecimal, BigInteger). For the Number types, the operators use the wrapped value within the object. The equality operators and the logical operators (!, |, ||, &, &&) do the same for boolean and Boolean. The equality and ordering operators perform time-value comparisons between objects of the java.util.Date class. The math operators (+, -, *, /, ~) accept both numeric primitives and the Number types. Arithmetic terms are promoted to compatible types for operations.

As was mentioned earlier, when specialBar is null, the expression

 specialBar.size == 2 

throws a NullPointerException in Java, but for the same condition in JDOQL, the expression evaluates to false. In general, when a NullPointerException arises during filter evaluation against a candidate, the innermost expression containing the field operator evaluates to false. The overall filter expression may still evaluate to true, and as a result, the candidate may still be included in the results collection. In this way, JDOQL shields the query execution from the hazards of individual candidates that may have a null reference in the fields that the JDOQL filter navigates.

Beginning with JDO 1.0.1, JDOQL also shields the query evaluation when a ClassCastException arises from using the cast operator. For each candidate where the exception is thrown, the innermost subexpression that gives rise to the exception evaluates to false. The overall filter expression may still evaluate to true, and as a result, the candidate may still be included in the results collection. In essence, the shielded cast operator acts as an instanceof operator in JDOQL, because it evaluates to false if the candidate is not of the right type.

The conditional Boolean operators (&&, ||) ensure that the right term is evaluated only if that evaluation makes a difference in the expression's value, but this feature is not tested by the JDO certification test suite. Because operators with side effects are not present in JDOQL, the conditional Boolean operators are an optimization with no semantic consequences.

Some Java operators are missing in JDOQL. The instanceof operator, the increment and decrement operators, and all of the assignment operators are not part of JDOQL. None of the operators included in JDOQL have side effects. Most of the bitwise operators are excluded, and the new operator is not supported. The array access operator ([]) is also missing.

JDO implementations may add other operators to JDOQL. Using these extensions limits the portability of your application between different JDO implementations.

The Query Methods of JDOQL

JDOQL defines four query methods for use within the query filter. Two of the query methods operate on strings, and two operate on collections. Table 2-2 lists the four query methods.

Table 2-2: JDO Query Methods

Query Method

Description

startsWith(String)

Tests if the string begins with the passed string, no wildcards

endsWith(String)

Tests if the string ends with the passed string, no wildcards

contains(Object)

Tests if the collection contains the object

isEmpty()

Tests if the collection is empty

The startsWith query method tests whether a string begins with a particular substring. For example, the following query filter on the candidate class Foo finds the foos whose names begin with "Jo":

 "name.startsWith(\"Jo\")" 

The endsWith query method tests whether a string ends with a particular substring. The startsWith method is found in the Java String class, but when startsWith is used in a JDOQL query filter, what it signifies depends on whether the query runs against objects in memory or against an extent in the datastore. If the query runs in memory, then the String class's startsWith method is called. If the query runs in the datastore, then the startsWith method is translated into the semantic equivalent in the datastore's query language. When the startsWith and endsWith methods execute in the datastore, JDO does not define whether they are case sensitive or case insensitive.

If a collection reference is null or if the collection is empty, the isEmpty method evaluates to true and the contains method evaluates to false. The contains query method has a special meaning when used with a variable. The section entitled "The Special Syntax and Semantics of the contains Method" that comes later in this chapter describes the contains query method.

In JDOQL there is no general support for methods, but implementations may support additional nonmutating query methods in JDOQL. By using an implementation-supplied extension, you limit the portability of your application.

A General Difficulty with Interface Types

Java interfaces are used to model the common behavior of unrelated classes. Since Java does not support multiple inheritance, an interface handles the need to put a common type on classes that do not share a common implementation. Generally, application data classes are fine-grained objects with only the behavior necessary to access and maintain the integrity of their data fields. As a result, many application data classes are simple classes that do not use application-defined interface types for persistent fields. On the other hand, for those classes that use such fields, be aware that JDOQL imposes limitations.

Although application data classes have persistent fields, interfaces never have persistent fields. The only members of interfaces are methods and static fields. As Chapter 5 explains, static fields are never persistent. To query on a field that is an application-defined interface type, the query filter must cast the field to one of the application data classes that implements the interface. If several application data classes implement the interface, a separate filter clause might be required for each implementing class. Clearly this approach is not modular since the query filter must be changed each time a new class implements the interface.

For these reasons, the use of application-defined interface types in the design of application data classes imposes one of two costs on the application's design. Either the fields of application-defined interface types cannot be used in queries, or the query filter is dependent on the list of application data classes that implement the interface.




Using and Understanding Java Data Objects
Using and Understanding Java Data Objects
ISBN: 1590590430
EAN: 2147483647
Year: 2005
Pages: 156
Authors: David Ezzio

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net