Skip to main content

Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "EclipseLink/Development/AdditionalCriteria"

(Additional Criteria Requirements and Design)
(A more complex example)
 
(167 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Additional Criteria Requirements and Design ==
+
<div style="float:right;width:300px">
 +
__TOC__
 +
</div>
  
Enhancement Request: {{bug|322008}}
+
== Additional Criteria Requirements and Design  ==
  
This work will introduce an additional criteria EclipseLink users can apply to a descriptors default queries in turn providing them with a filtering option. This filtering option will allow for the user to enable and disable the filter (or portions of it) as needed at runtime.
+
Enhancement Request: {{bug|322008}}
  
See the following blog from Doug discussing filters and their current usage though a descriptor customizer.
+
This work will introduce an additional criteria EclipseLink users can apply to a descriptors default queries in turn providing them with a filtering option. This filtering option will allow users to leverage the existing additional join expression from a descriptor query manager and allow parameters to be passed to it.
  
http://java-persistence.blogspot.com/2010/08/eclipselink-filters-how-to.html
+
See the following blog from Doug discussing filters and their current usage though a descriptor customizer.  
  
A point form list of requirements are then as follows:
+
http://java-persistence.blogspot.com/2010/08/eclipselink-filters-how-to.html
  
* Simplify the definition and usage of EclipseLink's additional join expressions using Eclipselink metadata.
+
A point form list of requirements are then as follows:
* Allow additional criteria to be specified through the use of annotations and xml.
+
* Allow users the option to enable and disable additional criteria.
+
* Allow for xml mapping file merging and overridding using the eclipselink-orm.xml
+
* Allow for JPQL fragments to specify the details of the additional criteria.
+
* Allow for a mechanism to pass parameters to the additional criteria.
+
* Easy to use and forward compatible.
+
* Respect the general JPA look and feel.
+
  
== Metadata ==
+
*Provide a mechanism for users to achieve:
 +
**Multi-tenancy
 +
**Soft deletes
 +
**Temporal filtering
 +
*Simplify the definition and usage of EclipseLink's additional join expressions using Eclipselink metadata.
 +
*Allow additional criteria to be specified through the use of annotations and xml.
 +
*Allow for xml mapping file merging and overridding using the eclipselink-orm.xml
 +
*Allow for JPQL fragments to specify the details of the additional criteria.
 +
*Allow for a mechanism to pass parameters to the additional criteria.
 +
*Easy to use and forward compatible.
 +
*Respect the general JPA look and feel.
  
The additional criteria will be available in the form of annotations and/or xml where additional criteria can be overriden from the eclipselink-orm.xml. XML file merging will be available as well in its current form, simply expanded to include the additional criteria and additional criteria callback methods.
+
== Metadata  ==
  
An example of the XML override is as follows:
+
The following sections will detail the metadata changes and modifications that are required. The additional criteria will be available in the form of annotations and xml and will be used to form the descritor query manager's additionalJoinExpression that is applied to all queries for that descriptor.  
* mapping.xml defines:
+
** additional-criteria named - A
+
** additional-criteria named - B
+
* eclipselink.xml defines:
+
** additional-criteria named - A
+
** additional-criteria named - C
+
  
The outcome if the following additional criteria list appended to the descriptors query event manager:
+
=== @AdditionalCriteria  ===
* A - from eclipselink-orm.xml
+
<source lang="java">
* B - from mapping.xml
+
/**
* C - from eclipselink-orm.xml
+
* An additional criteria can be specified at the Entity or MappedSuperclass
 +
* level. When specified at the mapped superclass level, it applies to all
 +
* inheriting entities unless those entities define their own additional  
 +
* criteria, at which point the additional criteria from the mapped superclass
 +
* is ignored.
 +
*
 +
* The additional criteria supports any valid JPQL string and must use 'this'
 +
* as an alias to form your additional criteria. E.G.,
 +
*
 +
* @Entity
 +
* @AdditionalCriteria("this.nut.size = :NUT_SIZE and this.nut.color = :NUT_COLOR")
 +
* public class Bolt {...}
 +
 +
* Additional criteria parameters are also accepted and are set through
 +
* properties on the entity manager factory, or on an entity manager. When set
 +
* on the entity manager, the properties must be set before any query execution
 +
* and should not be changed for the life span of that entity manager.
 +
*  
 +
* Properties set on the entity manager will override those similarly named
 +
* properties set on the entity manager factory.
 +
*  
 +
* Additional criteria is not supported with any native queries.
 +
*  
 +
* @author Guy Pelletier
 +
* @since EclipseLink 2.2
 +
*/
 +
@Target({TYPE})
 +
@Retention(RUNTIME)
 +
public @interface AdditionalCriteria {
 +
    /**
 +
    * (Required) The JPQL fragment to use as the additional criteria.
 +
    */
 +
    String value();
 +
}
 +
</source>
  
The following new element will be added to <entity> and <mapped-superclass> complex elements to facilitate the additional criteria support.
+
=== &lt;additional-criteria&gt;  ===
  
<code>
+
An additional criteria complex element will be created to allow future expansion.
  <xsd:choice>
+
    <xsd:element name="additional-criteria" type="orm:additional-criteria" maxOccurs="unbounded"/>
+
    <xsd:element name="additional-criteria-callback-method" type="orm:additional-criteria-callback-method" maxOccurs="unbounded"/>
+
  </xsd:choice>
+
</code>
+
  
The additional-criteria will be applied to all queries. Users can then further configure those queries using additional criteria callback method(s), say to append login credentials to the query.
+
<source lang="xml">
 
+
=== Additional Criteria ===
+
 
+
The additional criteria(s) will be used to form the existing additionalJoinExpression from the descriptor's query manager. See the JPQL fragment section below that will discuss how this value will be populated. The additional criterias will be stored on the query manager, keyed by name and can be enabled/disabled using properties set on the EntityManager.
+
 
+
<pre>
+
 
<xsd:complexType name="additional-criteria">
 
<xsd:complexType name="additional-criteria">
 
   <xsd:annotation>
 
   <xsd:annotation>
 
     <xsd:documentation>
 
     <xsd:documentation>
 
+
    /**
      /**
+
      * An additional criteria can be specified at the Entity or MappedSuperclass  
      * Can be specified at the Entity or MappedSuperclass level. When specified at  
+
      * level. When specified at the mapped superclass level, it applies to all  
      * the mapped superclass level, it applies to all inheriting entities unless  
+
      * inheriting entities unless those entities define their own additional  
      * those entities define their own additional criteria, at which point the  
+
      * criteria, at which point the additional criteria from the mapped superclass  
      * additional criteria from the mapped superclass is ignored.  
+
      * is ignored.
      *  
+
      *  
      * Additional criteria can be specified as a single item or as multiples using
+
      * The additional criteria supports any valid JPQL string and must use 'this'
      * the plural AdditionalCriterias annotation. Additional criteria(s) can not be  
+
      * as an alias to form your additional criteria. E.G.,
      * specified in conjunction with an additional criteria callback.  
+
      *  
      *  
+
      * @Entity
      * @author Guy Pelletier
+
      * @AdditionalCriteria("this.nut.size = :NUT_SIZE and this.nut.color = :NUT_COLOR")
      * @since EclipseLink 2.2
+
      * public class Bolt {...}
      */
+
      * 
      @Target({TYPE})
+
      * Additional criteria parameters are also accepted and are set through
      @Retention(RUNTIME)
+
      * properties on the entity manager factory, or on an entity manager. When set
      public @interface AdditionalCriteria {
+
      * on the entity manager, the properties must be set before any query execution
          /**
+
      * and should not be changed for the life span of that entity manager.
          * (Optional) The name of the additional criteria. Naming allows the
+
      *  
          * capability of turning off individual criteria based on name.
+
      * Properties set on the entity manager will override those similarly named
          */
+
      * properties set on the entity manager factory.
           String name() default "default";
+
      *
   
+
      * Additional criteria is not supported with any native queries.
          /**
+
      *  
          * (Optional) By default, the additional criteria is not enabled and applied.
+
      * @author Guy Pelletier
          */
+
      * @since EclipseLink 2.2
          boolean enabled() default false;
+
      */
   
+
    @Target({TYPE})
          /**
+
    @Retention(RUNTIME)
          * (Required) The JPQL fragment to use as the additional criteria.
+
    public @interface AdditionalCriteria {
          */
+
        /**
          String value();
+
           * (Required) The JPQL fragment to use as the additional criteria.
 +
          */
 +
        String value();
 
       }
 
       }
  
Line 95: Line 119:
 
       <xsd:element name="criteria" type="xsd:string"/>
 
       <xsd:element name="criteria" type="xsd:string"/>
 
   </xsd:sequence>
 
   </xsd:sequence>
  <xsd:attribute name="name" type="xsd:string"/>
 
  <xsd:attribute name="enabled" type="xsd:boolean"/>
 
 
</xsd:complexType>
 
</xsd:complexType>
</pre>
+
</source>
 +
The additional-criteria element will be added to entity and mapped-superclass complex elements as follows
 +
<source lang=xml>
 +
<xsd:complexType name="entity">
 +
    <xsd:annotation>
 +
      <xsd:documentation>
 +
      ...
 +
      </xsd:documentation>
 +
    </xsd:annotation>
 +
    <xsd:sequence>
 +
      ...
 +
      <xsd:element name="additional-criteria" type="orm:additional-criteria" minOccurs="0"/>
 +
      ...
 +
    </xsd:sequence>
 +
    ...
 +
</xsd:complexType>
  
==== Example ====
+
<xsd:complexType name="mapped-superclass">
 +
    <xsd:annotation>
 +
      <xsd:documentation>
 +
      ...
 +
      </xsd:documentation>
 +
    </xsd:annotation>
 +
    <xsd:sequence>
 +
      ...
 +
      <xsd:element name="additional-criteria" type="orm:additional-criteria" minOccurs="0"/>
 +
      ...
 +
    </xsd:sequence>
 +
    ...
 +
</xsd:complexType>
 +
</source>
  
 +
=== Example  ===
 
<pre>
 
<pre>
  @AdditionalCriteria(
+
@AdditionalCriteria("this.address.city IS NOT NULL")
    name="CitySpecified",
+
    enabled=true,
+
    value="address.city IS NOT NULL"
+
  )
+
  
  <additional-criteria name="CitySpecified" enabled="true">
+
&lt;additional-criteria&gt;
    <criteria>address.city IS NOT NULL</criteria>
+
  &lt;criteria&gt;this.address.city IS NOT NULL&lt;/criteria&gt;
  </additional-criteria>
+
&lt;/additional-criteria&gt;
 
</pre>
 
</pre>
  
=== Additional Criteria Callback - through existing EntityListener ===
+
=== Metadata overriding and merging  ===
  
The users will be able to control how the additionalJoinExpression is expressed through an EntityListener. We will allow them to decorate the entity listener with a new callback annotation (AdditionalCallbackMethod) to specify those methods that should be used to generate additional join expressions.
+
The additional criteria can be overridden from the eclipselink-orm.xml. XML file merging will be available as well in its current form, simply expanded to include the additional criteria. The following will be the order of precedence used to determine the which additional-criteria is applied to the descriptor.
  
Using a callback class, users can further control which additional criteria is used for individual query classes. See the AdditionalCriteriaCallbackMethod below.
+
#eclipselink-orm.xml
 +
#mapping file
 +
#on the entity class
 +
#on a mapped superclass (first one to define one)
  
Multiple additional callback methods for the same query class will be allowed and cause each callback method to be called (although the order of invocation is not predictable)
+
=== Internal mapping  ===
  
<pre>
+
The additional criteria will be used to form the additionalJoinExpression from the descriptor's query manager.
  <xsd:complexType name="entity-listener">
+
    <xsd:annotation>
+
      <xsd:documentation>
+
  
        Defines an entity listener to be invoked at lifecycle events
+
== Core  ==
        for the entities that list this listener.
+
  
      </xsd:documentation>
+
The following sections will detail the core changes and modifications that are required.
    </xsd:annotation>
+
    <xsd:sequence>
+
      <xsd:element name="description" type="xsd:string" minOccurs="0"/>
+
      <xsd:element name="pre-persist" type="orm:pre-persist" minOccurs="0"/>
+
      <xsd:element name="post-persist" type="orm:post-persist"
+
                  minOccurs="0"/>
+
      <xsd:element name="pre-remove" type="orm:pre-remove" minOccurs="0"/>
+
      <xsd:element name="post-remove" type="orm:post-remove" minOccurs="0"/>
+
      <xsd:element name="pre-update" type="orm:pre-update" minOccurs="0"/>
+
      <xsd:element name="post-update" type="orm:post-update" minOccurs="0"/>
+
      <xsd:element name="post-load" type="orm:post-load" minOccurs="0"/>
+
      <xsd:element name="additional-criteria-method" type="orm:additional-criteria-method" maxOccurs="unbounded"/>
+
    </xsd:sequence>
+
    <xsd:attribute name="class" type="xsd:string" use="required"/>
+
  </xsd:complexType>
+
</pre>
+
  
==== Additional Criteria Callback Method ====
+
=== DescriptorQueryManager  ===
  
The additional criteria callback method(s) control which methods from the callback class are used to control the additional criteria and to which queries they apply.
+
The additional criteria will be used to form the existing additional join expression stored on the descriptor query manager. Care must be taken by those users who currently set the additional join expression directly through a customizer. Adding additional criteria will be AND'ed to this expression.
  
<pre>
+
The metadata will set the additional criteria through the following new API on the DescriptorQueryManager.
<xsd:complexType name="additional-criteria-callback-method">
+
  <xsd:annotation>
+
    <xsd:documentation>
+
+
      /**
+
      * An additional criteria callback method(s) is specified on an additional
+
      * criteria callback class. It also defines the EclipseLink queries that should
+
      * call the method on execution.
+
      *
+
      * @author Guy Pelletier
+
      * @since EclipseLink 2.2
+
      */
+
      @Target({METHOD})
+
      @Retention(RUNTIME)
+
      public @interface AdditionalCriteriaCallbackMethod {   
+
          /**
+
          * (Optional) The list of EclipseLink query classes that will accept the
+
          * additional criteria. E.g. ReadAllQuery.class, DeleteObjectQuery.class.
+
          * By defaul the callback method is applied to all queries.
+
          *
+
          * There can be multiple AdditionalCriteriaCallbackMethod on a callback
+
          * class.
+
          */
+
          Class[] value() default {};
+
      }
+
 
+
    </xsd:documentation>
+
  </xsd:annotation>
+
  <xsd:sequence>
+
      <xsd:element name="query-class" type="xsd:string" maxOccurs="unbounded"/>
+
  </xsd:sequence>
+
  <xsd:attribute name="name" type="xsd:string" use="required"/>
+
</xsd:complexType>
+
</pre>
+
  
==== Example ====
+
<source lang="java">public void setAdditionalCriteria(String jpqlFragment)</source>
  
<pre>
+
The jpql fragment will be parsed into the additional join expression at post-initialization time. Any parsing exceptions will be thrown at that time.
  
@EntityListener(CustomerUserCriteria.class)
+
Other new API added to DescriptorQueryManager:
  
public class CustomerUserCriteria {
+
<source lang="java">
  @AdditionalCriteriaCallbackMethod
+
HashMap<String, Class> getAdditionalCriteriaArguments() // key = name and value = type
  public void handleAll(DatabaseQuery query) {}
+
boolean hasAdditionalCriteria()
 +
boolean hasAdditionalCriteriaArguments()
 +
</source>
  
  @AdditionalCriteriaCallbackMethod({ReadAllQuery.class, ReadObject.class})
+
=== JPQL fragment parsing ===
  public void handleRead(DatabaseQuery query) {}
+
  
  @AdditionalCriteriaCallbackMethod({DeleteObjectQuery.class, DeleteAllQuery.class})
+
We will tie into the existing JPQL parser to parse the additional criteria where the only alias allowed will be 'this'. We will prepend the following select statement with the additional criteria JPQL fragment and harness the selection criteria from that resulting query and set it to be the additional join expression.
  public void handleDelete(DatabaseQuery query) {}
+
}
+
  
<entity-listener class="CustomerUserCriteria"/>
+
<pre>Select this from &lt;class&gt; this where</pre>
  
<entity-listener class="CustomerUserCriteria">
+
The JPQL will be parsed at descriptor postInitialization time. Multiple selects will not be supported in the JPQL fragment.
  <additional-criteria-callback-method name="handleAll"/>
+
  <additional-criteria-callback-method name="handleRead">
+
    <query-class>ReadAllQuery</query-class>
+
    <query-class>ReadObjectQuery</query-class>
+
  </additional-criteria-callback-method>
+
  <additional-criteria-callback-method name="handleDelete">
+
    <query-class>org.eclipse.persistence.queries.DeleteAllQuery</query-class>
+
    <query-class>org.eclipse.persistence.queries.DeleteObjectQuery</query-class>
+
  </additional-criteria-callback-method>
+
</entity-listener>
+
</pre>
+
  
==== Notes ====
+
=== Parameters ===
* The org.eclipse.persistence.queries package will be appended by default to the query-class.
+
  
== Enabling/Disabling additional criteria ==
+
At runtime, users will provide parameters to their additional criteria during EntityManager create or through a set property call before any query execution. Changing the parameters during the lifespan of the EntityManager is not defined and could lead to a 'corrupted' cache and unpredictable results.
  
The additional criteria will be enable and disabled using EntityManager properties:
+
Parameters are global in scope and are added to the active JPA context (server session) and will be applied all additional criteria that accept the same parameter name at query execution time.
  
The following properties will be added to org.eclipse.persistence.config.PersistenceUnitProperties
+
'''NOTE:''' Users must be careful when selecting their parameter names so as to not conflict with existing JPA and Eclipselink properties.
  
*eclipselink-enable-additional-criteria
+
Query parameters and their types will be available from the DescriptorQueryManager after postInitialization through the following API:
*eclipselink-disable-additional-criteria
+
  
Both properties accept the 'entity-name:additional-criteria-name' format to specify which additional
+
<source lang="java">
criteria to enable/disable.
+
HashMap<String, Class> getAdditionalCriteriaArguments()
 +
</source>
  
Example:
+
These parameters are added to each executing query during its prepare. More specifically in the call to buildArgumentFields(). Following that, the parameter values are added to each executing query before its execution in the call to rowFromArguments(List, AbstractSession). The properties are extracted from the session given. If an additional criteria parameter value is not found, a new exception QueryException.argumentFromAdditionalCriteriaMissing is thrown. To ease the checking if a parameter is an additional criteria parameter, the following API had been added to DatabaseQuery:
  
<pre>
+
<source lang="java">
eclipselink-enable-additional-criteria = model.Employee:CompanyFilter
+
boolean isAdditionalCriteriaArgument(String argument)
</pre>
+
</source>
  
This would then enable the additional criteria named 'CompanayFilter' on the model.Employee's DescriptorQueryManager.
+
Beyond that, existing checking remains in place for an incorrect number of arguments vs. number of values provided, that is, QueryException.argumentSizeMismatchInQueryAndQueryDefinition
  
These properties are passed to the EntityManager through the following API:
+
=== Example  ===
#setProperties
+
#setProperty
+
#find
+
#refresh
+
#remove
+
  
== Passing parameters to the additional criteria ==
+
With the given additional additional criteria  
 +
<source lang="java">
 +
package model;
  
... work in progress ...
+
@AdditionalCriteria("this.company=:COMPANY")
 +
public class Employee {
 +
  ...
 +
}
 +
</source>
  
== Core ==
+
Setting the following property on the EntityManager would return all employees of Oracle.
  
=== JPQL fragment ===
+
<source lang="java">entityManager.setProperty("COMPANY", "Oracle");</source>
The current notion will be to tie into the existing JPQL parser to parse the additional criteria where the only alias allowed will be 'this'. We will prepend the select statement, e.g. "Select this from <class> this where" and harness the selection criteria from that resulting query and appended to the executing query.
+
  
For an additional criteria group, each selection criteria harnessed from each additional criteria within the group will be joined with an 'AND'
+
=== A more complex example ===
  
Items that will not be supported in the JPQL fragment are:
+
<source lang="java">
* multiple selects
+
@Entity
* order by
+
@AdditionalCriteria("this.nut.size = :NUT_SIZE and this.nut.color = :NUT_COLOR order by this.id")
* group by
+
public class Bolt {
* ... more to come ...
+
...
 +
}
 +
</source>
  
=== Query manager ===
+
This additional criteria accepts two parameters across a 1-1 relation and is order by id.
  
Will be responsible for controlling the additional criteria that is applied to the queries. That is, it will take into consideration the additional criteria that is enabled. The query manager is responsible for directing the executing query to the related/associated callback method from the callback class (entity listener or entity class itself).
+
=== Exceptions/Open Issues/Future ===
  
The query manager will store the list of user decorated additional criteria.
+
* Exception: Additional criteria specified on a descriptor within an inheritance hierarchy using views is not supported.
 +
* Future: Allow additional criteria to be specified at the mapping level.
 +
* Future: Allow multiple additional criteria with option to enable/disable individual additonal criteria

Latest revision as of 17:16, 9 March 2011

Additional Criteria Requirements and Design

Enhancement Request: bug 322008

This work will introduce an additional criteria EclipseLink users can apply to a descriptors default queries in turn providing them with a filtering option. This filtering option will allow users to leverage the existing additional join expression from a descriptor query manager and allow parameters to be passed to it.

See the following blog from Doug discussing filters and their current usage though a descriptor customizer.

http://java-persistence.blogspot.com/2010/08/eclipselink-filters-how-to.html

A point form list of requirements are then as follows:

  • Provide a mechanism for users to achieve:
    • Multi-tenancy
    • Soft deletes
    • Temporal filtering
  • Simplify the definition and usage of EclipseLink's additional join expressions using Eclipselink metadata.
  • Allow additional criteria to be specified through the use of annotations and xml.
  • Allow for xml mapping file merging and overridding using the eclipselink-orm.xml
  • Allow for JPQL fragments to specify the details of the additional criteria.
  • Allow for a mechanism to pass parameters to the additional criteria.
  • Easy to use and forward compatible.
  • Respect the general JPA look and feel.

Metadata

The following sections will detail the metadata changes and modifications that are required. The additional criteria will be available in the form of annotations and xml and will be used to form the descritor query manager's additionalJoinExpression that is applied to all queries for that descriptor.

@AdditionalCriteria

/**
 * An additional criteria can be specified at the Entity or MappedSuperclass 
 * level. When specified at the mapped superclass level, it applies to all 
 * inheriting entities unless those entities define their own additional 
 * criteria, at which point the additional criteria from the mapped superclass 
 * is ignored.
 * 
 * The additional criteria supports any valid JPQL string and must use 'this' 
 * as an alias to form your additional criteria. E.G.,
 * 
 * @Entity
 * @AdditionalCriteria("this.nut.size = :NUT_SIZE and this.nut.color = :NUT_COLOR")
 * public class Bolt {...}
 *   
 * Additional criteria parameters are also accepted and are set through 
 * properties on the entity manager factory, or on an entity manager. When set 
 * on the entity manager, the properties must be set before any query execution
 * and should not be changed for the life span of that entity manager.
 * 
 * Properties set on the entity manager will override those similarly named 
 * properties set on the entity manager factory.
 * 
 * Additional criteria is not supported with any native queries.
 * 
 * @author Guy Pelletier
 * @since EclipseLink 2.2
 */
@Target({TYPE})
@Retention(RUNTIME)
public @interface AdditionalCriteria {
    /**
     * (Required) The JPQL fragment to use as the additional criteria.
     */
    String value();
}

<additional-criteria>

An additional criteria complex element will be created to allow future expansion.

<xsd:complexType name="additional-criteria">
  <xsd:annotation>
    <xsd:documentation>
     /**
      * An additional criteria can be specified at the Entity or MappedSuperclass 
      * level. When specified at the mapped superclass level, it applies to all 
      * inheriting entities unless those entities define their own additional 
      * criteria, at which point the additional criteria from the mapped superclass 
      * is ignored.
      * 
      * The additional criteria supports any valid JPQL string and must use 'this' 
      * as an alias to form your additional criteria. E.G.,
      * 
      * @Entity
      * @AdditionalCriteria("this.nut.size = :NUT_SIZE and this.nut.color = :NUT_COLOR")
      * public class Bolt {...}
      *   
      * Additional criteria parameters are also accepted and are set through 
      * properties on the entity manager factory, or on an entity manager. When set 
      * on the entity manager, the properties must be set before any query execution
      * and should not be changed for the life span of that entity manager.
      * 
      * Properties set on the entity manager will override those similarly named 
      * properties set on the entity manager factory.
      * 
      * Additional criteria is not supported with any native queries.
      * 
      * @author Guy Pelletier
      * @since EclipseLink 2.2
      */
     @Target({TYPE})
     @Retention(RUNTIME)
     public @interface AdditionalCriteria {
         /**
          * (Required) The JPQL fragment to use as the additional criteria.
          */
         String value();
      }
 
    </xsd:documentation>
  </xsd:annotation>
  <xsd:sequence>
      <xsd:element name="criteria" type="xsd:string"/>
  </xsd:sequence>
</xsd:complexType>

The additional-criteria element will be added to entity and mapped-superclass complex elements as follows

<xsd:complexType name="entity">
    <xsd:annotation>
      <xsd:documentation>
       ...
      </xsd:documentation>
    </xsd:annotation>
    <xsd:sequence>
      ...
      <xsd:element name="additional-criteria" type="orm:additional-criteria" minOccurs="0"/>
      ...
    </xsd:sequence>
    ...
</xsd:complexType>
 
<xsd:complexType name="mapped-superclass">
    <xsd:annotation>
      <xsd:documentation>
       ...
      </xsd:documentation>
    </xsd:annotation>
    <xsd:sequence>
      ...
      <xsd:element name="additional-criteria" type="orm:additional-criteria" minOccurs="0"/>
      ...
    </xsd:sequence>
    ...
</xsd:complexType>

Example

@AdditionalCriteria("this.address.city IS NOT NULL")

<additional-criteria>
  <criteria>this.address.city IS NOT NULL</criteria>
</additional-criteria>

Metadata overriding and merging

The additional criteria can be overridden from the eclipselink-orm.xml. XML file merging will be available as well in its current form, simply expanded to include the additional criteria. The following will be the order of precedence used to determine the which additional-criteria is applied to the descriptor.

  1. eclipselink-orm.xml
  2. mapping file
  3. on the entity class
  4. on a mapped superclass (first one to define one)

Internal mapping

The additional criteria will be used to form the additionalJoinExpression from the descriptor's query manager.

Core

The following sections will detail the core changes and modifications that are required.

DescriptorQueryManager

The additional criteria will be used to form the existing additional join expression stored on the descriptor query manager. Care must be taken by those users who currently set the additional join expression directly through a customizer. Adding additional criteria will be AND'ed to this expression.

The metadata will set the additional criteria through the following new API on the DescriptorQueryManager.

public void setAdditionalCriteria(String jpqlFragment)

The jpql fragment will be parsed into the additional join expression at post-initialization time. Any parsing exceptions will be thrown at that time.

Other new API added to DescriptorQueryManager:

HashMap<String, Class> getAdditionalCriteriaArguments() // key = name and value = type
boolean hasAdditionalCriteria()
boolean hasAdditionalCriteriaArguments()

JPQL fragment parsing

We will tie into the existing JPQL parser to parse the additional criteria where the only alias allowed will be 'this'. We will prepend the following select statement with the additional criteria JPQL fragment and harness the selection criteria from that resulting query and set it to be the additional join expression.

Select this from <class> this where

The JPQL will be parsed at descriptor postInitialization time. Multiple selects will not be supported in the JPQL fragment.

Parameters

At runtime, users will provide parameters to their additional criteria during EntityManager create or through a set property call before any query execution. Changing the parameters during the lifespan of the EntityManager is not defined and could lead to a 'corrupted' cache and unpredictable results.

Parameters are global in scope and are added to the active JPA context (server session) and will be applied all additional criteria that accept the same parameter name at query execution time.

NOTE: Users must be careful when selecting their parameter names so as to not conflict with existing JPA and Eclipselink properties.

Query parameters and their types will be available from the DescriptorQueryManager after postInitialization through the following API:

HashMap<String, Class> getAdditionalCriteriaArguments()

These parameters are added to each executing query during its prepare. More specifically in the call to buildArgumentFields(). Following that, the parameter values are added to each executing query before its execution in the call to rowFromArguments(List, AbstractSession). The properties are extracted from the session given. If an additional criteria parameter value is not found, a new exception QueryException.argumentFromAdditionalCriteriaMissing is thrown. To ease the checking if a parameter is an additional criteria parameter, the following API had been added to DatabaseQuery:

boolean isAdditionalCriteriaArgument(String argument)

Beyond that, existing checking remains in place for an incorrect number of arguments vs. number of values provided, that is, QueryException.argumentSizeMismatchInQueryAndQueryDefinition

Example

With the given additional additional criteria

package model;
 
@AdditionalCriteria("this.company=:COMPANY")
public class Employee {
  ...
}

Setting the following property on the EntityManager would return all employees of Oracle.

entityManager.setProperty("COMPANY", "Oracle");

A more complex example

@Entity
@AdditionalCriteria("this.nut.size = :NUT_SIZE and this.nut.color = :NUT_COLOR order by this.id")
public class Bolt {
...
}

This additional criteria accepts two parameters across a 1-1 relation and is order by id.

Exceptions/Open Issues/Future

  • Exception: Additional criteria specified on a descriptor within an inheritance hierarchy using views is not supported.
  • Future: Allow additional criteria to be specified at the mapping level.
  • Future: Allow multiple additional criteria with option to enable/disable individual additonal criteria

Back to the top