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/11/16 15:14:24 UTC

svn commit: r1410350 - in /cxf/branches/2.6.x-fixes: ./ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ 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/se...

Author: sergeyb
Date: Fri Nov 16 14:14:22 2012
New Revision: 1410350

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

........
  r1410348 | sergeyb | 2012-11-16 14:10:27 +0000 (Fri, 16 Nov 2012) | 1 line
  
  Finalizing JPA2 related enhancements for now with the initial support for joins
........

Added:
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/BookReview.java
      - copied unchanged from r1410348, cxf/trunk/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/BookReview.java
Modified:
    cxf/branches/2.6.x-fixes/   (props changed)
    cxf/branches/2.6.x-fixes/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/AbstractSearchConditionVisitor.java
    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/PrimitiveStatement.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/jpa/JPACriteriaQueryVisitor.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/JPATypedQueryVisitor.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/Book.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/Book_.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/JPATypedQueryVisitorTest.java
    cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/resources/META-INF/persistence.xml

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

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

Modified: cxf/branches/2.6.x-fixes/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java?rev=1410350&r1=1410349&r2=1410350&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java (original)
+++ cxf/branches/2.6.x-fixes/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/InjectionUtils.java Fri Nov 16 14:14:22 2012
@@ -1134,6 +1134,13 @@ public final class InjectionUtils {
         }
         if (cls.isPrimitive()) {
             return PrimitiveUtils.read(value, cls);
+        } else if (cls.isEnum()) {
+            try {
+                Method m  = cls.getMethod("valueOf", new Class[]{String.class});
+                return m.invoke(null, value.toUpperCase());
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
         } else {
             try {
                 Constructor<?> c = cls.getConstructor(new Class<?>[]{String.class});

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/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/AbstractSearchConditionVisitor.java?rev=1410350&r1=1410349&r2=1410350&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/AbstractSearchConditionVisitor.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/AbstractSearchConditionVisitor.java Fri Nov 16 14:14:22 2012
@@ -19,7 +19,11 @@
 package org.apache.cxf.jaxrs.ext.search;
 
 import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.cxf.jaxrs.utils.InjectionUtils;
 
@@ -45,6 +49,17 @@ public abstract class AbstractSearchCond
     }    
     
     protected ClassValue getPrimitiveFieldClass(String name, Class<?> valueCls, Object value) {
+        return getPrimitiveFieldClass(name, valueCls, valueCls, value);
+    }
+    
+    protected ClassValue getPrimitiveFieldClass(String name, Class<?> valueCls, Type type, Object value) {
+        return doGetPrimitiveFieldClass(name, valueCls, type, value, new HashSet<String>());
+    }
+    
+    @SuppressWarnings("rawtypes")
+    private ClassValue doGetPrimitiveFieldClass(String name, Class<?> valueCls, Type type, Object value, 
+                                                Set<String> set) {
+        boolean isCollection = InjectionUtils.isSupportedCollectionOrArray(valueCls);
         
         int index = name.indexOf(".");
         if (index != -1) {
@@ -58,16 +73,25 @@ public abstract class AbstractSearchCond
                     } else {
                         nextPart = Character.toUpperCase(nextPart.charAt(0)) + nextPart.substring(1);
                     }
-                    Method m = valueCls.getMethod("get" + nextPart, new Class[]{});
+                    Class<?> actualCls = isCollection 
+                        ? InjectionUtils.getActualType(type) : valueCls;
+                    Method m = actualCls.getMethod("get" + nextPart, new Class[]{});
+                    if (isCollection) {
+                        value = ((Collection)value).iterator().next();
+                        set.add(names[0]);
+                    }
                     value = m.invoke(value, new Object[]{});
                     valueCls = value.getClass();
-                    
+                    type = m.getGenericReturnType();
                 } catch (Throwable ex) {
                     throw new RuntimeException();
                 }
-                return getPrimitiveFieldClass(name, valueCls, value);
+                return doGetPrimitiveFieldClass(name, valueCls, type, value, set);
             }
-            
+        } else if (isCollection) {
+            set.add(name);
+            value = ((Collection)value).iterator().next();
+            valueCls = value.getClass();
         }
         
         Class<?> cls = null;
@@ -77,7 +101,7 @@ public abstract class AbstractSearchCond
         if (cls == null) {  
             cls = valueCls;
         }
-        return new ClassValue(cls, value);
+        return new ClassValue(cls, value, set);
     }
 
     public void setPrimitiveFieldTypeMap(Map<String, Class<?>> primitiveFieldTypeMap) {
@@ -91,10 +115,11 @@ public abstract class AbstractSearchCond
     protected class ClassValue {
         private Class<?> cls;
         private Object value;
-        public ClassValue(Class<?> cls, Object value) {
+        private Set<String> collectionProps;
+        public ClassValue(Class<?> cls, Object value, Set<String> collectionProps) {
             this.cls = cls;
             this.value = value;
-                
+            this.collectionProps = collectionProps;       
         }
         public Class<?> getCls() {
             return cls;
@@ -108,5 +133,9 @@ public abstract class AbstractSearchCond
         public void setValue(Object value) {
             this.value = value;
         }
+        
+        public boolean isCollection(String name) {
+            return collectionProps != null && collectionProps.contains(name);
+        }
     }
 }

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=1410350&r1=1410349&r2=1410350&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 Fri Nov 16 14:14:22 2012
@@ -21,6 +21,7 @@ package org.apache.cxf.jaxrs.ext.search;
 import java.beans.IntrospectionException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -91,7 +92,7 @@ public class Beanspector<T> {
         return Collections.unmodifiableSet(setters.keySet());
     }
 
-    public Class<?> getAccessorType(String getterOrSetterName) throws Exception {
+    public TypeInfo getAccessorTypeInfo(String getterOrSetterName) throws Exception {
         Method m = getters.get(getterOrSetterName);
         if (m == null) {
             m = setters.get(getterOrSetterName);
@@ -102,7 +103,7 @@ public class Beanspector<T> {
                                        setters.keySet(), getters.keySet());
             throw new IntrospectionException(msg);
         }
-        return m.getReturnType();
+        return new TypeInfo(m.getReturnType(), m.getGenericReturnType());
     }
 
     public Beanspector<T> swap(T newobject) throws Exception {
@@ -190,5 +191,21 @@ public class Beanspector<T> {
     }
 
     
-
+    public static class TypeInfo {
+        private Class<?> cls;
+        private Type genericType;
+        
+        public TypeInfo(Class<?> cls, Type genericType) {
+            this.cls = cls;
+            this.genericType = genericType;
+        }
+        
+        public Class<?> getTypeClass() {
+            return cls;
+        }
+        
+        public Type getGenericType() {
+            return genericType;
+        }
+    }
 }

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=1410350&r1=1410349&r2=1410350&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 Fri Nov 16 14:14:22 2012
@@ -19,6 +19,7 @@
 package org.apache.cxf.jaxrs.ext.search;
 
 import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -29,16 +30,19 @@ public class PrimitiveSearchCondition<T>
     
     private String propertyName;
     private Object propertyValue;
+    private Type propertyType;
     private T condition;
     private ConditionType cType;
     private Beanspector<T> beanspector;
     
     public PrimitiveSearchCondition(String propertyName, 
                                     Object propertyValue,
+                                    Type propertyType,
                                     ConditionType ct,
                                     T condition) {
         this.propertyName = propertyName;
         this.propertyValue = propertyValue;
+        this.propertyType = propertyType;
         this.condition = condition;
         this.cType = ct;
         if (propertyName != null) {
@@ -70,7 +74,7 @@ public class PrimitiveSearchCondition<T>
     }
 
     public PrimitiveStatement getStatement() {
-        return new PrimitiveStatement(propertyName, propertyValue, cType);
+        return new PrimitiveStatement(propertyName, propertyValue, propertyType, cType);
     }
 
     public boolean isMet(T pojo) {
@@ -113,7 +117,6 @@ public class PrimitiveSearchCondition<T>
         visitor.visit(this);    
     }
    
-
     private boolean isPrimitive(T pojo) {
         return pojo.getClass().getName().startsWith("java.lang");
     }

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/PrimitiveStatement.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/PrimitiveStatement.java?rev=1410350&r1=1410349&r2=1410350&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/PrimitiveStatement.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/PrimitiveStatement.java Fri Nov 16 14:14:22 2012
@@ -18,6 +18,8 @@
  */
 package org.apache.cxf.jaxrs.ext.search;
 
+import java.lang.reflect.Type;
+
 /**
  * Encapsulates a basic search statement such as a = b, i < 5, etc
  */
@@ -26,12 +28,14 @@ public class PrimitiveStatement {
 
     private String property;
     private Object value;
+    private Type propertyType;
     private ConditionType condition;
     
-    public PrimitiveStatement(String property, Object value, ConditionType condition) {
+    public PrimitiveStatement(String property, Object value, Type type, ConditionType condition) {
         this.property = property;
         this.value = value;
         this.condition = condition;
+        this.propertyType = type;
     }
     
     public String getProperty() {
@@ -41,6 +45,11 @@ public class PrimitiveStatement {
     public Object getValue() {
         return value;
     }
+    
+    public Type getValueType() {
+        return propertyType;
+    }
+    
     public ConditionType getCondition() {
         return condition;
     }

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=1410350&r1=1410349&r2=1410350&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 Fri Nov 16 14:14:22 2012
@@ -18,6 +18,7 @@
  */
 package org.apache.cxf.jaxrs.ext.search;
 
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -27,6 +28,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.cxf.jaxrs.ext.search.Beanspector.TypeInfo;
+
 /**
  * Simple search condition comparing primitive objects or complex object by its getters. For details see
  * {@link #isMet(Object)} description.
@@ -68,7 +71,7 @@ public class SimpleSearchCondition<T> im
             throw new IllegalArgumentException("unsupported condition type: " + cType.name());
         }
         this.condition = condition;
-        scts = createConditions(null, null, cType);
+        scts = createConditions(null, null, null, cType);
                 
     }
 
@@ -82,6 +85,7 @@ public class SimpleSearchCondition<T> im
      */
     public SimpleSearchCondition(Map<String, ConditionType> getters2operators, 
                                  Map<String, String> realGetters,
+                                 Map<String, TypeInfo> propertyTypeInfo,
                                  T condition) {
         if (getters2operators == null) {
             throw new IllegalArgumentException("getters2operators is null");
@@ -100,12 +104,12 @@ public class SimpleSearchCondition<T> im
                 throw new IllegalArgumentException("unsupported condition type: " + ct.name());
             }
         }
-        scts = createConditions(getters2operators, realGetters, null);
+        scts = createConditions(getters2operators, realGetters, propertyTypeInfo, null);
     }
 
     public SimpleSearchCondition(Map<String, ConditionType> getters2operators, 
                                  T condition) {
-        this(getters2operators, null, condition);
+        this(getters2operators, null, null, condition);
     }
     
     public T getCondition() {
@@ -135,10 +139,11 @@ public class SimpleSearchCondition<T> im
 
     private List<SearchCondition<T>> createConditions(Map<String, ConditionType> getters2operators,
                                                       Map<String, String> realGetters,
+                                                      Map<String, TypeInfo> propertyTypeInfo,
                                                       ConditionType sharedType) {
         if (isBuiltIn(condition)) {
             return Collections.singletonList(
-                (SearchCondition<T>)new PrimitiveSearchCondition<T>(null, condition, sharedType, condition));
+                (SearchCondition<T>)new PrimitiveSearchCondition<T>(null, condition, null, sharedType, condition));
         } else {
             List<SearchCondition<T>> list = new ArrayList<SearchCondition<T>>();
             Map<String, Object> get2val = getGettersAndValues();
@@ -158,8 +163,11 @@ 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, ct, condition));
+                list.add(new PrimitiveSearchCondition<T>(realGetter, rval, genType, ct, condition));
                 
             }
             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=1410350&r1=1410349&r2=1410350&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 Fri Nov 16 14:14:22 2012
@@ -34,6 +34,7 @@ import javax.xml.datatype.DatatypeFactor
 
 import org.apache.cxf.jaxrs.ext.search.AndSearchCondition;
 import org.apache.cxf.jaxrs.ext.search.Beanspector;
+import org.apache.cxf.jaxrs.ext.search.Beanspector.TypeInfo;
 import org.apache.cxf.jaxrs.ext.search.ConditionType;
 import org.apache.cxf.jaxrs.ext.search.OrSearchCondition;
 import org.apache.cxf.jaxrs.ext.search.PropertyNotFoundException;
@@ -252,7 +253,7 @@ public class FiqlParser<T> implements Se
                 name = beanPropertyName;
             }
             
-            Object castedValue = parseType(name, value);
+            TypeInfoObject castedValue = parseType(name, value);
             if (castedValue != null) {
                 return new Comparison(name, operator, castedValue);
             } else if (MessageUtils.isTrue(contextProperties.get(SearchUtils.LAX_PROPERTY_MATCH))) {
@@ -266,13 +267,15 @@ public class FiqlParser<T> implements Se
     }
 
     
-    private Object parseType(String setter, String value) throws SearchParseException {
+    private TypeInfoObject parseType(String setter, String value) throws SearchParseException {
         String name = getSetter(setter);
         
         try {
-            Class<?> valueType = 
-                beanspector != null ? beanspector.getAccessorType(name) : String.class;
-            return parseType(null, null, setter, valueType, value);
+            TypeInfo typeInfo = 
+                beanspector != null ? beanspector.getAccessorTypeInfo(name) 
+                    : new TypeInfo(String.class, String.class);
+            Object object = parseType(null, null, setter, typeInfo, value);
+            return new TypeInfoObject(object, typeInfo);
         } catch (Exception e) {
             return null;
         }
@@ -280,29 +283,41 @@ public class FiqlParser<T> implements Se
     }
 
     private Object parseType(Object ownerBean, Object lastCastedValue, String setter, 
-                             Class<?> valueType, String value) throws SearchParseException {
+                             TypeInfo typeInfo, String value) throws SearchParseException {
+        Class<?> valueType = typeInfo.getTypeClass();
+        boolean isCollection = InjectionUtils.isSupportedCollectionOrArray(valueType);
+        Class<?> actualType = isCollection ? InjectionUtils.getActualType(typeInfo.getGenericType()) : valueType;
+        
         int index = setter.indexOf(".");
         if (index == -1) {
             Object castedValue = value;
             if (Date.class.isAssignableFrom(valueType)) {
                 castedValue = convertToDate(value);
-            } else if (ownerBean == null || valueType.isPrimitive()) {
-                try {
-                    castedValue = InjectionUtils.convertStringToPrimitive(value, valueType);
-                } catch (Exception e) {
-                    throw new SearchParseException("Cannot convert String value \"" + value
-                                                 + "\" to a value of class " + valueType.getName(), e);
-                }
             } else {
-                try {
-                    Method setterM = valueType.getMethod("set" + getMethodNameSuffix(setter),
-                                                         new Class[]{String.class});
-                    setterM.invoke(ownerBean, new Object[]{value});
-                } catch (Throwable ex) {
-                    throw new SearchParseException("Cannot convert String value \"" + value
-                                                   + "\" to a value of class " + valueType.getName(), ex);
+                if (ownerBean == null || InjectionUtils.isPrimitive(valueType) || valueType.isEnum()) {
+                    try {
+                        castedValue = InjectionUtils.convertStringToPrimitive(value, actualType);
+                        if (isCollection) {
+                            castedValue = Collections.singletonList(castedValue);
+                        }
+                    } catch (Exception e) {
+                        throw new SearchParseException("Cannot convert String value \"" + value
+                                                     + "\" to a value of class " + valueType.getName(), e);
+                    }
+                } else {
+                    Class<?> classType = isCollection ? valueType : value.getClass(); 
+                    try {
+                        Method setterM = valueType.getMethod("set" + getMethodNameSuffix(setter),
+                                                             new Class[]{classType});
+                        Object objectValue = !isCollection ? value : Collections.singletonList(value);
+                        setterM.invoke(ownerBean, new Object[]{objectValue});
+                        castedValue = objectValue; 
+                    } catch (Throwable ex) {
+                        throw new SearchParseException("Cannot convert String value \"" + value
+                                                       + "\" to a value of class " + valueType.getName(), ex);
+                    }
+                    
                 }
-                
             }
             if (lastCastedValue != null) {
                 castedValue = lastCastedValue;
@@ -312,32 +327,39 @@ public class FiqlParser<T> implements Se
             String[] names = setter.split("\\.");
             try {
                 String nextPart = getMethodNameSuffix(names[1]);
-                Method getterM = valueType.getMethod("get" + nextPart, new Class[]{});   
+                Method getterM = actualType.getMethod("get" + nextPart, new Class[]{});   
                 Class<?> returnType = getterM.getReturnType();
+                boolean returnCollection = InjectionUtils.isSupportedCollectionOrArray(returnType);
                 
-                boolean isPrimitive = InjectionUtils.isPrimitive(returnType);
-                boolean lastTry = names.length == 2 && (isPrimitive || returnType == Date.class);
+                boolean isPrimitive = InjectionUtils.isPrimitive(returnType) || returnType.isEnum();
+                boolean lastTry = names.length == 2 
+                    && (isPrimitive || returnType == Date.class || returnCollection);
                 
-                Object valueObject = lastTry && ownerBean != null ? ownerBean : valueType.newInstance();
+                Object valueObject = lastTry && ownerBean != null ? ownerBean : actualType.newInstance();
                 Object nextObject;
                 
                 if (lastTry) {
-                    nextObject = isPrimitive ? InjectionUtils.convertStringToPrimitive(value, returnType) 
-                        : convertToDate(value); 
+                    if (!returnCollection) {
+                        nextObject = isPrimitive ? InjectionUtils.convertStringToPrimitive(value, returnType) 
+                            : convertToDate(value);
+                    } else {
+                        nextObject = Collections.singletonList(value);
+                    }
                 } else {
                     nextObject = returnType.newInstance();
                 }
                 
-                Method setterM = valueType.getMethod("set" + nextPart, new Class[]{getterM.getReturnType()});
+                Method setterM = actualType.getMethod("set" + nextPart, new Class[]{returnType});
                 setterM.invoke(valueObject, new Object[]{nextObject});
                 
                 lastCastedValue = lastCastedValue == null ? valueObject : lastCastedValue;
                 if (lastTry) {
-                    return lastCastedValue;
+                    return isCollection ? Collections.singletonList(lastCastedValue) : lastCastedValue;
                 } 
                 
+                TypeInfo nextTypeInfo = new TypeInfo(nextObject.getClass(), getterM.getGenericReturnType()); 
                 return parseType(nextObject, lastCastedValue, setter.substring(index + 1), 
-                                 nextObject.getClass(), value);
+                                 nextTypeInfo, value);
             } catch (Throwable e) {
                 throw new SearchParseException("Cannot convert String value \"" + value
                                                + "\" to a value of class " + valueType.getName(), e);
@@ -440,22 +462,23 @@ public class FiqlParser<T> implements Se
     private class Comparison implements ASTNode<T> {
         private String name;
         private String operator;
-        private Object value;
+        private TypeInfoObject tvalue;
 
-        public Comparison(String name, String operator, Object value) {
+        public Comparison(String name, String operator, TypeInfoObject value) {
             this.name = name;
             this.operator = operator;
-            this.value = value;
+            this.tvalue = value;
         }
 
         @Override
         public String toString() {
-            return name + " " + operator + " " + value + " (" + value.getClass().getSimpleName() + ")";
+            return name + " " + operator + " " + tvalue.getObject() 
+                + " (" + tvalue.getObject().getClass().getSimpleName() + ")";
         }
 
         public SearchCondition<T> build() throws SearchParseException {
             String templateName = getSetter(name);
-            T cond = createTemplate(templateName, value);
+            T cond = createTemplate(templateName);
             ConditionType ct = OPERATORS_MAP.get(operator);
             
             if (isPrimitive(cond)) {
@@ -463,7 +486,8 @@ public class FiqlParser<T> implements Se
             } else {
                 return new SimpleSearchCondition<T>(Collections.singletonMap(templateName, ct),
                                                     Collections.singletonMap(templateName, name),
-                                                   cond);
+                                                    Collections.singletonMap(templateName, tvalue.getTypeInfo()),
+                                                    cond);
             }
         }
 
@@ -472,14 +496,14 @@ public class FiqlParser<T> implements Se
         }
         
         @SuppressWarnings("unchecked")
-        private T createTemplate(String setter, Object val) throws SearchParseException {
+        private T createTemplate(String setter) throws SearchParseException {
             try {
                 if (beanspector != null) {
-                    beanspector.instantiate().setValue(setter, val);
+                    beanspector.instantiate().setValue(setter, tvalue.getObject());
                     return beanspector.getBean();
                 } else {
                     SearchBean bean = (SearchBean)conditionClass.newInstance();
-                    bean.set(setter, value.toString());
+                    bean.set(setter, tvalue.getObject().toString());
                     return (T)bean;
                 }
             } catch (Throwable e) {
@@ -487,4 +511,23 @@ public class FiqlParser<T> implements Se
             }
         }
     }
+    
+    static class TypeInfoObject {
+        private Object object;
+        private TypeInfo typeInfo;
+        
+        public TypeInfoObject(Object object, TypeInfo typeInfo) {
+            this.object = object;
+            this.typeInfo = typeInfo;
+        }
+
+        public TypeInfo getTypeInfo() {
+            return typeInfo;
+        }
+
+        public Object getObject() {
+            return object;
+        }
+                
+    }
 }

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=1410350&r1=1410349&r2=1410350&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 Fri Nov 16 14:14:22 2012
@@ -18,15 +18,19 @@
  */
 package org.apache.cxf.jaxrs.ext.search.jpa;
 
+import java.lang.reflect.Type;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.Stack;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Join;
 import javax.persistence.criteria.Path;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
@@ -48,29 +52,52 @@ public abstract class AbstractJPATypedQu
     private CriteriaQuery<T1> cq;
     private Stack<List<Predicate>> predStack = new Stack<List<Predicate>>();
     private boolean criteriaFinalized;
+    private Set<String> joinProperties;
     
     protected AbstractJPATypedQueryVisitor(EntityManager em, Class<T> tClass) {
-        this(em, tClass, null, null);
+        this(em, tClass, null, null, null);
     }
     
     protected AbstractJPATypedQueryVisitor(EntityManager em, Class<T> tClass, Class<T1> queryClass) {
-        this(em, tClass, queryClass, null);
+        this(em, tClass, queryClass, null, null);
     }
     
     protected AbstractJPATypedQueryVisitor(EntityManager em, 
                                         Class<T> tClass, 
                                         Map<String, String> fieldMap) {
-        this(em, tClass, null, fieldMap);
+        this(em, tClass, null, fieldMap, null);
+    }
+    
+    protected AbstractJPATypedQueryVisitor(EntityManager em, 
+                                           Class<T> tClass, 
+                                           List<String> joinProps) {
+           this(em, tClass, null, null, joinProps);
     }
     
     protected AbstractJPATypedQueryVisitor(EntityManager em, 
                                         Class<T> tClass, 
-                                        Class<T1> queryClass,
-                                        Map<String, String> fieldMap) {
+                                        Map<String, String> fieldMap,
+                                        List<String> joinProps) {
+        this(em, tClass, null, fieldMap, joinProps);
+    }
+    
+    protected AbstractJPATypedQueryVisitor(EntityManager em, 
+                                           Class<T> tClass, 
+                                           Class<T1> queryClass,
+                                           Map<String, String> fieldMap) {
+        this(em, tClass, queryClass, fieldMap, null);
+    }
+    
+    protected AbstractJPATypedQueryVisitor(EntityManager em, 
+                                           Class<T> tClass, 
+                                           Class<T1> queryClass,
+                                           Map<String, String> fieldMap,
+                                           List<String> joinProps) {
         super(fieldMap);
         this.em = em;
         this.tClass = tClass;
         this.queryClass = toQueryClass(queryClass, tClass);
+        this.joinProperties = joinProps == null ? null : new HashSet<String>(joinProps);
     }
     
     @SuppressWarnings("unchecked")
@@ -94,7 +121,8 @@ public abstract class AbstractJPATypedQu
             if (statement.getProperty() != null) {
                 predStack.peek().add(buildPredicate(sc.getConditionType(), 
                                                     statement.getProperty(), 
-                                                    statement.getValue()));
+                                                    statement.getValue(),
+                                                    statement.getValueType()));
             }
         } else {
             predStack.push(new ArrayList<Predicate>());
@@ -138,17 +166,16 @@ public abstract class AbstractJPATypedQu
         return cq;
     }
     
-    
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    private Predicate buildPredicate(ConditionType ct, String name, Object value) {
+    private Predicate buildPredicate(ConditionType ct, String name, Object value, Type valueType) {
 
         name = super.getRealPropertyName(name);
-        ClassValue cv = getPrimitiveFieldClass(name, value.getClass(), value); 
+        ClassValue cv = getPrimitiveFieldClass(name, value.getClass(), valueType, value); 
         
         Class<? extends Comparable> clazz = (Class<? extends Comparable>)cv.getCls();
         value = cv.getValue();    
         
-        Path<?> path = getPath(root, name);
+        Path<?> path = getPath(root, name, cv);
         if (tClass != queryClass) {
             path.alias(name);
         }
@@ -191,16 +218,29 @@ public abstract class AbstractJPATypedQu
         return pred;
     }
 
-    private Path<?> getPath(Path<?> element, String name) {
+    private Path<?> getPath(Path<?> element, String name, ClassValue cv) {
         if (name.contains(".")) {
             String pre = name.substring(0, name.indexOf('.'));
             String post = name.substring(name.indexOf('.') + 1);
-            Path<?> newPath = element.get(pre);
-            return getPath(newPath, post);
+            return getPath(getNextPath(element, pre, cv), 
+                           post, 
+                           cv);
+        } else {
+            return getNextPath(element, name, cv);
+        }
+    }
+
+    private Path<?> getNextPath(Path<?> element, String name, ClassValue cv) {
+        if ((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);
         }
     }
     
+    private boolean isJoinProperty(String prop) {
+        return joinProperties == null ? false : joinProperties.contains(prop);
+    }
+    
     
 }

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/JPACriteriaQueryVisitor.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/JPACriteriaQueryVisitor.java?rev=1410350&r1=1410349&r2=1410350&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/JPACriteriaQueryVisitor.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/JPACriteriaQueryVisitor.java Fri Nov 16 14:14:22 2012
@@ -34,7 +34,14 @@ public class JPACriteriaQueryVisitor<T, 
     public JPACriteriaQueryVisitor(EntityManager em, 
                                    Class<T> tClass,
                                    Class<E> queryClass) {
-        this(em, tClass, queryClass, null);
+        this(em, tClass, queryClass, null, null);
+    }
+    
+    public JPACriteriaQueryVisitor(EntityManager em, 
+                                   Class<T> tClass,
+                                   Class<E> queryClass,
+                                   List<String> joinProps) {
+        this(em, tClass, queryClass, null, null);
     }
     
     public JPACriteriaQueryVisitor(EntityManager em, 
@@ -44,12 +51,20 @@ public class JPACriteriaQueryVisitor<T, 
         super(em, tClass, queryClass, fieldMap);
     }
     
+    public JPACriteriaQueryVisitor(EntityManager em, 
+                                   Class<T> tClass,
+                                   Class<E> queryClass,
+                                   Map<String, String> fieldMap,
+                                   List<String> joinProps) {
+        super(em, tClass, queryClass, fieldMap, joinProps);
+    }
+    
     public CriteriaQuery<E> getQuery() {
         return getCriteriaQuery();
     }
         
     public CriteriaQuery<E> selectArray(List<SingularAttribute<T, ?>> attributes) {
-        return selectArraySelections(toSelectionsArray(toSelectionsList(attributes)));
+        return selectArraySelections(toSelectionsArray(toSelectionsList(attributes, false)));
     }
     
     private CriteriaQuery<E> selectArraySelections(Selection<?>... selections) {
@@ -60,7 +75,7 @@ public class JPACriteriaQueryVisitor<T, 
     }
     
     public CriteriaQuery<E> selectConstruct(List<SingularAttribute<T, ?>> attributes) {
-        return selectConstructSelections(toSelectionsArray(toSelectionsList(attributes)));
+        return selectConstructSelections(toSelectionsArray(toSelectionsList(attributes, false)));
     }
     
     private CriteriaQuery<E> selectConstructSelections(Selection<?>... selections) {
@@ -69,7 +84,7 @@ public class JPACriteriaQueryVisitor<T, 
     }
     
     public CriteriaQuery<E> selectTuple(List<SingularAttribute<T, ?>> attributes) {
-        return selectTupleSelections(toSelectionsArray(toSelectionsList(attributes)));
+        return selectTupleSelections(toSelectionsArray(toSelectionsList(attributes, true)));
     }
     
     private CriteriaQuery<E> selectTupleSelections(Selection<?>... selections) {
@@ -80,7 +95,7 @@ public class JPACriteriaQueryVisitor<T, 
         return getQuery();
     }
     
-    private List<Selection<?>> toSelectionsList(List<SingularAttribute<T, ?>> attributes) {
+    private List<Selection<?>> toSelectionsList(List<SingularAttribute<T, ?>> attributes, boolean setAlias) {
         List<Selection<?>> selections = new ArrayList<Selection<?>>(attributes.size());
         for (SingularAttribute<T, ?> attr : attributes) {
             Path<?> path = getRoot().get(attr);

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/JPATypedQueryVisitor.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/JPATypedQueryVisitor.java?rev=1410350&r1=1410349&r2=1410350&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/JPATypedQueryVisitor.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/main/java/org/apache/cxf/jaxrs/ext/search/jpa/JPATypedQueryVisitor.java Fri Nov 16 14:14:22 2012
@@ -18,6 +18,8 @@
  */
 package org.apache.cxf.jaxrs.ext.search.jpa;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 import javax.persistence.EntityManager;
@@ -26,13 +28,32 @@ import javax.persistence.TypedQuery;
 public class JPATypedQueryVisitor<T> extends AbstractJPATypedQueryVisitor<T, T, TypedQuery<T>> {
 
     public JPATypedQueryVisitor(EntityManager em, Class<T> tClass) {
-        this(em, tClass, null);
+        this(em, tClass, null, null);
     }
     
     public JPATypedQueryVisitor(EntityManager em, Class<T> tClass, Map<String, String> fieldMap) {
         super(em, tClass, fieldMap);
     }
     
+    public JPATypedQueryVisitor(EntityManager em, 
+                                Class<T> tClass, 
+                                List<String> joinProps) {
+        super(em, tClass, null, joinProps);
+    }
+    
+    public JPATypedQueryVisitor(EntityManager em, 
+                                Class<T> tClass, 
+                                String joinProp) {
+        super(em, tClass, null, Collections.singletonList(joinProp));
+    }
+    
+    public JPATypedQueryVisitor(EntityManager em, 
+                                Class<T> tClass, 
+                                Map<String, String> fieldMap,
+                                List<String> joinProps) {
+        super(em, tClass, fieldMap, joinProps);
+    }
+    
     public TypedQuery<T> getQuery() {
         return getTypedQuery();
     }

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/Book.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/Book.java?rev=1410350&r1=1410349&r2=1410350&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/Book.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/Book.java Fri Nov 16 14:14:22 2012
@@ -18,10 +18,15 @@
  */
 package org.apache.cxf.jaxrs.ext.search.jpa;
 
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.ElementCollection;
 import javax.persistence.Embedded;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
 
 @Entity(name = "Book")
 public class Book {
@@ -30,6 +35,8 @@ public class Book {
     private OwnerAddress address;
     private OwnerInfo ownerInfo;
     private Library library;
+    private List<BookReview> reviews = new LinkedList<BookReview>();
+    private List<String> authors = new LinkedList<String>();
     
     @Id
     public int getId() {
@@ -73,4 +80,22 @@ public class Book {
     public void setLibrary(Library library) {
         this.library = library;
     }
+
+    @OneToMany
+    public List<BookReview> getReviews() {
+        return reviews;
+    }
+
+    public void setReviews(List<BookReview> reviews) {
+        this.reviews = reviews;
+    }
+
+    @ElementCollection
+    public List<String> getAuthors() {
+        return authors;
+    }
+
+    public void setAuthors(List<String> authors) {
+        this.authors = authors;
+    }
 }

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/Book_.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/Book_.java?rev=1410350&r1=1410349&r2=1410350&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/Book_.java (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/java/org/apache/cxf/jaxrs/ext/search/jpa/Book_.java Fri Nov 16 14:14:22 2012
@@ -18,6 +18,7 @@
  */
 package org.apache.cxf.jaxrs.ext.search.jpa;
 
+import javax.persistence.metamodel.ListAttribute;
 import javax.persistence.metamodel.SingularAttribute;
 
 @javax.persistence.metamodel.StaticMetamodel(Book.class)
@@ -31,5 +32,7 @@ public final class Book_ {
     public static volatile SingularAttribute<Book, Library> library;
     public static volatile SingularAttribute<Book, OwnerInfo> ownerInfo;
     public static volatile SingularAttribute<Book, OwnerAddress> address;
+    public static volatile ListAttribute<Book, BookReview> reviews;
+    public static volatile ListAttribute<Book, String> authors;
 }
 //CHECKSTYLE:ON
\ No newline at end of file

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=1410350&r1=1410349&r2=1410350&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 Fri Nov 16 14:14:22 2012
@@ -40,6 +40,7 @@ import org.apache.cxf.jaxrs.ext.search.S
 import org.apache.cxf.jaxrs.ext.search.SearchConditionVisitor;
 import org.apache.cxf.jaxrs.ext.search.SearchUtils;
 import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser;
+import org.apache.cxf.jaxrs.ext.search.jpa.BookReview.Review;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -74,8 +75,19 @@ public class JPATypedQueryVisitorTest ex
             lib.setAddress("town");
             em.persist(lib);
             assertTrue(em.contains(lib));
-                        
+            
+            BookReview br1 = new BookReview();
+            br1.setId(1);
+            br1.setReview(Review.BAD);
+            br1.getAuthors().add("Ted");
+            em.persist(br1);
+            
             Book b1 = new Book();
+            
+            br1.setBook(b1);
+            b1.getReviews().add(br1);
+            
+            
             b1.setId(9);
             b1.setTitle("num9");
             b1.setAddress(new OwnerAddress("Street1"));
@@ -84,9 +96,20 @@ public class JPATypedQueryVisitorTest ex
             info1.setDateOfBirth(parseDate("2000-01-01"));
             b1.setOwnerInfo(info1);
             b1.setLibrary(lib);
+            b1.getAuthors().add("John");
             em.persist(b1);
             assertTrue(em.contains(b1));
+            
+            BookReview br2 = new BookReview();
+            br2.setId(2);
+            br2.setReview(Review.GOOD);
+            br2.getAuthors().add("Ted");
+            em.persist(br2);
+            
             Book b2 = new Book();
+            b2.getReviews().add(br2);
+            br2.setBook(b2);
+            
             b2.setId(10);
             b2.setTitle("num10");
             b2.setAddress(new OwnerAddress("Street2"));
@@ -95,12 +118,23 @@ public class JPATypedQueryVisitorTest ex
             info2.setDateOfBirth(parseDate("2001-01-01"));
             b2.setOwnerInfo(info2);
             b2.setLibrary(lib);
+            b2.getAuthors().add("John");
             em.persist(b2);
             assertTrue(em.contains(b2));
+            
+            BookReview br3 = new BookReview();
+            br3.setId(3);
+            br3.setReview(Review.GOOD);
+            br3.getAuthors().add("Ted");
+            em.persist(br3);
+            
             Book b3 = new Book();
+            b3.getReviews().add(br3);
+            br3.setBook(b3);
             b3.setId(11);
             b3.setTitle("num11");
             b3.setAddress(new OwnerAddress("Street3"));
+            b3.getAuthors().add("Barry");
             OwnerInfo info3 = new OwnerInfo();
             info3.setName(new Name("Bill"));
             info3.setDateOfBirth(parseDate("2002-01-01"));
@@ -158,6 +192,21 @@ public class JPATypedQueryVisitorTest ex
     }
     
     @Test
+    public void testQueryCollection() throws Exception {
+        List<Book> books = 
+            queryBooks("reviews.authors==Ted");
+        assertEquals(3, books.size());
+    }
+    
+    @Test
+    public void testAndQueryCollection() throws Exception {
+        List<Book> books = 
+            queryBooks("id==10;authors==John;reviews.review==good;reviews.authors==Ted");
+        assertEquals(1, books.size());
+        assertTrue(10 == books.get(0).getId() && "num10".equals(books.get(0).getTitle()));
+    }
+    
+    @Test
     public void testAndQueryNoMatch() throws Exception {
         List<Book> books = queryBooks("id==10;title==num9");
         assertEquals(0, books.size());
@@ -172,7 +221,7 @@ public class JPATypedQueryVisitorTest ex
     
     @Test
     public void testEqualsCriteriaQueryTuple() throws Exception {
-        List<Tuple> books = criteriaQueryBooks("id==10");
+        List<Tuple> books = criteriaQueryBooksTuple("id==10");
         assertEquals(1, books.size());
         Tuple tuple = books.get(0);
         int tupleId = tuple.get("id", Integer.class);
@@ -180,6 +229,24 @@ public class JPATypedQueryVisitorTest ex
     }
     
     @Test
+    public void testEqualsCriteriaQueryConstruct() throws Exception {
+        List<BookInfo> books = criteriaQueryBooksConstruct("id==10");
+        assertEquals(1, books.size());
+        BookInfo info = books.get(0);
+        assertEquals(10, info.getId());
+        assertEquals("num10", info.getTitle());
+    }
+    
+    @Test
+    public void testEqualsCriteriaQueryArray() throws Exception {
+        List<Object[]> books = criteriaQueryBooksArray("id==10");
+        assertEquals(1, books.size());
+        Object[] info = books.get(0);
+        assertEquals(10, ((Integer)info[0]).intValue());
+        assertEquals("num10", (String)info[1]);
+    }
+    
+    @Test
     public void testEqualsAddressQuery() throws Exception {
         List<Book> books = queryBooks("address==Street1",
             Collections.singletonMap("address", "address.street"));
@@ -326,29 +393,36 @@ public class JPATypedQueryVisitorTest ex
     }
     
     private List<Book> queryBooks(String expression) throws Exception {
-        return queryBooks(expression, null);
+        return queryBooks(expression, null, null, null);
     }
     
     private List<Book> queryBooks(String expression, 
                                   Map<String, String> visitorProps) throws Exception {
-        return queryBooks(expression, visitorProps, null);
+        return queryBooks(expression, visitorProps, null, null);
     }
     
     private List<Book> queryBooks(String expression, 
                                   Map<String, String> visitorProps,
                                   Map<String, String> parserBinProps) throws Exception {
+        return queryBooks(expression, visitorProps, parserBinProps, null);
+    }
+    
+    private List<Book> queryBooks(String expression, 
+                                  Map<String, String> visitorProps,
+                                  Map<String, String> parserBinProps,
+                                  List<String> joinProps) throws Exception {
         SearchCondition<Book> filter = 
             new FiqlParser<Book>(Book.class,
                                  visitorProps,
                                  parserBinProps).parse(expression);
         SearchConditionVisitor<Book, TypedQuery<Book>> jpa = 
-            new JPATypedQueryVisitor<Book>(em, Book.class, visitorProps);
+            new JPATypedQueryVisitor<Book>(em, Book.class, visitorProps, joinProps);
         filter.accept(jpa);
         TypedQuery<Book> query = jpa.getQuery();
         return query.getResultList();
     }
     
-    private List<Tuple> criteriaQueryBooks(String expression) throws Exception {
+    private List<Tuple> criteriaQueryBooksTuple(String expression) throws Exception {
         SearchCondition<Book> filter = 
             new FiqlParser<Book>(Book.class).parse(expression);
         JPACriteriaQueryVisitor<Book, Tuple> jpa = 
@@ -364,4 +438,70 @@ public class JPATypedQueryVisitorTest ex
         CriteriaQuery<Tuple> cquery = jpa.getQuery();
         return em.createQuery(cquery).getResultList();
     }
+    
+    private List<BookInfo> criteriaQueryBooksConstruct(String expression) throws Exception {
+        SearchCondition<Book> filter = 
+            new FiqlParser<Book>(Book.class).parse(expression);
+        JPACriteriaQueryVisitor<Book, BookInfo> jpa = 
+            new JPACriteriaQueryVisitor<Book, BookInfo>(em, Book.class, BookInfo.class);
+        filter.accept(jpa);
+        
+        List<SingularAttribute<Book, ?>> selections = 
+            new ArrayList<SingularAttribute<Book, ?>>();
+        selections.add(Book_.id);
+        selections.add(Book_.title);
+        
+        jpa.selectConstruct(selections);
+        
+        CriteriaQuery<BookInfo> cquery = jpa.getQuery();
+        return em.createQuery(cquery).getResultList();
+    }
+    
+    private List<Object[]> criteriaQueryBooksArray(String expression) throws Exception {
+        SearchCondition<Book> filter = 
+            new FiqlParser<Book>(Book.class).parse(expression);
+        JPACriteriaQueryVisitor<Book, Object[]> jpa = 
+            new JPACriteriaQueryVisitor<Book, Object[]>(em, Book.class, Object[].class);
+        filter.accept(jpa);
+        
+        List<SingularAttribute<Book, ?>> selections = 
+            new ArrayList<SingularAttribute<Book, ?>>();
+        selections.add(Book_.id);
+        selections.add(Book_.title);
+        
+        jpa.selectArray(selections);
+        
+        CriteriaQuery<Object[]> cquery = jpa.getQuery();
+        return em.createQuery(cquery).getResultList();
+    }
+    
+    public static class BookInfo {
+        private int id;
+        private String title;
+
+        public BookInfo() {
+            
+        }
+        
+        public BookInfo(Integer id, String title) {
+            this.id = id;
+            this.title = title;
+        }
+        
+        public int getId() {
+            return id;
+        }
+
+        public void setId(int id) {
+            this.id = id;
+        }
+
+        public String getTitle() {
+            return title;
+        }
+
+        public void setTitle(String title) {
+            this.title = title;
+        }
+    }
 }

Modified: cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/resources/META-INF/persistence.xml
URL: http://svn.apache.org/viewvc/cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/resources/META-INF/persistence.xml?rev=1410350&r1=1410349&r2=1410350&view=diff
==============================================================================
--- cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/resources/META-INF/persistence.xml (original)
+++ cxf/branches/2.6.x-fixes/rt/rs/extensions/search/src/test/resources/META-INF/persistence.xml Fri Nov 16 14:14:22 2012
@@ -6,6 +6,7 @@
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <class>org.apache.cxf.jaxrs.ext.search.jpa.Book</class>
      <class>org.apache.cxf.jaxrs.ext.search.jpa.Library</class>
+     <class>org.apache.cxf.jaxrs.ext.search.jpa.BookReview</class>
      <exclude-unlisted-classes>true</exclude-unlisted-classes>
      <properties>
         <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:books-jpa"/>
@@ -23,6 +24,7 @@
      <class>org.apache.cxf.jaxrs.ext.search.jpa.OwnerAddress</class>
      <class>org.apache.cxf.jaxrs.ext.search.jpa.OwnerInfo</class>
      <class>org.apache.cxf.jaxrs.ext.search.jpa.Name</class>
+     <class>org.apache.cxf.jaxrs.ext.search.jpa.BookReview</class>
      <exclude-unlisted-classes>true</exclude-unlisted-classes>
      <properties>
         <property name="openjpa.ConnectionURL" value="jdbc:hsqldb:mem:books-jpa"/>