/**
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jboss.pnc.datastore.predicates.rsql;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.List;

abstract class AbstractTransformer<Entity> implements Transformer<Entity> {

    private final ArgumentHelper argumentHelper = new ArgumentHelper();

    @Override
    public Predicate transform(Root<Entity> r, CriteriaBuilder cb, Class<?> selectingClass, String operand, List<String> arguments) {
        return transform(r, selectWithOperand(r, operand), cb, operand, argumentHelper.getConvertedType(selectingClass, operand, arguments));
    }

    public static Path<?> selectWithOperand(Root<?> root, String operand) {
        String [] fields = operand.split("\\.");
        Path<?> path = root;
        for(int i = 0; i < fields.length - 1; i++) {
            if(i == 0)
                path = ((Root<?>)path).join(fields[i]);
            else
                path = ((Join<?, ?>)path).join(fields[i]);
        }
        return path.get(fields[fields.length - 1]);
    }

    abstract Predicate transform(Root<Entity> r, Path<?> selectedPath, CriteriaBuilder cb, String operand, List<Object> convertedArguments);
}

@@ -747,16 +747,53 @@
 .rsql;%0A%0A
+import javax.persistence.EmbeddedId;%0A
 import j
@@ -999,16 +999,146 @@
 ia.Root;
+%0A%0Aimport org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0Aimport java.lang.invoke.MethodHandles;%0Aimport java.lang.reflect.Field;
 %0Aimport 
@@ -1231,16 +1231,121 @@
 ity%3E %7B%0A%0A
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());%0A%0A
     priv
@@ -1526,24 +1526,36 @@
 ing operand,
+%0A           
  List%3CString
@@ -1629,23 +1629,55 @@
 rand
-), cb, operand,
+, selectingClass), cb, operand,%0A               
  arg
@@ -1822,19 +1822,112 @@
  operand
-) %7B
+, Class clazz) %7B%0A        Class%3C?%3E currentClass = clazz;%0A        boolean isFieldEmbedded = false;
 %0A       
@@ -1933,17 +1933,16 @@
   String
- 
 %5B%5D field
@@ -1967,16 +1967,17 @@
 %22%5C%5C.%22);%0A
+%0A
         
@@ -2008,16 +2008,17 @@
      for
+ 
 (int i =
@@ -2047,24 +2047,25 @@
 - 1; i++) %7B%0A
+%0A
             
@@ -2068,18 +2068,659 @@
     
-if
+try %7B%0A                // Get the field declaration%0A                Field field = currentClass.getDeclaredField(fields%5Bi%5D);%0A                // Is the field annotated with EmbeddedId class?%0A                isFieldEmbedded = field.getAnnotation(EmbeddedId.class) != null ? true : false;%0A                // search the field class recursively%0A                currentClass = field.getType();%0A            %7D catch (NoSuchFieldException e) %7B%0A                throw new RSQLConverterException(%22Unable to get class for field %22 + fields%5Bi%5D, e);%0A            %7D%0A%0A            logger.info(%22field %7B%7D is EMBEDDED %7B%7D%22, fields%5Bi%5D, isFieldEmbedded);%0A%0A            if 
 (i == 0)
 %0A   
@@ -2715,17 +2715,63 @@
 (i == 0)
+ %7B
 %0A
+                if (!isFieldEmbedded) %7B%0A    
         
@@ -2795,16 +2795,17 @@
 Root%3C?%3E)
+ 
 path).jo
@@ -2834,14 +2834,217 @@
     
+     %7D
  else
+ %7B
 %0A
+                    // do not join as it's embedded%0A                    path = ((Root%3C?%3E) path).get(fields%5Bi%5D);%0A                %7D%0A            %7D else %7B%0A                if (!isFieldEmbedded) %7B%0A    
     
@@ -3075,16 +3075,17 @@
 n%3C?, ?%3E)
+ 
 path).jo
@@ -3091,32 +3091,204 @@
 oin(fields%5Bi%5D);%0A
+                %7D else %7B%0A                    // do not join as it's embedded%0A                    path = ((Join%3C?, ?%3E) path).get(fields%5Bi%5D);%0A                %7D%0A            %7D%0A
         %7D%0A      
@@ -3273,32 +3273,33 @@
     %7D%0A        %7D%0A
+%0A
         return p
@@ -3447,16 +3447,28 @@
 operand,
+%0A           
  List%3COb

Verify if the field is embedded to avoid joins that would throw exceptions