You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2012/12/27 14:38:58 UTC

svn commit: r1426199 - in /cxf/branches/2.6.x-fixes: ./ rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/ rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/ rt/rs/extensions/search/src/main/java/org/...

Author: sergeyb
Date: Thu Dec 27 13:38:58 2012
New Revision: 1426199

URL: http://svn.apache.org/viewvc?rev=1426199&view=rev
Log:
Merged revisions 1426184 via svnmerge from 
https://svn.apache.org/repos/asf/cxf/trunk

........
  r1426184 | sergeyb | 2012-12-27 12:55:03 +0000 (Thu, 27 Dec 2012) | 1 line
  
  Updating FIQL parser to recognize collection checks, starting from count
........

Added:
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/
      - copied from r1426184, cxf/trunk/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/CollectionCheck.java
      - copied unchanged from r1426184, cxf/trunk/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/CollectionCheck.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/CollectionCheckCondition.java
      - copied unchanged from r1426184, cxf/trunk/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/CollectionCheckCondition.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/CollectionCheckInfo.java
      - copied unchanged from r1426184, cxf/trunk/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/CollectionCheckInfo.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/CollectionCheckStatement.java
      - copied unchanged from r1426184, cxf/trunk/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/collections/CollectionCheckStatement.java
Modified:
    cxf/branches/2.6.x-fixes/   (props changed)
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/Beanspector.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/PrimitiveSearchCondition.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/SimpleSearchCondition.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/fiql/FiqlParser.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/AbstractJPATypedQueryVisitor.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/visitor/AbstractSearchConditionVisitor.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/JPATypedQueryVisitorTest.java

Propchange: cxf/branches/2.6.x-fixes/
------------------------------------------------------------------------------
  Merged /cxf/trunk:r1426184

Propchange: cxf/branches/2.6.x-fixes/
------------------------------------------------------------------------------
Binary property 'svnmerge-integrated' - no diff available.

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/Beanspector.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/Beanspector.java?rev=1426199&r1=1426198&r2=1426199&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/Beanspector.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/Beanspector.java Thu Dec 27 13:38:58 2012
@@ -28,6 +28,8 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.cxf.jaxrs.ext.search.collections.CollectionCheckInfo;
+
 /**
  * Bean introspection utility.
  */
@@ -194,6 +196,7 @@ public class Beanspector<T> {
     public static class TypeInfo {
         private Class<?> cls;
         private Type genericType;
+        private CollectionCheckInfo checkInfo;
         
         public TypeInfo(Class<?> cls, Type genericType) {
             this.cls = cls;
@@ -207,5 +210,13 @@ public class Beanspector<T> {
         public Type getGenericType() {
             return genericType;
         }
+
+        public CollectionCheckInfo getCollectionCheckInfo() {
+            return checkInfo;
+        }
+
+        public void setCollectionCheckInfo(CollectionCheckInfo info) {
+            this.checkInfo = info;
+        }
     }
 }

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/PrimitiveSearchCondition.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/PrimitiveSearchCondition.java?rev=1426199&r1=1426198&r2=1426199&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/PrimitiveSearchCondition.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/PrimitiveSearchCondition.java Thu Dec 27 13:38:58 2012
@@ -76,6 +76,18 @@ public class PrimitiveSearchCondition<T>
         return cType;
     }
 
+    protected String getPropertyName() {
+        return propertyName;
+    }
+    
+    protected Object getPropertyValue() {
+        return propertyValue;
+    }
+    
+    protected Type getPropertyType() {
+        return propertyType;
+    }
+    
     public List<SearchCondition<T>> getSearchConditions() {
         return null;
     }

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/SimpleSearchCondition.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/SimpleSearchCondition.java?rev=1426199&r1=1426198&r2=1426199&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/SimpleSearchCondition.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/SimpleSearchCondition.java Thu Dec 27 13:38:58 2012
@@ -29,6 +29,8 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.cxf.jaxrs.ext.search.Beanspector.TypeInfo;
+import org.apache.cxf.jaxrs.ext.search.collections.CollectionCheckCondition;
+import org.apache.cxf.jaxrs.ext.search.collections.CollectionCheckInfo;
 
 /**
  * Simple search condition comparing primitive objects or complex object by its getters. For details see
@@ -163,11 +165,16 @@ public class SimpleSearchCondition<T> im
                 }
                 String realGetter = realGetters != null && realGetters.containsKey(getter) 
                     ? realGetters.get(getter) : getter;
-                    
-                Type genType = propertyTypeInfo != null && propertyTypeInfo.containsKey(getter)
-                    ? propertyTypeInfo.get(getter).getGenericType() : rval.getClass();
                 
-                list.add(new PrimitiveSearchCondition<T>(realGetter, rval, genType, ct, condition));
+                TypeInfo tInfo = propertyTypeInfo != null ? propertyTypeInfo.get(getter) : null;
+                Type genType = tInfo != null ? tInfo.getGenericType() : rval.getClass();
+                CollectionCheckInfo checkInfo = tInfo != null ? tInfo.getCollectionCheckInfo() : null;
+                
+                PrimitiveSearchCondition<T> pc = checkInfo == null 
+                    ? new PrimitiveSearchCondition<T>(realGetter, rval, genType, ct, condition)
+                    : new CollectionCheckCondition<T>(realGetter, rval, genType, ct, condition, checkInfo);    
+                
+                list.add(pc);
                 
             }
             if (list.isEmpty()) {

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/fiql/FiqlParser.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/fiql/FiqlParser.java?rev=1426199&r1=1426198&r2=1426199&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/fiql/FiqlParser.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/fiql/FiqlParser.java Thu Dec 27 13:38:58 2012
@@ -45,6 +45,8 @@ import org.apache.cxf.jaxrs.ext.search.S
 import org.apache.cxf.jaxrs.ext.search.SearchParseException;
 import org.apache.cxf.jaxrs.ext.search.SearchUtils;
 import org.apache.cxf.jaxrs.ext.search.SimpleSearchCondition;
+import org.apache.cxf.jaxrs.ext.search.collections.CollectionCheck;
+import org.apache.cxf.jaxrs.ext.search.collections.CollectionCheckInfo;
 import org.apache.cxf.jaxrs.utils.InjectionUtils;
 import org.apache.cxf.message.MessageUtils;
 
@@ -70,6 +72,10 @@ public class FiqlParser<T> implements Se
     public static final String NEQ = "!=";
     
     public static final Map<ConditionType, String> CONDITION_MAP;
+        
+    public static final String EXTENSION_COUNT = "count";
+    
+    private static final String EXTENSION_COUNT_OPEN = EXTENSION_COUNT + "(";
     
     private static final Map<String, ConditionType> OPERATORS_MAP;
     private static final Pattern COMPARATORS_PATTERN; 
@@ -253,19 +259,20 @@ public class FiqlParser<T> implements Se
     private Comparison parseComparison(String expr) throws SearchParseException {
         Matcher m = COMPARATORS_PATTERN.matcher(expr);
         if (m.find()) {
-            String name = expr.substring(0, m.start(1));
+            String propertyName = expr.substring(0, m.start(1));
             String operator = m.group(1);
             String value = expr.substring(m.end(1));
             if ("".equals(value)) {
                 throw new SearchParseException("Not a comparison expression: " + expr);
             }
             
+            String name = unwrapSetter(propertyName);
             String beanPropertyName = beanPropertiesMap == null ? null : beanPropertiesMap.get(name);
             if (beanPropertyName != null) {
                 name = beanPropertyName;
             }
             
-            TypeInfoObject castedValue = parseType(name, value);
+            TypeInfoObject castedValue = parseType(propertyName, name, value);
             if (castedValue != null) {
                 return new Comparison(name, operator, castedValue);
             } else if (MessageUtils.isTrue(contextProperties.get(SearchUtils.LAX_PROPERTY_MATCH))) {
@@ -279,14 +286,14 @@ public class FiqlParser<T> implements Se
     }
 
     
-    private TypeInfoObject parseType(String setter, String value) throws SearchParseException {
+    private TypeInfoObject parseType(String originalName, String setter, String value) throws SearchParseException {
         String name = getSetter(setter);
         
         try {
             TypeInfo typeInfo = 
                 beanspector != null ? beanspector.getAccessorTypeInfo(name) 
                     : new TypeInfo(String.class, String.class);
-            Object object = parseType(null, null, setter, typeInfo, value);
+            Object object = parseType(originalName, null, null, setter, typeInfo, value);
             return new TypeInfoObject(object, typeInfo);
         } catch (Exception e) {
             return null;
@@ -294,8 +301,12 @@ public class FiqlParser<T> implements Se
         
     }
 
-    private Object parseType(Object ownerBean, Object lastCastedValue, String setter, 
-                             TypeInfo typeInfo, String value) throws SearchParseException {
+    private Object parseType(String originalPropName, 
+                             Object ownerBean, 
+                             Object lastCastedValue, 
+                             String setter, 
+                             TypeInfo typeInfo, 
+                             String value) throws SearchParseException {
         Class<?> valueType = typeInfo.getTypeClass();
         boolean isCollection = InjectionUtils.isSupportedCollectionOrArray(valueType);
         Class<?> actualType = isCollection ? InjectionUtils.getActualType(typeInfo.getGenericType()) : valueType;
@@ -306,11 +317,19 @@ public class FiqlParser<T> implements Se
             if (Date.class.isAssignableFrom(valueType)) {
                 castedValue = convertToDate(value);
             } else {
-                if (ownerBean == null || InjectionUtils.isPrimitive(valueType) || valueType.isEnum()) {
+                boolean isPrimitive = InjectionUtils.isPrimitive(valueType);
+                boolean isPrimitiveOrEnum = isPrimitive || valueType.isEnum();
+                if (ownerBean == null || isPrimitiveOrEnum) {
                     try {
-                        castedValue = InjectionUtils.convertStringToPrimitive(value, actualType);
-                        if (isCollection) {
+                        CollectionCheck collCheck = getCollectionCheck(originalPropName, isCollection, actualType);
+                        if (collCheck == null) {
+                            castedValue = InjectionUtils.convertStringToPrimitive(value, actualType);
+                        } 
+                        if (collCheck == null && isCollection) {
                             castedValue = getCollectionSingleton(valueType, castedValue);
+                        } else if (isCollection) {
+                            typeInfo.setCollectionCheckInfo(new CollectionCheckInfo(collCheck, castedValue));
+                            castedValue = getEmptyCollection(valueType);
                         }
                     } catch (Exception e) {
                         throw new SearchParseException("Cannot convert String value \"" + value
@@ -342,6 +361,8 @@ public class FiqlParser<T> implements Se
                 Method getterM = actualType.getMethod("get" + nextPart, new Class[]{});   
                 Class<?> returnType = getterM.getReturnType();
                 boolean returnCollection = InjectionUtils.isSupportedCollectionOrArray(returnType);
+                Class<?> actualReturnType = !returnCollection ? returnType 
+                    : InjectionUtils.getActualType(getterM.getGenericReturnType());
                 
                 boolean isPrimitive = InjectionUtils.isPrimitive(returnType) || returnType.isEnum();
                 boolean lastTry = names.length == 2 
@@ -355,7 +376,13 @@ public class FiqlParser<T> implements Se
                         nextObject = isPrimitive ? InjectionUtils.convertStringToPrimitive(value, returnType) 
                             : convertToDate(value);
                     } else {
-                        nextObject = getCollectionSingleton(valueType, value);
+                        CollectionCheck collCheck = getCollectionCheck(originalPropName, true, actualReturnType);
+                        if (collCheck == null) {
+                            nextObject = getCollectionSingleton(valueType, value);
+                        } else {
+                            typeInfo.setCollectionCheckInfo(new CollectionCheckInfo(collCheck, value));
+                            nextObject = getEmptyCollection(valueType);
+                        }
                     }
                 } else {
                     nextObject = returnType.newInstance();
@@ -370,8 +397,12 @@ public class FiqlParser<T> implements Se
                 } 
                 
                 TypeInfo nextTypeInfo = new TypeInfo(nextObject.getClass(), getterM.getGenericReturnType()); 
-                return parseType(nextObject, lastCastedValue, setter.substring(index + 1), 
-                                 nextTypeInfo, value);
+                return parseType(originalPropName,
+                                 nextObject, 
+                                 lastCastedValue, 
+                                 setter.substring(index + 1), 
+                                 nextTypeInfo, 
+                                 value);
             } catch (Throwable e) {
                 throw new SearchParseException("Cannot convert String value \"" + value
                                                + "\" to a value of class " + valueType.getName(), e);
@@ -379,6 +410,19 @@ public class FiqlParser<T> implements Se
         }
     }
     
+    private CollectionCheck getCollectionCheck(String propName, boolean isCollection, Class<?> actualCls) {
+        if (isCollection) {
+            if (InjectionUtils.isPrimitive(actualCls)) {
+                if (propName.startsWith(EXTENSION_COUNT_OPEN)) {
+                    return CollectionCheck.SIZE;
+                }
+            } else {
+                return CollectionCheck.SIZE;
+            }
+        }
+        return null;
+    }
+    
     private Object getCollectionSingleton(Class<?> collectionCls, Object value) {
         if (Set.class.isAssignableFrom(collectionCls)) {
             return Collections.singleton(value);
@@ -387,6 +431,14 @@ public class FiqlParser<T> implements Se
         }
     }
     
+    private Object getEmptyCollection(Class<?> collectionCls) {
+        if (Set.class.isAssignableFrom(collectionCls)) {
+            return Collections.emptySet();
+        } else {
+            return Collections.emptyList();
+        }
+    }
+    
     private Object convertToDate(String value) throws SearchParseException {
         try {
             DateFormat df = SearchUtils.getDateFormat(contextProperties);
@@ -422,6 +474,14 @@ public class FiqlParser<T> implements Se
         }
     }
     
+    private String unwrapSetter(String setter) {
+        if (setter.startsWith(EXTENSION_COUNT_OPEN) && setter.endsWith(")")) {
+            return setter.substring(EXTENSION_COUNT_OPEN.length(), setter.length() - 1);        
+        } else {
+            return setter;
+        }
+    }
+    
     private String getMethodNameSuffix(String name) {
         if (name.length() == 1) {
             return name.toUpperCase();

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/AbstractJPATypedQueryVisitor.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/AbstractJPATypedQueryVisitor.java?rev=1426199&r1=1426198&r2=1426199&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/AbstractJPATypedQueryVisitor.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/AbstractJPATypedQueryVisitor.java Thu Dec 27 13:38:58 2012
@@ -18,8 +18,8 @@
  */
 package org.apache.cxf.jaxrs.ext.search.jpa;
 
-import java.lang.reflect.Type;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -30,6 +30,7 @@ import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Expression;
 import javax.persistence.criteria.Join;
 import javax.persistence.criteria.Path;
 import javax.persistence.criteria.Predicate;
@@ -39,6 +40,7 @@ import org.apache.cxf.jaxrs.ext.search.C
 import org.apache.cxf.jaxrs.ext.search.OrSearchCondition;
 import org.apache.cxf.jaxrs.ext.search.PrimitiveStatement;
 import org.apache.cxf.jaxrs.ext.search.SearchCondition;
+import org.apache.cxf.jaxrs.ext.search.collections.CollectionCheckInfo;
 import org.apache.cxf.jaxrs.ext.search.visitor.AbstractSearchConditionVisitor;
 
 public abstract class AbstractJPATypedQueryVisitor<T, T1, E> 
@@ -116,14 +118,8 @@ public abstract class AbstractJPATypedQu
             root = cq.from(tClass);
             predStack.push(new ArrayList<Predicate>());
         }
-        PrimitiveStatement statement = sc.getStatement();
-        if (statement != null) {
-            if (statement.getProperty() != null) {
-                predStack.peek().add(buildPredicate(sc.getConditionType(), 
-                                                    statement.getProperty(), 
-                                                    statement.getValue(),
-                                                    statement.getValueType()));
-            }
+        if (sc.getStatement() != null) {
+            predStack.peek().add(buildPredicate(sc.getStatement()));
         } else {
             predStack.push(new ArrayList<Predicate>());
             for (SearchCondition<T> condition : sc.getSearchConditions()) {
@@ -166,21 +162,34 @@ public abstract class AbstractJPATypedQu
         return cq;
     }
     
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private Predicate buildPredicate(ConditionType ct, String name, Object value, Type valueType) {
-
+    private Predicate buildPredicate(PrimitiveStatement ps) {
+        String name = ps.getProperty();
         name = super.getRealPropertyName(name);
-        ClassValue cv = getPrimitiveFieldClass(name, value.getClass(), valueType, value); 
+        ClassValue cv = getPrimitiveFieldClass(ps,
+                                               name, 
+                                               ps.getValue().getClass(), 
+                                               ps.getValueType(), 
+                                               ps.getValue()); 
+        CollectionCheckInfo collInfo = cv.getCollectionCheckInfo();
+        Path<?> path = getPath(root, name, cv, collInfo);
         
-        Class<? extends Comparable> clazz = (Class<? extends Comparable>)cv.getCls();
-        value = cv.getValue();    
+        Predicate pred = collInfo == null 
+            ? doBuildPredicate(ps.getCondition(), path, cv.getCls(), cv.getValue()) 
+            : doBuildCollectionPredicate(ps.getCondition(), path, collInfo);
         
-        Path<?> path = getPath(root, name, cv);
+        return pred;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private Predicate doBuildPredicate(ConditionType ct, Path<?> path, Class<?> valueClazz, Object value) {
+        
+        Class<? extends Comparable> clazz = (Class<? extends Comparable>)valueClazz;
+        Expression<? extends Comparable> exp = path.as(clazz);
         
         Predicate pred = null;
         switch (ct) {
         case GREATER_THAN:
-            pred = builder.greaterThan(path.as(clazz), clazz.cast(value));
+            pred = builder.greaterThan(exp, clazz.cast(value));
             break;
         case EQUALS:
             if (clazz.equals(String.class)) {
@@ -188,47 +197,77 @@ public abstract class AbstractJPATypedQu
                 if (theValue.contains("*")) {
                     theValue = ((String)value).replaceAll("\\*", "");
                 }
-                pred = builder.like(path.as(String.class), "%" + theValue + "%");
+                pred = builder.like((Expression<String>)exp, "%" + theValue + "%");
             } else {
-                pred = builder.equal(path.as(clazz), clazz.cast(value));
+                pred = builder.equal(exp, clazz.cast(value));
             }
             break;
         case NOT_EQUALS:
-            pred = builder.notEqual(path.as(clazz), 
-                                    clazz.cast(value));
+            pred = builder.notEqual(exp, clazz.cast(value));
             break;
         case LESS_THAN:
-            pred = builder.lessThan(path.as(clazz), 
-                                    clazz.cast(value));
+            pred = builder.lessThan(exp, clazz.cast(value));
             break;
         case LESS_OR_EQUALS:
-            pred = builder.lessThanOrEqualTo(path.as(clazz), 
-                                             clazz.cast(value));
+            pred = builder.lessThanOrEqualTo(exp, clazz.cast(value));
             break;
         case GREATER_OR_EQUALS:
-            pred = builder.greaterThanOrEqualTo(path.as(clazz), 
-                                                clazz.cast(value));
+            pred = builder.greaterThanOrEqualTo(exp, clazz.cast(value));
             break;
         default: 
             break;
         }
         return pred;
     }
-
-    private Path<?> getPath(Path<?> element, String name, ClassValue cv) {
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private Predicate doBuildCollectionPredicate(ConditionType ct, Path<?> path, CollectionCheckInfo collInfo) {
+        Predicate pred = null;
+        
+        Expression<Integer> exp = builder.size((Expression<? extends Collection>)path);
+        Integer value = Integer.valueOf(collInfo.getCollectionCheckValue().toString());
+        
+        switch (ct) {
+        case GREATER_THAN:
+            pred = builder.greaterThan(exp, value);
+            break;
+        case EQUALS:
+            pred = builder.equal(exp, value);
+            break;
+        case NOT_EQUALS:
+            pred = builder.notEqual(exp, value);
+            break;
+        case LESS_THAN:
+            pred = builder.lessThan(exp, value);
+            break;
+        case LESS_OR_EQUALS:
+            pred = builder.lessThanOrEqualTo(exp, value);
+            break;
+        case GREATER_OR_EQUALS:
+            pred = builder.greaterThanOrEqualTo(exp, value);
+            break;
+        default: 
+            break;
+        }
+        return pred;
+    }
+    
+    private Path<?> getPath(Path<?> element, String name, ClassValue cv, CollectionCheckInfo collSize) {
         if (name.contains(".")) {
             String pre = name.substring(0, name.indexOf('.'));
             String post = name.substring(name.indexOf('.') + 1);
-            return getPath(getNextPath(element, pre, cv), 
+            return getPath(getNextPath(element, pre, cv, null), 
                            post, 
-                           cv);
+                           cv,
+                           collSize);
         } else {
-            return getNextPath(element, name, cv);
+            return getNextPath(element, name, cv, collSize);
         }
     }
 
-    private Path<?> getNextPath(Path<?> element, String name, ClassValue cv) {
-        if ((cv.isCollection(name) || isJoinProperty(name)) && (element == root || element instanceof Join)) {
+    private Path<?> getNextPath(Path<?> element, String name, ClassValue cv, CollectionCheckInfo collSize) {
+        if (collSize == null
+            && (cv.isCollection(name) || isJoinProperty(name)) && (element == root || element instanceof Join)) {
             return element == root ? root.join(name) : ((Join<?, ?>)element).join(name);
         } else {
             return element.get(name);

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/visitor/AbstractSearchConditionVisitor.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/visitor/AbstractSearchConditionVisitor.java?rev=1426199&r1=1426198&r2=1426199&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/visitor/AbstractSearchConditionVisitor.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/visitor/AbstractSearchConditionVisitor.java Thu Dec 27 13:38:58 2012
@@ -25,7 +25,10 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.cxf.jaxrs.ext.search.PrimitiveStatement;
 import org.apache.cxf.jaxrs.ext.search.SearchConditionVisitor;
+import org.apache.cxf.jaxrs.ext.search.collections.CollectionCheckInfo;
+import org.apache.cxf.jaxrs.ext.search.collections.CollectionCheckStatement;
 import org.apache.cxf.jaxrs.utils.InjectionUtils;
 
 
@@ -50,23 +53,26 @@ public abstract class AbstractSearchCond
     }    
     
     protected ClassValue getPrimitiveFieldClass(String name, Class<?> valueCls, Object value) {
-        return getPrimitiveFieldClass(name, valueCls, valueCls, value);
+        return getPrimitiveFieldClass(null, name, valueCls, valueCls, value);
     }
     
-    protected ClassValue getPrimitiveFieldClass(String name, Class<?> valueCls, Type type, Object value) {
-        return doGetPrimitiveFieldClass(name, valueCls, type, value, new HashSet<String>());
+    protected ClassValue getPrimitiveFieldClass(PrimitiveStatement ps, String name, Class<?> valueCls, 
+                                                Type type, Object value) {
+        return doGetPrimitiveFieldClass(ps, name, valueCls, type, value, new HashSet<String>());
     }
     
     @SuppressWarnings("rawtypes")
-    private ClassValue doGetPrimitiveFieldClass(String name, Class<?> valueCls, Type type, Object value, 
+    private ClassValue doGetPrimitiveFieldClass(PrimitiveStatement ps,
+                                                String name, Class<?> valueCls, Type type, Object value, 
                                                 Set<String> set) {
         boolean isCollection = InjectionUtils.isSupportedCollectionOrArray(valueCls);
-        
+        Class<?> actualCls = isCollection ? InjectionUtils.getActualType(type) : valueCls;
+        CollectionCheckInfo collInfo = null;
         int index = name.indexOf(".");
         if (index != -1) {
             String[] names = name.split("\\.");
             name = name.substring(index + 1);
-            if (value != null && !InjectionUtils.isPrimitive(valueCls)) {
+            if (value != null && !InjectionUtils.isPrimitive(actualCls)) {
                 try {
                     String nextPart = names[1];
                     if (nextPart.length() == 1) {
@@ -74,8 +80,7 @@ public abstract class AbstractSearchCond
                     } else {
                         nextPart = Character.toUpperCase(nextPart.charAt(0)) + nextPart.substring(1);
                     }
-                    Class<?> actualCls = isCollection 
-                        ? InjectionUtils.getActualType(type) : valueCls;
+                    
                     Method m = actualCls.getMethod("get" + nextPart, new Class[]{});
                     if (isCollection) {
                         value = ((Collection)value).iterator().next();
@@ -87,12 +92,16 @@ public abstract class AbstractSearchCond
                 } catch (Throwable ex) {
                     throw new RuntimeException();
                 }
-                return doGetPrimitiveFieldClass(name, valueCls, type, value, set);
+                return doGetPrimitiveFieldClass(ps, name, valueCls, type, value, set);
             }
         } else if (isCollection) {
             set.add(name);
-            value = ((Collection)value).iterator().next();
-            valueCls = value.getClass();
+            Collection coll = (Collection)value;
+            value = coll.isEmpty() ? null : coll.iterator().next();
+            valueCls = actualCls;
+            if (ps instanceof CollectionCheckStatement) { 
+                collInfo = ((CollectionCheckStatement)ps).getCollectionCheckInfo();
+            }
         }
         
         Class<?> cls = null;
@@ -102,7 +111,7 @@ public abstract class AbstractSearchCond
         if (cls == null) {  
             cls = valueCls;
         }
-        return new ClassValue(cls, value, set);
+        return new ClassValue(cls, value, collInfo, set);
     }
 
     public void setPrimitiveFieldTypeMap(Map<String, Class<?>> primitiveFieldTypeMap) {
@@ -116,10 +125,16 @@ public abstract class AbstractSearchCond
     protected class ClassValue {
         private Class<?> cls;
         private Object value;
+        private CollectionCheckInfo collInfo;
+        
         private Set<String> collectionProps;
-        public ClassValue(Class<?> cls, Object value, Set<String> collectionProps) {
+        public ClassValue(Class<?> cls, 
+                          Object value,
+                          CollectionCheckInfo collInfo,
+                          Set<String> collectionProps) {
             this.cls = cls;
             this.value = value;
+            this.collInfo = collInfo;
             this.collectionProps = collectionProps;       
         }
         public Class<?> getCls() {
@@ -135,6 +150,10 @@ public abstract class AbstractSearchCond
             this.value = value;
         }
         
+        public CollectionCheckInfo getCollectionCheckInfo() {
+            return collInfo;
+        }
+        
         public boolean isCollection(String name) {
             return collectionProps != null && collectionProps.contains(name);
         }

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/JPATypedQueryVisitorTest.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/JPATypedQueryVisitorTest.java?rev=1426199&r1=1426198&r2=1426199&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/JPATypedQueryVisitorTest.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/JPATypedQueryVisitorTest.java Thu Dec 27 13:38:58 2012
@@ -199,6 +199,62 @@ public class JPATypedQueryVisitorTest ex
     }
     
     @Test
+    public void testQueryElementCollection() throws Exception {
+        List<Book> books = 
+            queryBooks("authors==John");
+        assertEquals(2, books.size());
+    }
+    
+    @Test
+    public void testNumberOfReviews() throws Exception {
+        List<Book> books = 
+            queryBooks("reviews=gt=0");
+        assertEquals(3, books.size());
+    }
+    
+    @Test
+    public void testNumberOfReviews2() throws Exception {
+        List<Book> books = 
+            queryBooks("reviews=gt=3");
+        assertEquals(0, books.size());
+    }
+    
+    @Test
+    public void testNumberOfReviewAuthors() throws Exception {
+        List<Book> books = 
+            queryBooks("count(reviews.authors)=gt=0");
+        assertEquals(3, books.size());
+    }
+    
+    @Test
+    public void testNumberOfReviewAuthors2() throws Exception {
+        List<Book> books = 
+            queryBooks("count(reviews.authors)=gt=3");
+        assertEquals(0, books.size());
+    }
+    
+    @Test
+    public void testNumberOfAuthors() throws Exception {
+        List<Book> books = 
+            queryBooks("count(authors)=gt=0");
+        assertEquals(3, books.size());
+    }
+    
+    @Test
+    public void testNumberOfAuthors2() throws Exception {
+        List<Book> books = 
+            queryBooks("count(authors)=gt=3");
+        assertEquals(0, books.size());
+    }
+    
+    @Test
+    public void testQueryCollectionSize2() throws Exception {
+        List<Book> books = 
+            queryBooks("reviews.authors=gt=0");
+        assertEquals(3, books.size());
+    }
+    
+    @Test
     public void testAndQueryCollection() throws Exception {
         List<Book> books = 
             queryBooks("id==10;authors==John;reviews.review==good;reviews.authors==Ted");