You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pp...@apache.org on 2009/07/29 21:07:57 UTC

svn commit: r799018 - in /openjpa/trunk: openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/ openjpa-persistence/src/main/java/org/apache/openjpa/persistence/ openjpa-persistence/src/main/java/org/apache/openjpa/persistence/...

Author: ppoddar
Date: Wed Jul 29 19:07:56 2009
New Revision: 799018

URL: http://svn.apache.org/viewvc?rev=799018&view=rev
Log:
OPENJPA-1198: Query by example.

Added:
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestQueryByExample.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompareByExample.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ComparisonStyle.java   (with props)
Modified:
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManager.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManagerFactory.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AbstractManagedType.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/Members.java

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestQueryByExample.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestQueryByExample.java?rev=799018&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestQueryByExample.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestQueryByExample.java Wed Jul 29 19:07:56 2009
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.persistence.criteria;
+
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.metamodel.Attribute;
+
+/**
+ * Tests different styles for query by example.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
+public class TestQueryByExample extends CriteriaTest {
+    
+    public void testBasicFieldsWithNonDefaultValue() {
+        String jpql = "SELECT e FROM Employee e WHERE e.rating=1 AND e.salary=1100";
+        
+        CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
+        
+        Employee example = new Employee();
+        example.setSalary(1000+100);
+        example.setRating(1);
+        
+        ComparisonStyle style = null;
+        Attribute<?,?>[] excludes = null;
+        q.where(cb.example(q.from(Employee.class), example, style, excludes));
+        
+        assertEquivalence(q, jpql);
+    }
+    
+    public void testExcludeBasicFieldWithNonDefaultValue() {
+        String jpql = "SELECT e FROM Employee e WHERE e.salary=1100";
+        
+        CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
+        
+        Employee example = new Employee();
+        example.setSalary(1000+100);
+        example.setRating(1);
+        
+        ComparisonStyle style = null;
+        Attribute<?,?>[] excludes = {Employee_.rating};
+        q.where(cb.example(q.from(Employee.class), example, style, excludes));
+        
+        assertEquivalence(q, jpql);
+    }
+    
+    public void testBasicFieldWithDefaultValueExcludedByDefaultStyle() {
+        String jpql = "SELECT e FROM Employee e WHERE e.rating=1";
+        
+        CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
+        
+        Employee example = new Employee();
+        example.setRating(1);
+        
+        ComparisonStyle style = null;
+        Attribute<?,?>[] excludes = null;
+        q.where(cb.example(q.from(Employee.class), example, style, excludes));
+        
+        executeAndCompareSQL(q, "WHERE (t0.rating = ?)");        
+        assertEquivalence(q, jpql);
+    }
+    
+    public void testBasicFieldWithDefaultValueCanBeIncludedByStyle() {
+        String jpql = "SELECT e FROM Employee e WHERE e.rating=1 AND e.salary=1100";
+        
+        CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
+        
+        Employee example = new Employee();
+        example.setRating(1);
+        
+        ComparisonStyle style = cb.comparisonStyle();
+        Attribute<?,?>[] excludes = null;
+        q.where(cb.example(q.from(Employee.class), example, style.setExcludeDefault(false), excludes));
+        
+        executeAndCompareSQL(q, "WHERE (t0.rating = ? AND t0.salary = ?)");
+        assertEquivalence(q, jpql);
+    }
+    
+    public void testRelationFieldWithNonDefaultValue() {
+        String jpql = "SELECT e FROM Employee e WHERE e.rating=1 AND e.salary=1100 AND e.department.name='ExampleDept'";
+        
+        CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
+        
+        Employee example = new Employee();
+        example.setSalary(1100);
+        example.setRating(1);
+        Department dept = new Department();
+        dept.setName("ExampleDept");
+        example.setDepartment(dept);
+        
+        
+        ComparisonStyle style = cb.comparisonStyle();
+        Attribute<?,?>[] excludes = null;
+        q.where(cb.example(q.from(Employee.class), example, style, excludes));
+        
+        executeAndCompareSQL(q, "WHERE (t1.name = ? AND t0.rating = ? AND t0.salary = ?)");
+    }
+    
+    public void testRelationFieldWithNullValueIncluded() {
+        String jpql = "SELECT e FROM Employee e WHERE e.rating=1 AND e.salary=1100 AND e.department IS NULL";
+
+        CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
+        
+        Employee example = new Employee();
+        example.setName("ExampleEmployee");
+        example.setSalary(1100);
+        example.setRating(1);
+        example.setDepartment(null);
+        
+        ComparisonStyle style = cb.comparisonStyle();
+        Attribute<?,?>[] excludes = {Employee_.frequentFlierPlan, Employee_.manager, Employee_.spouse};
+        q.where(cb.example(q.from(Employee.class), example, style.setExcludeNull(false).setExcludeDefault(false), 
+                excludes));
+        
+        executeAndCompareSQL(q, "WHERE (1 <> 1 AND t0.DEPARTMENT_DEPTNO IS NULL " 
+                + "AND t0.name = ? AND t0.rating = ? AND t0.salary = ?)");
+    }
+    
+    public void testEmbeddedField() {
+        String jpql = "SELECT e FROM Employee e WHERE e.rating=1 AND e.salary=1100 AND e.department IS NULL";
+
+        CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
+        
+        Employee example = new Employee();
+        example.setName("ExampleEmployee");
+        example.setSalary(1100);
+        example.setRating(1);
+        Contact contact = new Contact();
+        Address address = new Address();
+        address.setCity("Plano");
+        address.setState("TX");
+        address.setCountry("USA");
+        contact.setAddress(address);
+        example.setContactInfo(contact);
+        
+        ComparisonStyle style = cb.comparisonStyle();
+        Attribute<?,?>[] excludes = {Employee_.department, Employee_.frequentFlierPlan, 
+                Employee_.manager, Employee_.spouse};
+        q.where(cb.example(q.from(Employee.class), example, style, excludes));
+        
+        executeAndCompareSQL(q, "WHERE (t1.city = ? AND t1.country = ? AND t1.state = ? " 
+                + "AND t0.name = ? AND t0.rating = ? AND t0.salary = ?)");
+    }
+    
+    void executeAndCompareSQL(CriteriaQuery<?> q, String expected) {
+        auditor.clear();
+        em.createQuery(q).getResultList();
+        assertEquals(1,auditor.getSQLs().size());
+        String actual = extract("WHERE", auditor.getSQLs().get(0));
+        assertEquals(expected, actual);
+    }
+    
+    String extract(String key, String s) {
+        int index = s.indexOf(key);
+        return index == -1 ? "" : s.substring(index);
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestQueryByExample.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java?rev=799018&r1=799017&r2=799018&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java Wed Jul 29 19:07:56 2009
@@ -364,7 +364,7 @@
         return getStoreCache();
     }
 
-    public QueryBuilder getQueryBuilder() {
+    public CriteriaBuilder getQueryBuilder() {
         return new CriteriaBuilder().setMetaModel(getMetamodel());
     }
     

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java?rev=799018&r1=799017&r2=799018&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java Wed Jul 29 19:07:56 2009
@@ -1566,7 +1566,7 @@
         return finalMap;
     }
 
-    public QueryBuilder getQueryBuilder() {
+    public CriteriaBuilder getQueryBuilder() {
         return _emf.getQueryBuilder();
     }
 

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManager.java?rev=799018&r1=799017&r2=799018&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManager.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManager.java Wed Jul 29 19:07:56 2009
@@ -31,6 +31,7 @@
 import org.apache.openjpa.kernel.ConnectionRetainModes;
 import org.apache.openjpa.kernel.DetachState;
 import org.apache.openjpa.kernel.RestoreState;
+import org.apache.openjpa.persistence.criteria.CriteriaBuilder;
 import org.apache.openjpa.persistence.query.QueryDefinition;
 
 /**
@@ -1141,4 +1142,12 @@
      * instead: <code>em.getTransaction().getRollbackOnly()</code>
      */
     public boolean getRollbackOnly();
+    
+    /**
+     * Gets the QueryBuilder with OpenJPA-extended capabilities. 
+     * 
+     * @since 2.0.0
+     */
+    public CriteriaBuilder getQueryBuilder();
+
 }

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManagerFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManagerFactory.java?rev=799018&r1=799017&r2=799018&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManagerFactory.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/OpenJPAEntityManagerFactory.java Wed Jul 29 19:07:56 2009
@@ -23,6 +23,7 @@
 
 import javax.persistence.EntityManagerFactory;
 
+import org.apache.openjpa.persistence.criteria.CriteriaBuilder;
 import org.apache.openjpa.persistence.query.QueryBuilder;
 
 /**
@@ -130,4 +131,11 @@
      * Gets a builder for dynamic queries.
      */
     public QueryBuilder getDynamicQueryBuilder();
+    
+    /**
+     * Gets the QueryBuilder with OpenJPA-extended capabilities. 
+     * 
+     * @since 2.0.0
+     */
+    public CriteriaBuilder getQueryBuilder();
 }

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompareByExample.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompareByExample.java?rev=799018&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompareByExample.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompareByExample.java Wed Jul 29 19:07:56 2009
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.persistence.criteria;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.Path;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.ManagedType;
+import javax.persistence.metamodel.SingularAttribute;
+
+import org.apache.openjpa.enhance.Reflection;
+
+/**
+ * An expression for query-by-example.
+ * 
+ * @author Pinaki Poddar
+ * 
+ */
+class CompareByExample<T> extends PredicateImpl {
+
+    CompareByExample(CriteriaBuilder builder, ManagedType<T> type, 
+            Path<T> from, T instance, ComparisonStyle style,
+            Attribute<?, ?>... excludes) {
+        super(extractOperator(style));
+        List<Attribute<?, ?>> excludeAttr = excludes == null 
+            ? new ArrayList<Attribute<?,?>>() : Arrays.asList(excludes);
+        
+        Set<SingularAttribute<? super T, ?>> attrs = type.getSingularAttributes();
+        for (SingularAttribute<? super T, ?> attr : attrs) {
+            if (excludeAttr.contains(attr) 
+            || (style.excludeIdentity() && attr.isId()) 
+            || (style.excludeVersion() && attr.isVersion())) {
+                continue;
+            }
+
+            Object value = extractValue(instance, attr);
+            if ((style.excludeNull() && value == null)
+             || (style.excludeDefault() && isDefaultValue(attr.getJavaType(), value)))
+                continue;
+
+            Predicate p = null;
+            if (value == null) {
+                p = from.get(attr).isNull();
+                this.add(p);
+                continue;
+            }
+            if (attr.isAssociation()) {
+                p = new CompareByExample(builder, (ManagedType<?>)attr.getType(), 
+                        from.get(attr), value, style, excludes);
+            } else if (attr.getJavaType() == String.class) {
+                Expression<String> s = from.get(attr).as(String.class);
+                switch (style.getStringComparsionMode()) {
+                    case EXACT : p = builder.equal(s, value);
+                    break;
+                    case CASE_INSENSITIVE : p = builder.equal(builder.upper(s), value.toString());
+                    break;
+                    case LIKE: p = builder.like(s, value.toString());
+                    break;
+                }
+            } else {
+                p = builder.equal(from.get(attr), value);
+            }
+            this.add(p);
+        }
+    }
+    
+    Object extractValue(T instance, SingularAttribute<? super T, ?> attr) {
+        Class<?> cls = instance.getClass();
+        Method getter = Reflection.findGetter(cls, attr.getName(), false);
+        if (getter != null)
+            return Reflection.get(instance, getter);
+        Field field = Reflection.findField(cls, attr.getName(), false);
+        if (field != null)
+            return Reflection.get(instance, field);
+        return null;
+    }
+    
+    boolean isDefaultValue(Class<?> cls, Object val) {
+        if (val == null) {
+            return true;
+        }
+        if (cls == Boolean.class || cls == boolean.class) {
+           return Boolean.FALSE.equals(val);
+        } else if (cls == Character.class || cls == char.class) {
+            return ((Character) val).charValue() == 0;
+        } else if (cls == Byte.class || cls == byte.class
+                || cls == Double.class || cls == double.class
+                || cls == Float.class || cls == float.class
+                || cls == Long.class || cls == long.class
+                || cls == Integer.class || cls == int.class
+                || cls == Short.class || cls == short.class) {
+                   return ((Number) val).intValue() == 0;
+        } else if (cls == String.class) {
+            return "".equals(val);
+        } else {
+            return false;
+        }
+    }
+    
+    static <T> BooleanOperator extractOperator(ComparisonStyle style) {
+        return style == null ? BooleanOperator.AND : style.isDisjunction() ? BooleanOperator.OR : BooleanOperator.AND;
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompareByExample.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ComparisonStyle.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ComparisonStyle.java?rev=799018&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ComparisonStyle.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ComparisonStyle.java Wed Jul 29 19:07:56 2009
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.persistence.criteria;
+
+
+/**
+ * Defines a comparison style to be applied for query-by-example attribute comparison.
+ * 
+ * @author Pinaki Poddar
+ * 
+ * @since 2.0.0
+ *
+ */
+public interface ComparisonStyle {
+    public static enum StringComparisonMode {
+        EXACT,            // compares exactly preserving case
+        CASE_INSENSITIVE, // compares ignoring case
+        LIKE              // compares with LIKE() operator
+    }
+    
+    /**
+     * Affirms if the attribute comparisons are OR'ed.
+     * Defaults to false.
+     */
+    boolean isDisjunction();
+    
+    /**
+     * Sets whether the comparison to OR the attribute comparisons.
+     */
+    ComparisonStyle setDisjunction(boolean flag);
+    
+    /**
+     * Affirms if the null-valued attribute be excluded from comparison.
+     * Defaults to true.
+     */
+    boolean excludeNull();
+    
+    /**
+     * Sets whether the comparison excludes null-valued attributes.
+     */
+    ComparisonStyle setExcludeNull(boolean flag);
+    
+    /**
+     * Affirms if the identity attribute be excluded from comparison.
+     * Defaults to true.
+     */
+    boolean excludeIdentity();
+    
+    /**
+     * Sets whether the comparison excludes identity attribute.
+     */
+    ComparisonStyle setExcludeIdentity(boolean flag);
+    
+    /**
+     * Affirms if the version attribute be excluded from comparison.
+     * Defaults to true.
+     */
+    boolean excludeVersion();
+    
+    /**
+     * Sets whether the comparison excludes version attribute.
+     */
+    ComparisonStyle setExcludeVersion(boolean flag);
+    
+    /**
+     * Affirms if the default-valued attribute be excluded from comparison.
+     * Defaults to true.
+     */
+    
+    boolean excludeDefault();
+
+    /**
+     * Sets whether the comparison excludes default-valued attributes.
+     */
+    ComparisonStyle setExcludeDefault(boolean flag);
+    
+    /**
+     * Gets how string-valued attributes be compared.
+     */
+    StringComparisonMode getStringComparsionMode();
+
+    /**
+     * Sets the comparison mode for String-valued attributes.
+     */
+    ComparisonStyle setStringComparisonMode(StringComparisonMode mode);
+
+    /**
+     * Default implementation.
+     * 
+     */
+    static class Default implements ComparisonStyle {
+        private boolean excludeDefault = true;
+        private boolean excludeNull = true;
+        private boolean excludeIdentity = true;
+        private boolean excludeVersion = true;
+        private boolean disjunction = false;
+        private StringComparisonMode stringMode = StringComparisonMode.EXACT;
+        
+        public boolean excludeDefault() {
+            return excludeDefault;
+        }
+
+        public boolean excludeNull() {
+            return excludeNull;
+        }
+
+        public StringComparisonMode getStringComparsionMode() {
+            return stringMode;
+        }
+
+        public boolean isDisjunction() {
+            return disjunction;
+        }
+        
+        public ComparisonStyle setExcludeDefault(boolean flag) {
+            excludeDefault = flag;
+            return this;
+        }
+        
+        public ComparisonStyle setExcludeNull(boolean flag) {
+            excludeNull = flag;
+            return this;
+        }
+        
+        public ComparisonStyle setStringComparisonMode(StringComparisonMode mode) {
+            stringMode = mode;
+            return this;
+        }
+        
+        public ComparisonStyle setDisjunction(boolean flag) {
+            disjunction = flag;
+            return this;
+        }
+        
+        public boolean excludeIdentity() {
+            return excludeIdentity;
+            
+        }
+        
+        public ComparisonStyle setExcludeIdentity(boolean flag) {
+            excludeIdentity = flag;
+            return this;
+        }
+        
+        public boolean excludeVersion() {
+            return excludeVersion;
+            
+        }
+        
+        public ComparisonStyle setExcludeVersion(boolean flag) {
+            excludeVersion = flag;
+            return this;
+        }
+    }
+}
+
+

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ComparisonStyle.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java?rev=799018&r1=799017&r2=799018&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java Wed Jul 29 19:07:56 2009
@@ -31,12 +31,15 @@
 import javax.persistence.criteria.CompoundSelection;
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.From;
 import javax.persistence.criteria.Order;
 import javax.persistence.criteria.ParameterExpression;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.QueryBuilder;
 import javax.persistence.criteria.Selection;
 import javax.persistence.criteria.Subquery;
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.ManagedType;
 
 import org.apache.openjpa.kernel.ExpressionStoreQuery;
 import org.apache.openjpa.kernel.exps.ExpressionFactory;
@@ -688,4 +691,45 @@
     public CompoundSelection<Tuple> tuple(Selection<?>... selections) {
         return new TupleSelection<Tuple>(Tuple.class, selections);
     }
+    
+    /**
+     * Create a predicate based upon the attribute values of a given
+     * "example" entity instance. The predicate is the conjunction 
+     * or disjunction of predicates for subset of attribute of the entity.
+     * <br>
+     * By default, all the singular entity attributes (the basic, embedded
+     * and uni-cardinality relations) that have a non-null or non-default
+     * value for the example instance and are not an identity or version
+     * attribute are included. The comparable attributes can be further
+     * pruned by specifying variable list of attributes as the final argument.
+     * 
+     * @param example an instance of an entity class
+     * 
+     * @param style specifies various aspects of comparison such as whether
+     * non-null attribute values be included, how string-valued attribute be 
+     * compared, whether the individual attribute based predicates are ANDed
+     * or ORed etc.
+     * 
+     * @param excludes list of attributes that are excluded from comparison.
+     *  
+     * @return a predicate 
+     */
+    public <T> Predicate example(From<?, T> from, T example, ComparisonStyle style, Attribute<?,?>... excludes) {
+        if (from == null)
+            throw new NullPointerException();
+        if (example == null) {
+            return from.isNull();
+            
+        }
+        ManagedType<T> type = (ManagedType<T>)_model.type(example.getClass());
+        return new CompareByExample<T>(this, type, from, example, 
+            style == null ? comparisonStyle() : style, excludes);
+    }
+    
+    /**
+     * Create a style to tune different aspects of comparison by example. 
+     */
+    public ComparisonStyle comparisonStyle() {
+        return new ComparisonStyle.Default();
+    }
 }

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java?rev=799018&r1=799017&r2=799018&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/ExpressionImpl.java Wed Jul 29 19:07:56 2009
@@ -62,7 +62,7 @@
      * @return expression
      */
     public <Y> Expression<Y> as(Class<Y> type) {
-       return new Expressions.CastAs<Y>(type, this);
+       return type == getJavaType() ? (Expression<Y>)this : new Expressions.CastAs<Y>(type, this);
     }
 
     /**

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java?rev=799018&r1=799017&r2=799018&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java Wed Jul 29 19:07:56 2009
@@ -19,17 +19,25 @@
 
 package org.apache.openjpa.persistence.criteria;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.From;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.QueryBuilder;
 import javax.persistence.criteria.Selection;
 import javax.persistence.criteria.Subquery;
 import javax.persistence.criteria.QueryBuilder.Trimspec;
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.ManagedType;
+import javax.persistence.metamodel.SingularAttribute;
 
+import org.apache.openjpa.enhance.Reflection;
 import org.apache.openjpa.kernel.exps.ExpressionFactory;
 import org.apache.openjpa.kernel.exps.Literal;
 import org.apache.openjpa.kernel.exps.Value;

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AbstractManagedType.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AbstractManagedType.java?rev=799018&r1=799017&r2=799018&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AbstractManagedType.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/AbstractManagedType.java Wed Jul 29 19:07:56 2009
@@ -27,6 +27,7 @@
 import java.util.Date;
 import java.util.HashSet;
 import java.util.Locale;
+import java.util.TreeSet;
 
 import javax.persistence.metamodel.Attribute;
 import javax.persistence.metamodel.CollectionAttribute;
@@ -186,7 +187,7 @@
      * 
      */
     public java.util.Set<Attribute<X, ?>> getDeclaredAttributes() {
-        return filter(attrs, new HashSet<Attribute<X, ?>>(),
+        return filter(attrs, new TreeSet<Attribute<X, ?>>(),
                 declaredAttributeFilter);
     }
 
@@ -195,7 +196,7 @@
      * 
      */
     public java.util.Set<SingularAttribute<? super X, ?>> getSingularAttributes() {
-        return filter(attrs, new HashSet<SingularAttribute<? super X, ?>>(),
+        return filter(attrs, new TreeSet<SingularAttribute<? super X, ?>>(),
                 singularAttributeFilter);
     }
 
@@ -204,7 +205,7 @@
      * 
      */
     public java.util.Set<SingularAttribute<X, ?>> getDeclaredSingularAttributes() {
-        return filter(attrs, new HashSet<SingularAttribute<X, ?>>(),
+        return filter(attrs, new TreeSet<SingularAttribute<X, ?>>(),
                 declaredAttributeFilter, 
                 singularAttributeFilter);
     }

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/Members.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/Members.java?rev=799018&r1=799017&r2=799018&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/Members.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/meta/Members.java Wed Jul 29 19:07:56 2009
@@ -52,7 +52,7 @@
      * @param <X> The type that contains this attribute
      * @param <Y> The type of this attribute
 	 */
-    public static abstract class Member<X, Y> implements Attribute<X, Y> {
+    public static abstract class Member<X, Y> implements Attribute<X, Y>, Comparable<Member<X,Y>> {
         public final AbstractManagedType<X> owner;
         public final FieldMetaData fmd;
 
@@ -130,6 +130,10 @@
                 return PersistentAttributeType.ELEMENT_COLLECTION;
             return PersistentAttributeType.BASIC;
         }
+
+        public int compareTo(Member<X, Y> o) {
+            return fmd.getName().compareTo(o.fmd.getName());
+        }
     }