[OLINGO-644 and OLINGO-647] Support for nested method expressions in
$filter and preserve order by clause order

Signed-off-by: Chandan V A <chandan.v.a@sap.com>
diff --git a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLSelectContextView.java b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLSelectContextView.java
index 072dc3d..fc41411 100644
--- a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLSelectContextView.java
+++ b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/jpql/JPQLSelectContextView.java
@@ -18,7 +18,6 @@
  ******************************************************************************/
 package org.apache.olingo.odata2.jpa.processor.api.jpql;
 
-import java.util.Map;
 
 /**
  * The interface provide a view on JPQL select context.The interface provides
@@ -40,18 +39,11 @@
   public String getSelectExpression();
 
   /**
-   * The method returns an ordered map of JPQL ORDERBY clause. The ORDERBY clause
+   * The method returns an JPQL ORDERBY clause. The ORDERBY clause
    * is built from $orderby OData system query option. The hash map contains
-   * <ol>
-   * <li>Key - JPA Entity Property name to be ordered</li>
-   * <li>Value - Sort Order in JPQL (desc,asc)</li>
-   * </ol>
-   * in the order based on the expression specified
-   * (accessible with <code>Map.entrySet(..)</code>).
-   * 
-   * @return an ordered map of (JPA Property Name,Sort Order)
+   * @return an order by expression (JPA Property Name,Sort Order)
    */
-  public Map<String, String> getOrderByCollection();
+  public String getOrderByCollection();
 
   /**
    * The method returns a JPQL WHERE condition as string. The WHERE condition
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParser.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParser.java
index d86461c..830aaa8 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParser.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParser.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,14 +20,12 @@
 
 import java.util.ArrayList;
 import java.util.Calendar;
-import java.util.HashMap;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.List;
 
 import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmLiteral;
 import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
-import org.apache.olingo.odata2.api.edm.EdmMappable;
 import org.apache.olingo.odata2.api.edm.EdmMapping;
 import org.apache.olingo.odata2.api.edm.EdmProperty;
 import org.apache.olingo.odata2.api.edm.EdmSimpleType;
@@ -55,9 +53,9 @@
 
 /**
  * This class contains utility methods for parsing the filter expressions built by core library from user OData Query.
- * 
- * 
- * 
+ *
+ *
+ *
  */
 public class ODataExpressionParser {
 
@@ -66,9 +64,9 @@
 
   /**
    * This method returns the parsed where condition corresponding to the filter input in the user query.
-   * 
+   *
    * @param whereExpression
-   * 
+   *
    * @return Parsed where condition String
    * @throws ODataException
    */
@@ -167,9 +165,8 @@
       }
 
     case PROPERTY:
-      String returnStr =
-          tableAlias + JPQLStatement.DELIMITER.PERIOD
-              + ((EdmProperty) ((PropertyExpression) whereExpression).getEdmProperty()).getMapping().getInternalName();
+      String returnStr = tableAlias + JPQLStatement.DELIMITER.PERIOD
+          + getPropertyName(whereExpression);
       return returnStr;
 
     case MEMBER:
@@ -183,23 +180,18 @@
           memberExpStr = JPQLStatement.DELIMITER.PERIOD + memberExpStr;
         }
         i++;
-        memberExpStr =
-            ((EdmProperty) ((PropertyExpression) member.getProperty()).getEdmProperty()).getMapping().getInternalName()
-                + memberExpStr;
+        memberExpStr = getPropertyName(member.getProperty()) + memberExpStr;
         tempExp = member.getPath();
       }
       memberExpStr =
-          ((EdmMappable) ((PropertyExpression) tempExp).getEdmProperty()).getMapping().getInternalName()
-              + JPQLStatement.DELIMITER.PERIOD + memberExpStr;
+          getPropertyName(tempExp) + JPQLStatement.DELIMITER.PERIOD + memberExpStr;
       return tableAlias + JPQLStatement.DELIMITER.PERIOD + memberExpStr;
 
     case LITERAL:
       final LiteralExpression literal = (LiteralExpression) whereExpression;
       final EdmSimpleType literalType = (EdmSimpleType) literal.getEdmType();
-      String value =
-          literalType.valueToString(literalType.valueOfString(literal.getUriLiteral(), EdmLiteralKind.URI, null,
-              literalType.getDefaultType()), EdmLiteralKind.DEFAULT, null);
-      return evaluateComparingExpression(value, literalType);
+      EdmLiteral uriLiteral = EdmSimpleTypeKind.parseUriLiteral(literal.getUriLiteral());
+      return evaluateComparingExpression(uriLiteral.getLiteral(), literalType);
 
     case METHOD:
       final MethodExpression methodExpression = (MethodExpression) whereExpression;
@@ -216,21 +208,21 @@
         third = third != null ? ", " + third : "";
         return String.format("SUBSTRING(%s, %s + 1 %s)", first, second, third);
       case SUBSTRINGOF:
-        first = first.substring(1, first.length() - 1);
         if (methodFlag.get() != null && methodFlag.get() == 1) {
           methodFlag.set(null);
-          return String.format("(CASE WHEN (%s LIKE '%%%s%%') THEN TRUE ELSE FALSE END)", second, first);
+          return String.format("(CASE WHEN (%s LIKE CONCAT('%%',%s,'%%')) THEN TRUE ELSE FALSE END)", second, first);
         } else {
-          return String.format("(CASE WHEN (%s LIKE '%%%s%%') THEN TRUE ELSE FALSE END) = true", second, first);
+          return String.format("(CASE WHEN (%s LIKE CONCAT('%%',%s,'%%')) THEN TRUE ELSE FALSE END) = true", second,
+              first);
         }
       case TOLOWER:
         return String.format("LOWER(%s)", first);
       case STARTSWITH:
-        second = second.substring(1, second.length() - 1);
-        return String.format("%s LIKE '%s%%'", first, second);
+        // second = second.substring(1, second.length() - 1);
+        return String.format("%s LIKE CONCAT(%s,'%%')", first, second);
       case ENDSWITH:
-        second = second.substring(1, second.length() - 1);
-        return String.format("%s LIKE '%%%s'", first, second);
+        // second = second.substring(1, second.length() - 1);
+        return String.format("%s LIKE CONCAT('%%',%s)", first, second);
       default:
         throw new ODataNotImplementedException();
       }
@@ -242,7 +234,7 @@
 
   /**
    * This method parses the select clause
-   * 
+   *
    * @param tableAlias
    * @param selectedFields
    * @return a select expression
@@ -270,14 +262,14 @@
 
   /**
    * This method parses the order by condition in the query.
-   * 
+   *
    * @param orderByExpression
    * @return a map of JPA attributes and their sort order
    * @throws ODataJPARuntimeException
    */
-  public static HashMap<String, String> parseToJPAOrderByExpression(final OrderByExpression orderByExpression,
+  public static String parseToJPAOrderByExpression(final OrderByExpression orderByExpression,
       final String tableAlias) throws ODataJPARuntimeException {
-    HashMap<String, String> orderByMap = new HashMap<String, String>();
+    String jpqlOrderByExpression = "";
     if (orderByExpression != null && orderByExpression.getOrders() != null) {
       List<OrderExpression> orderBys = orderByExpression.getOrders();
       String orderByField = null;
@@ -285,22 +277,30 @@
       for (OrderExpression orderBy : orderBys) {
 
         try {
-          orderByField =
-              ((EdmProperty) ((PropertyExpression) orderBy.getExpression()).getEdmProperty()).getMapping()
-                  .getInternalName();
-          orderByDirection = (orderBy.getSortOrder() == SortOrder.asc) ? EMPTY : "DESC"; //$NON-NLS-1$
-          orderByMap.put(tableAlias + JPQLStatement.DELIMITER.PERIOD + orderByField, orderByDirection);
+          orderByField = getPropertyName(orderBy.getExpression());
+          orderByDirection = (orderBy.getSortOrder() == SortOrder.asc) ? EMPTY :
+              JPQLStatement.DELIMITER.SPACE + "DESC"; //$NON-NLS-1$
+          jpqlOrderByExpression +=
+              tableAlias + JPQLStatement.DELIMITER.PERIOD + orderByField + orderByDirection + " , ";
         } catch (EdmException e) {
           throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.GENERAL.addContent(e.getMessage()), e);
         }
       }
     }
-    return orderByMap;
+    return normalizeOrderByExpression(jpqlOrderByExpression);
+  }
+
+  private static String normalizeOrderByExpression(final String jpqlOrderByExpression) {
+    if (jpqlOrderByExpression != "") {
+      return jpqlOrderByExpression.substring(0, jpqlOrderByExpression.length() - 3);
+    } else {
+      return jpqlOrderByExpression;
+    }
   }
 
   /**
    * This method evaluated the where expression for read of an entity based on the keys specified in the query.
-   * 
+   *
    * @param keyPredicates
    * @return the evaluated where expression
    */
@@ -342,10 +342,13 @@
     }
   }
 
-  public static HashMap<String, String> parseKeyPropertiesToJPAOrderByExpression(
+  public static String parseKeyPropertiesToJPAOrderByExpression(
       final List<EdmProperty> edmPropertylist, final String tableAlias) throws ODataJPARuntimeException {
-    LinkedHashMap<String, String> orderByMap = new LinkedHashMap<String, String>();
     String propertyName = null;
+    String orderExpression = "";
+    if (edmPropertylist == null) {
+      return orderExpression;
+    }
     for (EdmProperty edmProperty : edmPropertylist) {
       try {
         EdmMapping mapping = edmProperty.getMapping();
@@ -357,31 +360,32 @@
       } catch (EdmException e) {
         throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.GENERAL.addContent(e.getMessage()), e);
       }
-      orderByMap.put(tableAlias + JPQLStatement.DELIMITER.PERIOD + propertyName, EMPTY);
+      orderExpression += tableAlias + JPQLStatement.DELIMITER.PERIOD + propertyName + " , ";
     }
-    return orderByMap;
+    return normalizeOrderByExpression(orderExpression);
   }
 
   /**
    * This method evaluates the expression based on the type instance. Used for adding escape characters where necessary.
-   * 
-   * @param value
+   *
+   * @param uriLiteral
    * @param edmSimpleType
    * @return the evaluated expression
    * @throws ODataJPARuntimeException
    */
-  private static String evaluateComparingExpression(String value, final EdmSimpleType edmSimpleType)
+  private static String evaluateComparingExpression(String uriLiteral, final EdmSimpleType edmSimpleType)
       throws ODataJPARuntimeException {
 
-    if (edmSimpleType == EdmSimpleTypeKind.String.getEdmSimpleTypeInstance()
-        || edmSimpleType == EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance()) {
-      value = value.replaceAll("'", "''");
-      value = "\'" + value + "\'"; //$NON-NLS-1$	//$NON-NLS-2$
-    } else if (edmSimpleType == EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance()
-        || edmSimpleType == EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance()) {
+    if (EdmSimpleTypeKind.String.getEdmSimpleTypeInstance().isCompatible(edmSimpleType)
+        || EdmSimpleTypeKind.Guid.getEdmSimpleTypeInstance().isCompatible(edmSimpleType)) {
+      uriLiteral = uriLiteral.replaceAll("'", "''");
+      uriLiteral = "'" + uriLiteral + "'"; //$NON-NLS-1$	//$NON-NLS-2$
+    } else if (EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance().isCompatible(edmSimpleType)
+        || EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance().isCompatible(edmSimpleType)) {
       try {
         Calendar datetime =
-            (Calendar) edmSimpleType.valueOfString(value, EdmLiteralKind.DEFAULT, null, edmSimpleType.getDefaultType());
+            (Calendar) edmSimpleType.valueOfString(uriLiteral, EdmLiteralKind.DEFAULT, null, edmSimpleType
+                .getDefaultType());
 
         String year = String.format("%04d", datetime.get(Calendar.YEAR));
         String month = String.format("%02d", datetime.get(Calendar.MONTH) + 1);
@@ -390,7 +394,7 @@
         String min = String.format("%02d", datetime.get(Calendar.MINUTE));
         String sec = String.format("%02d", datetime.get(Calendar.SECOND));
 
-        value =
+        uriLiteral =
             JPQLStatement.DELIMITER.LEFT_BRACE + JPQLStatement.KEYWORD.TIMESTAMP + JPQLStatement.DELIMITER.SPACE + "\'"
                 + year + JPQLStatement.DELIMITER.HYPHEN + month + JPQLStatement.DELIMITER.HYPHEN + day
                 + JPQLStatement.DELIMITER.SPACE + hour + JPQLStatement.DELIMITER.COLON + min
@@ -401,26 +405,33 @@
         throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.GENERAL.addContent(e.getMessage()), e);
       }
 
-    } else if (edmSimpleType == EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance()) {
+    } else if (EdmSimpleTypeKind.Time.getEdmSimpleTypeInstance().isCompatible(edmSimpleType)) {
       try {
         Calendar time =
-            (Calendar) edmSimpleType.valueOfString(value, EdmLiteralKind.DEFAULT, null, edmSimpleType.getDefaultType());
+            (Calendar) edmSimpleType.valueOfString(uriLiteral, EdmLiteralKind.DEFAULT, null, edmSimpleType
+                .getDefaultType());
 
         String hourValue = String.format("%02d", time.get(Calendar.HOUR_OF_DAY));
         String minValue = String.format("%02d", time.get(Calendar.MINUTE));
         String secValue = String.format("%02d", time.get(Calendar.SECOND));
 
-        value =
+        uriLiteral =
             "\'" + hourValue + JPQLStatement.DELIMITER.COLON + minValue + JPQLStatement.DELIMITER.COLON + secValue
                 + "\'";
       } catch (EdmSimpleTypeException e) {
         throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.GENERAL.addContent(e.getMessage()), e);
       }
 
-    } else if (edmSimpleType == EdmSimpleTypeKind.Int64.getEdmSimpleTypeInstance()) {
-      value = value + JPQLStatement.DELIMITER.LONG; //$NON-NLS-1$
+    } else if (EdmSimpleTypeKind.Int64.getEdmSimpleTypeInstance().isCompatible(edmSimpleType)) {
+      uriLiteral = uriLiteral + JPQLStatement.DELIMITER.LONG; //$NON-NLS-1$
     }
-    return value;
+    return uriLiteral;
   }
 
+  private static String getPropertyName(final CommonExpression whereExpression) throws EdmException {
+    EdmProperty property = ((EdmProperty) ((PropertyExpression) whereExpression).getEdmProperty());
+    EdmMapping mapping = property.getMapping();
+    String name = mapping != null ? mapping.getInternalName() : property.getName();
+    return name;
+  }
 }
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectContext.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectContext.java
index e5d9df8..9812327 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectContext.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectContext.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContext.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContext.java
index 199f05a..56b1686 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContext.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContext.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilder.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilder.java
index 0a9a5b9..3682205 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilder.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilder.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilder.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilder.java
index 40ceeba..246cffb 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilder.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilder.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,9 +18,7 @@
  ******************************************************************************/
 package org.apache.olingo.odata2.jpa.processor.core.jpql;
 
-import java.util.Iterator;
 import java.util.List;
-import java.util.Map.Entry;
 
 import org.apache.olingo.odata2.jpa.processor.api.access.JPAJoinClause;
 import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
@@ -118,23 +116,10 @@
 
     }
 
-    if (context.getOrderByCollection() != null && context.getOrderByCollection().size() > 0) {
+    if (context.getOrderByCollection() != null && context.getOrderByCollection().length() > 0) {
 
       StringBuilder orderByBuilder = new StringBuilder();
-      Iterator<Entry<String, String>> orderItr = context.getOrderByCollection().entrySet().iterator();
-
-      int i = 0;
-
-      while (orderItr.hasNext()) {
-        if (i != 0) {
-          orderByBuilder.append(JPQLStatement.DELIMITER.SPACE).append(JPQLStatement.DELIMITER.COMMA).append(
-              JPQLStatement.DELIMITER.SPACE);
-        }
-        Entry<String, String> entry = orderItr.next();
-        orderByBuilder.append(entry.getKey()).append(JPQLStatement.DELIMITER.SPACE);
-        orderByBuilder.append(entry.getValue());
-        i++;
-      }
+      orderByBuilder.append(context.getOrderByCollection());
       jpqlQuery.append(JPQLStatement.DELIMITER.SPACE).append(JPQLStatement.KEYWORD.ORDERBY).append(
           JPQLStatement.DELIMITER.SPACE);
       jpqlQuery.append(orderByBuilder);
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java
index 4668b7d..34f8655 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContext.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,8 +18,6 @@
  ******************************************************************************/
 package org.apache.olingo.odata2.jpa.processor.core.jpql;
 
-import java.util.HashMap;
-
 import org.apache.olingo.odata2.api.edm.EdmEntityType;
 import org.apache.olingo.odata2.api.edm.EdmException;
 import org.apache.olingo.odata2.api.edm.EdmMapping;
@@ -35,7 +33,7 @@
 public class JPQLSelectContext extends JPQLContext implements JPQLSelectContextView {
 
   protected String selectExpression;
-  protected HashMap<String, String> orderByCollection;
+  protected String orderByCollection;
   protected String whereCondition;
 
   protected boolean isCountOnly = false;// Support for $count
@@ -44,7 +42,7 @@
     this.isCountOnly = isCountOnly;
   }
 
-  protected final void setOrderByCollection(final HashMap<String, String> orderByCollection) {
+  protected final void setOrderByCollection(final String orderByCollection) {
     this.orderByCollection = orderByCollection;
   }
 
@@ -62,7 +60,7 @@
   }
 
   @Override
-  public HashMap<String, String> getOrderByCollection() {
+  public String getOrderByCollection() {
     return orderByCollection;
   }
 
@@ -72,7 +70,7 @@
   }
 
   public class JPQLSelectContextBuilder extends
-      org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext.JPQLContextBuilder {
+  org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext.JPQLContextBuilder {
 
     protected GetEntitySetUriInfo entitySetView;
 
@@ -134,7 +132,7 @@
     /*
      * Generate Order By Clause Fields
      */
-    protected HashMap<String, String> generateOrderByFileds() throws ODataJPARuntimeException, EdmException {
+    protected String generateOrderByFileds() throws ODataJPARuntimeException, EdmException {
 
       if (entitySetView.getOrderBy() != null) {
 
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleContext.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleContext.java
index ac54d2c..99715223 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleContext.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleContext.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -55,7 +55,7 @@
   }
 
   public class JPQLSelectSingleContextBuilder extends
-      org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext.JPQLContextBuilder {
+  org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContext.JPQLContextBuilder {
 
     protected GetEntityUriInfo entityView;
 
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilder.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilder.java
index 4e06b9e..0db1084 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilder.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilder.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilder.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilder.java
index 22dcc9a..49ed28b 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilder.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilder.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,9 +18,6 @@
  ******************************************************************************/
 package org.apache.olingo.odata2.jpa.processor.core.jpql;
 
-import java.util.Iterator;
-import java.util.Map.Entry;
-
 import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
 import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContextType;
 import org.apache.olingo.odata2.jpa.processor.api.jpql.JPQLContextView;
@@ -69,23 +66,10 @@
       jpqlQuery.append(context.getWhereExpression());
     }
 
-    if (context.getOrderByCollection() != null && context.getOrderByCollection().size() > 0) {
+    if (context.getOrderByCollection() != null && context.getOrderByCollection().length() > 0) {
 
       StringBuilder orderByBuilder = new StringBuilder();
-      Iterator<Entry<String, String>> orderItr = context.getOrderByCollection().entrySet().iterator();
-
-      int i = 0;
-
-      while (orderItr.hasNext()) {
-        if (i != 0) {
-          orderByBuilder.append(JPQLStatement.DELIMITER.SPACE).append(JPQLStatement.DELIMITER.COMMA).append(
-              JPQLStatement.DELIMITER.SPACE);
-        }
-        Entry<String, String> entry = orderItr.next();
-        orderByBuilder.append(entry.getKey()).append(JPQLStatement.DELIMITER.SPACE);
-        orderByBuilder.append(entry.getValue());
-        i++;
-      }
+      orderByBuilder.append(context.getOrderByCollection());
       jpqlQuery.append(JPQLStatement.DELIMITER.SPACE);
       jpqlQuery.append(JPQLStatement.KEYWORD.ORDERBY).append(JPQLStatement.DELIMITER.SPACE);
       jpqlQuery.append(orderByBuilder);
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParserTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParserTest.java
deleted file mode 100644
index 3ca93c5..0000000
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataExpressionParserTest.java
+++ /dev/null
@@ -1,515 +0,0 @@
-/*******************************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ******************************************************************************/
-package org.apache.olingo.odata2.jpa.processor.core;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.olingo.odata2.api.edm.EdmException;
-import org.apache.olingo.odata2.api.edm.EdmFacets;
-import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
-import org.apache.olingo.odata2.api.edm.EdmMapping;
-import org.apache.olingo.odata2.api.edm.EdmProperty;
-import org.apache.olingo.odata2.api.edm.EdmSimpleType;
-import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
-import org.apache.olingo.odata2.api.edm.EdmTypeKind;
-import org.apache.olingo.odata2.api.edm.EdmTyped;
-import org.apache.olingo.odata2.api.exception.ODataException;
-import org.apache.olingo.odata2.api.uri.KeyPredicate;
-import org.apache.olingo.odata2.api.uri.expression.BinaryExpression;
-import org.apache.olingo.odata2.api.uri.expression.BinaryOperator;
-import org.apache.olingo.odata2.api.uri.expression.CommonExpression;
-import org.apache.olingo.odata2.api.uri.expression.ExpressionKind;
-import org.apache.olingo.odata2.api.uri.expression.FilterExpression;
-import org.apache.olingo.odata2.api.uri.expression.LiteralExpression;
-import org.apache.olingo.odata2.api.uri.expression.MemberExpression;
-import org.apache.olingo.odata2.api.uri.expression.MethodExpression;
-import org.apache.olingo.odata2.api.uri.expression.MethodOperator;
-import org.apache.olingo.odata2.api.uri.expression.PropertyExpression;
-import org.apache.olingo.odata2.api.uri.expression.UnaryExpression;
-import org.apache.olingo.odata2.api.uri.expression.UnaryOperator;
-import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
-import org.apache.olingo.odata2.jpa.processor.core.common.ODataJPATestConstants;
-import org.easymock.EasyMock;
-import org.junit.Test;
-
-public class ODataExpressionParserTest {
-
-  private static final String EXPECTED_STR_1 = "(gwt1.SalesOrder = 1234)";
-  private static final String EXPECTED_STR_2 = "((gwt1.SalesOrder >= 1234) AND (gwt1.SalesABC <> XYZ))";
-  private static final String EXPECTED_STR_3 = "((gwt1.SalesOrder >= 1234) OR (gwt1.SalesABC <> XYZ))";
-  private static final String EXPECTED_STR_4 = "((gwt1.SalesOrder < 1234) AND (gwt1.SalesABC <= XYZ))";
-  private static final String EXPECTED_STR_5 = "((gwt1.LineItems > 2345) AND (gwt1.SalesOrder >= Amazon))";
-  private static final String EXPECTED_STR_6 = "(gwt1.Address.city = \'City_3\')";
-  private static final String EXPECTED_STR_7 = "(gwt1.Address.city.area = \'BTM\')";
-  private static final String EXPECTED_STR_8 = "gwt1.field1 = 1 AND gwt1.field2 = 'abc'";
-  private static final String EXPECTED_STR_9 = "gwt1.BuyerAddress, gwt1.BuyerName, gwt1.BuyerId";
-  private static final String EXPECTED_STR_10 = "gwt1.SalesOrder";
-  private static final String EXPECTED_STR_11 = "NOT(gwt1.deliveryStatus)";
-  private static final String EXPECTED_STR_12 =
-      "((CASE WHEN (gwt1.currencyCode LIKE '%Ru%') THEN TRUE ELSE FALSE END) = true)";
-  private static final String EXPECTED_STR_13 = "(SUBSTRING(gwt1.currencyCode, 1 + 1 , 2) = 'NR')";
-  private static final String EXPECTED_STR_14 = "(LOWER(gwt1.currencyCode) = 'inr rupees')";
-  private static final String EXPECTED_STR_15 =
-      "((CASE WHEN (LOWER(gwt1.currencyCode) LIKE '%nr rupees%') THEN TRUE ELSE FALSE END) = true)";
-  private static final String EXPECTED_STR_16 =
-      "(CASE WHEN (gwt1.currencyCode LIKE '%INR%') THEN TRUE ELSE FALSE END) = true";
-  private static final String EXPECTED_STR_17 =
-      "(CASE WHEN (LOWER(gwt1.currencyCode) LIKE '%nr rupees%') THEN TRUE ELSE FALSE END) = true";
-
-  private static final String ADDRESS = "Address";
-  private static final String CITY = "city";
-  private static final String AREA = "area";
-  private static final String SALES_ORDER = "SalesOrder";
-  private static final String SALES_ABC = "SalesABC";
-  private static final String SAMPLE_DATA_1 = "1234";
-  private static final String SAMPLE_DATA_2 = "2345";
-  private static final String SAMPLE_DATA_XYZ = "XYZ";
-  private static final String SAMPLE_DATA_BTM = "\'BTM\'";
-  private static final String SAMPLE_DATA_CITY_3 = "\'City_3\'";
-  private static final String SAMPLE_DATA_LINE_ITEMS = "LineItems";
-  private static final String SAMPLE_DATA_AMAZON = "Amazon";
-  private static final String SAMPLE_DATA_FIELD1 = "field1";
-  private static final String SAMPLE_DATA_FIELD2 = "field2";
-
-  private static final String TABLE_ALIAS = "gwt1"; //$NON-NLS-1$
-
-  @Test
-  public void testParseWhereExpression() {
-    try {
-      String parsedStr = ODataJPATestConstants.EMPTY_STRING;
-      // Simple Binary query -
-      parsedStr =
-          ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpressionMockedObj(BinaryOperator.EQ,
-              ExpressionKind.PROPERTY, SALES_ORDER, SAMPLE_DATA_1), TABLE_ALIAS);
-
-      assertEquals(EXPECTED_STR_1, parsedStr);
-      // complex query -
-      parsedStr = ODataJPATestConstants.EMPTY_STRING;
-
-      CommonExpression exp1 =
-          getBinaryExpressionMockedObj(BinaryOperator.GE, ExpressionKind.PROPERTY, SALES_ORDER, SAMPLE_DATA_1);
-      CommonExpression exp2 =
-          getBinaryExpressionMockedObj(BinaryOperator.NE, ExpressionKind.PROPERTY, SALES_ABC, SAMPLE_DATA_XYZ);
-      parsedStr =
-          ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpression(exp1, BinaryOperator.AND, exp2),
-              TABLE_ALIAS);
-      assertEquals(EXPECTED_STR_2, parsedStr);
-    } catch (EdmException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    } catch (ODataException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-  }
-
-  @Test
-  public void testMoreThanOneBinaryExpression() {
-    // complex query -
-    String parsedStr = ODataJPATestConstants.EMPTY_STRING;
-    CommonExpression exp1 =
-        getBinaryExpressionMockedObj(BinaryOperator.GE, ExpressionKind.PROPERTY, SALES_ORDER, SAMPLE_DATA_1);
-    CommonExpression exp2 =
-        getBinaryExpressionMockedObj(BinaryOperator.NE, ExpressionKind.PROPERTY, SALES_ABC, SAMPLE_DATA_XYZ);
-    try {
-      parsedStr =
-          ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpression(exp1, BinaryOperator.AND, exp2),
-              TABLE_ALIAS);
-      assertEquals(EXPECTED_STR_2, parsedStr);
-      parsedStr =
-          ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpression(exp1, BinaryOperator.OR, exp2),
-              TABLE_ALIAS);
-    } catch (ODataException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-    assertEquals(EXPECTED_STR_3, parsedStr);
-  }
-
-  @Test
-  public void testParseFilterExpression() {
-    try {
-      assertEquals(EXPECTED_STR_10, ODataExpressionParser.parseToJPAWhereExpression(getFilterExpressionMockedObj(
-          ExpressionKind.PROPERTY, SALES_ORDER), TABLE_ALIAS));
-    } catch (ODataException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-  }
-
-  @Test
-  public void testAllBinaryOperators() { // Test for all Binary Operators
-    // complex query -
-    String parsedStr1 = ODataJPATestConstants.EMPTY_STRING;
-    String parsedStr2 = ODataJPATestConstants.EMPTY_STRING;
-
-    CommonExpression exp1 =
-        getBinaryExpressionMockedObj(BinaryOperator.LT, ExpressionKind.PROPERTY, SALES_ORDER, SAMPLE_DATA_1);
-    CommonExpression exp2 =
-        getBinaryExpressionMockedObj(BinaryOperator.LE, ExpressionKind.PROPERTY, SALES_ABC, SAMPLE_DATA_XYZ);
-
-    try {
-      parsedStr1 =
-          ODataExpressionParser.parseToJPAWhereExpression((BinaryExpression) getBinaryExpression(exp1,
-              BinaryOperator.AND, exp2), TABLE_ALIAS);
-      assertEquals(EXPECTED_STR_4, parsedStr1);
-
-      CommonExpression exp3 =
-          getBinaryExpressionMockedObj(BinaryOperator.GT, ExpressionKind.PROPERTY, SAMPLE_DATA_LINE_ITEMS,
-              SAMPLE_DATA_2);
-      CommonExpression exp4 =
-          getBinaryExpressionMockedObj(BinaryOperator.GE, ExpressionKind.PROPERTY, SALES_ORDER, SAMPLE_DATA_AMAZON);
-
-      parsedStr2 =
-          ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpression(exp3, BinaryOperator.AND, exp4),
-              TABLE_ALIAS);
-
-    } catch (ODataException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-    assertEquals(EXPECTED_STR_5, parsedStr2);
-  }
-
-  @Test
-  public void testParseMemberExpression() {
-    try {
-      assertEquals(EXPECTED_STR_6, ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpression(
-          getMemberExpressionMockedObj(ADDRESS, CITY), BinaryOperator.EQ,
-          getLiteralExpressionMockedObj(SAMPLE_DATA_CITY_3)), TABLE_ALIAS));
-      assertEquals(EXPECTED_STR_7, ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpression(
-          getMultipleMemberExpressionMockedObj(ADDRESS, CITY, AREA), BinaryOperator.EQ,
-          getLiteralExpressionMockedObj(SAMPLE_DATA_BTM)), TABLE_ALIAS));
-    } catch (ODataException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-  }
-
-  @Test
-  public void testParseMethodExpression() {
-    try {
-      assertEquals(EXPECTED_STR_12, ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpression(
-          getMethodExpressionMockedObj(MethodOperator.SUBSTRINGOF, "'Ru'", "currencyCode", null, 2), BinaryOperator.EQ,
-          getLiteralExpressionMockedObj("true")), TABLE_ALIAS));
-      assertEquals(EXPECTED_STR_13, ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpression(
-          getMethodExpressionMockedObj(MethodOperator.SUBSTRING, "currencyCode", "1", "2", 3), BinaryOperator.EQ,
-          getLiteralExpressionMockedObj("'NR'")), TABLE_ALIAS));
-      assertEquals(EXPECTED_STR_14, ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpression(
-          getMethodExpressionMockedObj(MethodOperator.TOLOWER, "currencyCode", null, null, 1), BinaryOperator.EQ,
-          getLiteralExpressionMockedObj("'inr rupees'")), TABLE_ALIAS));
-      assertEquals(EXPECTED_STR_15, ODataExpressionParser.parseToJPAWhereExpression(getBinaryExpression(
-          getMultipleMethodExpressionMockedObj(MethodOperator.SUBSTRINGOF, "'nr rupees'", MethodOperator.TOLOWER,
-              "currencyCode", 2, 1), BinaryOperator.EQ, getLiteralExpressionMockedObj("true")), TABLE_ALIAS));
-      assertEquals(EXPECTED_STR_16, ODataExpressionParser.parseToJPAWhereExpression(
-          getFilterExpressionForFunctionsMockedObj(MethodOperator.SUBSTRINGOF, "'INR'", null, "currencyCode", 2, null)
-          /*
-           * getBinaryExpression(
-           * getMemberExpressionMockedObj(ADDRESS,
-           * CITY),
-           * BinaryOperator.EQ,
-           * getLiteralExpressionMockedObj(SAMPLE_DATA_CITY_3))
-           */, TABLE_ALIAS));
-      assertEquals(EXPECTED_STR_17, ODataExpressionParser.parseToJPAWhereExpression(
-          getFilterExpressionForFunctionsMockedObj(MethodOperator.SUBSTRINGOF, "'nr rupees'", MethodOperator.TOLOWER,
-              "currencyCode", 2, 1)
-          /*
-           * getBinaryExpression(
-           * getMemberExpressionMockedObj(ADDRESS,
-           * CITY),
-           * BinaryOperator.EQ,
-           * getLiteralExpressionMockedObj(SAMPLE_DATA_CITY_3))
-           */, TABLE_ALIAS));
-
-    } catch (ODataException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-  }
-
-  private CommonExpression getMethodExpressionMockedObj(final MethodOperator methodOperator, final String firstName,
-      final String secondName, final String thirdName, final Integer parameterCount) {
-
-    List<CommonExpression> parameters = new ArrayList<CommonExpression>();
-
-    if (methodOperator == MethodOperator.SUBSTRINGOF) {
-      parameters.add(getLiteralExpressionMockedObj(firstName));
-      parameters.add(getPropertyExpressionMockedObj(ExpressionKind.PROPERTY, secondName));
-    } else if (methodOperator == MethodOperator.SUBSTRING) {
-      parameters.add(getPropertyExpressionMockedObj(ExpressionKind.PROPERTY, firstName));
-      parameters.add(getLiteralExpressionMockedObj(secondName));
-      parameters.add(getLiteralExpressionMockedObj(thirdName));
-    } else if (methodOperator == MethodOperator.TOLOWER) {
-      parameters.add(getPropertyExpressionMockedObj(ExpressionKind.PROPERTY, firstName));
-    }
-
-    MethodExpression methodExpression = EasyMock.createMock(MethodExpression.class);
-
-    EasyMock.expect(methodExpression.getKind()).andStubReturn(ExpressionKind.METHOD);
-    EasyMock.expect(methodExpression.getMethod()).andStubReturn(methodOperator);
-    EasyMock.expect(methodExpression.getParameterCount()).andStubReturn(parameterCount);
-    EasyMock.expect(methodExpression.getParameters()).andStubReturn(parameters);
-    EasyMock.replay(methodExpression);
-
-    return methodExpression;
-  }
-
-  private CommonExpression getMultipleMethodExpressionMockedObj(final MethodOperator methodOperator1,
-      final String firstName, final MethodOperator methodOperator2, final String secondName,
-      final Integer parameterCount1, final Integer parameterCount2) {
-
-    // complex query
-    List<CommonExpression> parameters = new ArrayList<CommonExpression>();
-
-    parameters.add(getLiteralExpressionMockedObj(firstName));
-    parameters.add(getMethodExpressionMockedObj(methodOperator2, secondName, null, null, 1));
-
-    MethodExpression methodExpression = EasyMock.createMock(MethodExpression.class);
-
-    EasyMock.expect(methodExpression.getKind()).andStubReturn(ExpressionKind.METHOD);
-    EasyMock.expect(methodExpression.getMethod()).andStubReturn(methodOperator1);
-    EasyMock.expect(methodExpression.getParameterCount()).andStubReturn(parameterCount1);
-    EasyMock.expect(methodExpression.getParameters()).andStubReturn(parameters);
-    EasyMock.replay(methodExpression);
-
-    return methodExpression;
-  }
-
-  private CommonExpression getMultipleMemberExpressionMockedObj(final String string1, final String string2,
-      final String string3) {
-
-    MemberExpression memberExpression = EasyMock.createMock(MemberExpression.class);
-
-    EasyMock.expect(memberExpression.getPath()).andStubReturn(getMemberExpressionMockedObj(string1, string2));
-    EasyMock.expect(memberExpression.getProperty()).andStubReturn(
-        getPropertyExpressionMockedObj(ExpressionKind.PROPERTY, string3));
-    EasyMock.expect(memberExpression.getKind()).andStubReturn(ExpressionKind.MEMBER);
-    EasyMock.replay(memberExpression);
-
-    return memberExpression;
-  }
-
-  @Test
-  public void testParseUnaryExpression() {
-
-    UnaryExpression unaryExpression =
-        getUnaryExpressionMockedObj(getPropertyExpressionMockedObj(ExpressionKind.PROPERTY, "deliveryStatus"),
-            org.apache.olingo.odata2.api.uri.expression.UnaryOperator.NOT);
-    try {
-      assertEquals(EXPECTED_STR_11, ODataExpressionParser.parseToJPAWhereExpression(unaryExpression, TABLE_ALIAS));
-    } catch (ODataException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-
-  }
-
-  private UnaryExpression
-      getUnaryExpressionMockedObj(final CommonExpression operand, final UnaryOperator unaryOperator) {
-    UnaryExpression unaryExpression = EasyMock.createMock(UnaryExpression.class);
-    EasyMock.expect(unaryExpression.getKind()).andStubReturn(ExpressionKind.UNARY);
-    EasyMock.expect(unaryExpression.getOperand()).andStubReturn(operand);
-    EasyMock.expect(unaryExpression.getOperator()).andStubReturn(unaryOperator);
-
-    EasyMock.replay(unaryExpression);
-    return unaryExpression;
-  }
-
-  private CommonExpression getMemberExpressionMockedObj(final String pathUriLiteral, final String propertyUriLiteral) {
-    MemberExpression memberExpression = EasyMock.createMock(MemberExpression.class);
-    EasyMock.expect(memberExpression.getPath()).andStubReturn(
-        getPropertyExpressionMockedObj(ExpressionKind.PROPERTY, pathUriLiteral));
-    EasyMock.expect(memberExpression.getProperty()).andStubReturn(
-        getPropertyExpressionMockedObj(ExpressionKind.PROPERTY, propertyUriLiteral));
-    EasyMock.expect(memberExpression.getKind()).andStubReturn(ExpressionKind.MEMBER);
-
-    EasyMock.replay(memberExpression);
-    return memberExpression;
-  }
-
-  private LiteralExpression getLiteralExpressionMockedObj(final String uriLiteral) {
-    LiteralExpression rightOperandLiteralExpresion = EasyMock.createMock(LiteralExpression.class);
-    EasyMock.expect(rightOperandLiteralExpresion.getKind()).andStubReturn(ExpressionKind.LITERAL);
-    EasyMock.expect(rightOperandLiteralExpresion.getUriLiteral()).andStubReturn(uriLiteral);// SAMPLE_DATA
-    EasyMock.expect(rightOperandLiteralExpresion.getEdmType()).andStubReturn(getEdmSimpleTypeMockedObj(uriLiteral));
-    EasyMock.replay(rightOperandLiteralExpresion);
-    return rightOperandLiteralExpresion;
-
-  }
-
-  private EdmSimpleType getEdmSimpleTypeMockedObj(final String value) {
-    EdmSimpleType edmSimpleType = EasyMock.createMock(EdmSimpleType.class);
-    try {
-      EasyMock.expect(edmSimpleType.getName()).andReturn(value);
-      EasyMock.expect(edmSimpleType.getKind()).andStubReturn(EdmTypeKind.SIMPLE);
-      EasyMock.expect(edmSimpleType.valueOfString(value, EdmLiteralKind.URI, getEdmFacetsMockedObj(), null))
-          .andStubReturn(value);
-      EasyMock.expect(edmSimpleType.valueOfString(value, EdmLiteralKind.URI, null, null)).andStubReturn(value);
-      EasyMock.expect(edmSimpleType.valueToString(value, EdmLiteralKind.DEFAULT, getEdmFacetsMockedObj()))
-          .andStubReturn(value);
-      EasyMock.expect(edmSimpleType.valueToString(value, EdmLiteralKind.DEFAULT, null)).andStubReturn(value);
-    } catch (EdmException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-    EasyMock.expect(edmSimpleType.getDefaultType()).andStubReturn(null);
-    EasyMock.replay(edmSimpleType);
-    return edmSimpleType;
-  }
-
-  private EdmFacets getEdmFacetsMockedObj() {
-    EdmFacets facets = EasyMock.createMock(EdmFacets.class);
-
-    EasyMock.replay(facets);
-    return facets;
-  }
-
-  private PropertyExpression getPropertyExpressionMockedObj(final ExpressionKind expKind, final String propertyName) {
-    PropertyExpression leftOperandPropertyExpresion = EasyMock.createMock(PropertyExpression.class);
-    EasyMock.expect(leftOperandPropertyExpresion.getKind()).andStubReturn(ExpressionKind.PROPERTY);
-    EasyMock.expect(leftOperandPropertyExpresion.getPropertyName()).andStubReturn(propertyName);
-    EasyMock.expect(leftOperandPropertyExpresion.getEdmProperty()).andStubReturn(getEdmTypedMockedObj(propertyName));
-    EasyMock.replay(leftOperandPropertyExpresion);
-    return leftOperandPropertyExpresion;
-  }
-
-  private EdmTyped getEdmTypedMockedObj(final String propertyName) {
-    EdmProperty mockedEdmProperty = EasyMock.createMock(EdmProperty.class);
-    try {
-      EasyMock.expect(mockedEdmProperty.getMapping()).andStubReturn(getEdmMappingMockedObj(propertyName));
-      EasyMock.replay(mockedEdmProperty);
-    } catch (EdmException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-    return mockedEdmProperty;
-  }
-
-  private EdmMapping getEdmMappingMockedObj(final String propertyName) {
-    EdmMapping mockedEdmMapping = EasyMock.createMock(EdmMapping.class);
-    EasyMock.expect(mockedEdmMapping.getInternalName()).andStubReturn(propertyName);
-    EasyMock.replay(mockedEdmMapping);
-    return mockedEdmMapping;
-  }
-
-  private BinaryExpression getBinaryExpressionMockedObj(final BinaryOperator operator,
-      final ExpressionKind leftOperandExpKind, final String propertyName, final String literalStr) {
-    BinaryExpression binaryExpression = EasyMock.createMock(BinaryExpression.class);
-    EasyMock.expect(binaryExpression.getKind()).andStubReturn(ExpressionKind.BINARY);
-    EasyMock.expect(binaryExpression.getLeftOperand()).andStubReturn(
-        getPropertyExpressionMockedObj(leftOperandExpKind, propertyName));
-    EasyMock.expect(binaryExpression.getOperator()).andStubReturn(operator);
-    EasyMock.expect(binaryExpression.getRightOperand()).andStubReturn(getLiteralExpressionMockedObj(literalStr));
-
-    EasyMock.replay(binaryExpression);
-    return binaryExpression;
-  }
-
-  private FilterExpression getFilterExpressionMockedObj(final ExpressionKind leftOperandExpKind,
-      final String propertyName) {
-    FilterExpression filterExpression = EasyMock.createMock(FilterExpression.class);
-    EasyMock.expect(filterExpression.getKind()).andStubReturn(ExpressionKind.FILTER);
-    EasyMock.expect(filterExpression.getExpression()).andStubReturn(
-        getPropertyExpressionMockedObj(leftOperandExpKind, propertyName));
-
-    EasyMock.replay(filterExpression);
-    return filterExpression;
-  }
-
-  private FilterExpression getFilterExpressionForFunctionsMockedObj(final MethodOperator methodOperator1,
-      final String firstName, final MethodOperator methodOperator2, final String secondName,
-      final Integer parameterCount1, final Integer parameterCount2) {
-    // default value handling of SUBSTRINGOF
-    FilterExpression filterExpression = EasyMock.createMock(FilterExpression.class);
-    EasyMock.expect(filterExpression.getKind()).andStubReturn(ExpressionKind.FILTER);
-    if ((methodOperator2 != null) && (parameterCount2 != null)) {
-      EasyMock.expect(filterExpression.getExpression()).andStubReturn(
-          getMultipleMethodExpressionMockedObj(methodOperator1, firstName, methodOperator2, secondName,
-              parameterCount1, parameterCount2));
-    } else {
-      EasyMock.expect(filterExpression.getExpression()).andStubReturn(
-          getMethodExpressionMockedObj(methodOperator1, firstName, secondName, null, parameterCount1));
-    }
-
-    EasyMock.replay(filterExpression);
-    return filterExpression;
-  }
-
-  private CommonExpression getBinaryExpression(final CommonExpression leftOperand, final BinaryOperator operator,
-      final CommonExpression rightOperand) {
-    BinaryExpression binaryExpression = EasyMock.createMock(BinaryExpression.class);
-    EasyMock.expect(binaryExpression.getKind()).andStubReturn(ExpressionKind.BINARY);
-    EasyMock.expect(binaryExpression.getLeftOperand()).andStubReturn(leftOperand);
-    EasyMock.expect(binaryExpression.getRightOperand()).andStubReturn(rightOperand);
-    EasyMock.expect(binaryExpression.getOperator()).andStubReturn(operator);
-
-    EasyMock.replay(binaryExpression);
-    return binaryExpression;
-  }
-
-  @Test
-  public void testParseKeyPredicates() {
-    // Setting up the expected value
-    KeyPredicate keyPredicate1 = EasyMock.createMock(KeyPredicate.class);
-    EdmProperty kpProperty1 = EasyMock.createMock(EdmProperty.class);
-    EasyMock.expect(keyPredicate1.getLiteral()).andStubReturn("1");
-    KeyPredicate keyPredicate2 = EasyMock.createMock(KeyPredicate.class);
-    EdmProperty kpProperty2 = EasyMock.createMock(EdmProperty.class);
-    EasyMock.expect(keyPredicate2.getLiteral()).andStubReturn("abc");
-    EdmMapping edmMapping = EasyMock.createMock(EdmMapping.class);
-    try {
-      EasyMock.expect(kpProperty1.getName()).andStubReturn(SAMPLE_DATA_FIELD1);
-      EasyMock.expect(kpProperty1.getType()).andStubReturn(EdmSimpleTypeKind.Int32.getEdmSimpleTypeInstance());
-      EasyMock.expect(kpProperty2.getName()).andStubReturn(SAMPLE_DATA_FIELD2);
-      EasyMock.expect(kpProperty2.getType()).andStubReturn(EdmSimpleTypeKind.String.getEdmSimpleTypeInstance());
-      EasyMock.expect(keyPredicate1.getProperty()).andStubReturn(kpProperty1);
-      EasyMock.expect(kpProperty1.getMapping()).andReturn(edmMapping);
-      EasyMock.expect(edmMapping.getInternalName()).andReturn(SAMPLE_DATA_FIELD1);
-      EasyMock.expect(keyPredicate2.getProperty()).andStubReturn(kpProperty2);
-      EasyMock.expect(kpProperty2.getMapping()).andReturn(edmMapping);
-    } catch (EdmException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-    EasyMock.expect(edmMapping.getInternalName()).andReturn(SAMPLE_DATA_FIELD2);
-    EasyMock.replay(edmMapping);
-    EasyMock.replay(kpProperty1, keyPredicate1, kpProperty2, keyPredicate2);
-
-    ArrayList<KeyPredicate> keyPredicates = new ArrayList<KeyPredicate>();
-    keyPredicates.add(keyPredicate1);
-    keyPredicates.add(keyPredicate2);
-    String str = null;
-
-    try {
-      str = ODataExpressionParser.parseKeyPredicates(keyPredicates, TABLE_ALIAS);
-    } catch (ODataJPARuntimeException e) {
-      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
-    }
-
-    assertEquals(EXPECTED_STR_8, str);
-  }
-
-  @Test
-  public void testParseToJPASelectExpression() {
-
-    ArrayList<String> selectedFields = new ArrayList<String>();
-    selectedFields.add("BuyerAddress");
-    selectedFields.add("BuyerName");
-    selectedFields.add("BuyerId");
-
-    assertEquals(EXPECTED_STR_9, ODataExpressionParser.parseToJPASelectExpression(TABLE_ALIAS, selectedFields));
-    assertEquals(TABLE_ALIAS, ODataExpressionParser.parseToJPASelectExpression(TABLE_ALIAS, null));
-
-    selectedFields.clear();
-    assertEquals(TABLE_ALIAS, ODataExpressionParser.parseToJPASelectExpression(TABLE_ALIAS, selectedFields));
-  }
-}
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataFilterExpressionParserTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataFilterExpressionParserTest.java
new file mode 100644
index 0000000..33419d5
--- /dev/null
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataFilterExpressionParserTest.java
@@ -0,0 +1,228 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.jpa.processor.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.InputStream;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.ep.EntityProvider;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.exception.ODataMessageException;
+import org.apache.olingo.odata2.api.uri.UriParser;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionParserException;
+import org.apache.olingo.odata2.api.uri.expression.FilterExpression;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ODataFilterExpressionParserTest {
+  private static final short INPUT = 0;
+  private static final short OUTPUT = 1;
+  private static final String TABLE_ALIAS = "E1";
+  private static final String NAMESPACE = "SalesOrderProcessing";
+  private static final String ENTITY_NOTE = "Note";
+  // Index 0 - Is test input and Index 1 - Is expected output
+  private static final String[] EXPRESSION_EQ = { "id eq '123'", "(E1.id = '123')" };
+  private static final String[] EXPRESSION_NE = { "id ne '123'", "(E1.id <> '123')" };
+  private static final String[] EXPRESSION_ESCAPE = { "id ne '123''22'", "(E1.id <> '123''22')" };
+  private static final String[] EXPRESSION_BINARY_AND =
+  {
+      "id le '123' and soId eq 123L and not (substringof(id,'123') eq false) eq true",
+      "(((E1.id <= '123') AND (E1.soId = 123L)) AND (NOT(((CASE WHEN ('123' LIKE CONCAT('%',E1.id,'%')) "
+          + "THEN TRUE ELSE FALSE END) = false)) = true))" };
+  private static final String[] EXPRESSION_BINARY_OR = { "id ge '123' or soId gt 123L",
+      "((E1.id >= '123') OR (E1.soId > 123L))" };
+  private static final String[] EXPRESSION_MEMBER_OR = { "id lt '123' or oValue/Currency eq 'INR'",
+      "((E1.id < '123') OR (E1.oValue.Currency = 'INR'))" };
+  private static final String[] EXPRESSION_STARTS_WITH = { "startswith(oValue/Currency,'INR')",
+      "E1.oValue.Currency LIKE CONCAT('INR','%')" };
+  private static final String[] EXPRESSION_STARTS_WITH_EQUAL = { "startswith(oValue/Currency,'INR') eq true",
+      "(E1.oValue.Currency LIKE CONCAT('INR','%') )" };
+  private static final String[] EXPRESSION_NOT_STARTS_WITH = { "startswith(oValue/Currency,'INR') eq false",
+      "(E1.oValue.Currency NOT LIKE CONCAT('INR','%') )" };
+  private static final String[] EXPRESSION_NOT_ENDS_WITH = { "endswith(oValue/Currency,tolower('INR')) eq false",
+      "(E1.oValue.Currency NOT LIKE CONCAT('%',LOWER('INR')) )" };
+  private static final String[] EXPRESSION_NESTED_METHOD = {
+      "endswith(substring(oValue/Currency,2),'INR') eq false",
+      "(SUBSTRING(E1.oValue.Currency, 2L + 1 ) NOT LIKE CONCAT('%','INR') )" };
+  private static final String[] EXPRESSION_SUBSTRING_OF = {
+      "substringof(id,'123') ne true",
+      "((CASE WHEN ('123' LIKE CONCAT('%',E1.id,'%')) THEN TRUE ELSE FALSE END) <> true)" };
+  private static final String[] EXPRESSION_STARTS_WITH_WRONG_OP = { "startswith(oValue/Currency,'INR') lt true", "" };
+  private static final String[] EXPRESSION_SUBSTRING_ALL_OP = { "substring(oValue/Currency,1,3) eq 'INR'",
+      "(SUBSTRING(E1.oValue.Currency, 1L + 1 , 3L) = 'INR')" };
+  private static final String[] EXPRESSION_SUBSTRINGOF_INJECTION1 = {
+      "substringof('a'' OR 1=1 OR E1.id LIKE ''b',id) eq true",
+      "((CASE WHEN (E1.id LIKE CONCAT('%','a'' OR 1=1 OR E1.id LIKE ''b','%')) THEN TRUE ELSE FALSE END) = true)" };
+  private static final String[] EXPRESSION_SUBSTRINGOF_INJECTION2 =
+  {
+      "substringof('substringof(''a'' OR 1=1 OR E1.id LIKE ''b'',id)',id) eq true",
+      "((CASE WHEN (E1.id LIKE CONCAT('%','substringof(''a'' OR 1=1 OR E1.id LIKE ''b'',id)','%')) "
+          + "THEN TRUE ELSE FALSE END) = true)" };
+  private static final String[] EXPRESSION_SUBSTRINGOF_INJECTION3 =
+  {
+      "substringof( substring(' ) OR execute_my_sql OR '' LIKE ',3),'de''') eq true",
+      "((CASE WHEN ('de''' LIKE CONCAT('%',SUBSTRING(' ) OR execute_my_sql OR '' LIKE ', 3L + 1 ),'%')) "
+          + "THEN TRUE ELSE FALSE END) = true)" };
+  private static final String[] EXPRESSION_ENDSWITH_INJECTION1 = { "endswith(id,'Str''eet') eq true",
+      "(E1.id LIKE CONCAT('%','Str''eet') )" };
+  private static final String[] EXPRESSION_PRECEDENCE = {
+      "id eq '123' and id ne '123' or (id eq '123' and id ne '123')",
+      "(((E1.id = '123') AND (E1.id <> '123')) OR ((E1.id = '123') AND (E1.id <> '123')))" };
+  private static final String[] EXPRESSION_DATETIME = { "date eq datetime'2000-01-01T00:00:00'",
+      "(E1.date = {ts '2000-01-01 00:00:00.000'})" };
+  private static Edm edm = null;
+
+  @BeforeClass
+  public static void setup() {
+    InputStream metadataStream =
+        ODataFilterExpressionParserTest.class.getClassLoader().getResourceAsStream("metadata.xml");
+    try {
+      edm = EntityProvider.readMetadata(metadataStream, true);
+    } catch (EntityProviderException e) {
+      fail("Not expected");
+    }
+  }
+
+  @Test
+  public void testDateTime() {
+    assertEquals(EXPRESSION_DATETIME[OUTPUT], parseWhereExpression(
+        EXPRESSION_DATETIME[INPUT], false));
+  }
+
+  @Test
+  public void testPrecedence() {
+    assertEquals(EXPRESSION_PRECEDENCE[OUTPUT], parseWhereExpression(
+        EXPRESSION_PRECEDENCE[INPUT], false));
+  }
+
+  @Test
+  public void testSubStringOfSQLInjection() {
+    assertEquals(EXPRESSION_SUBSTRINGOF_INJECTION1[OUTPUT], parseWhereExpression(
+        EXPRESSION_SUBSTRINGOF_INJECTION1[INPUT], false));
+    assertEquals(EXPRESSION_SUBSTRINGOF_INJECTION2[OUTPUT], parseWhereExpression(
+        EXPRESSION_SUBSTRINGOF_INJECTION2[INPUT], false));
+    assertEquals(EXPRESSION_SUBSTRINGOF_INJECTION3[OUTPUT], parseWhereExpression(
+        EXPRESSION_SUBSTRINGOF_INJECTION3[INPUT], false));
+  }
+
+  @Test
+  public void testEndsWithSQLInjection() {
+    assertEquals(EXPRESSION_ENDSWITH_INJECTION1[OUTPUT], parseWhereExpression(
+        EXPRESSION_ENDSWITH_INJECTION1[INPUT], false));
+  }
+
+  @Test
+  public void testSubStringWithAllOperator() {
+    assertEquals(EXPRESSION_SUBSTRING_ALL_OP[OUTPUT], parseWhereExpression(EXPRESSION_SUBSTRING_ALL_OP[INPUT], false));
+  }
+
+  @Test
+  public void testStartsWithWrongOperator() {
+    parseWhereExpression(EXPRESSION_STARTS_WITH_WRONG_OP[INPUT], true);
+  }
+
+  @Test
+  public void testSubStringOf() {
+    assertEquals(EXPRESSION_SUBSTRING_OF[OUTPUT], parseWhereExpression(EXPRESSION_SUBSTRING_OF[INPUT], false));
+  }
+
+  @Test
+  public void testStartsWithEqual() {
+    assertEquals(EXPRESSION_STARTS_WITH_EQUAL[OUTPUT], parseWhereExpression(EXPRESSION_STARTS_WITH_EQUAL[INPUT],
+        false));
+  }
+
+  @Test
+  public void testEscapeCharacters() {
+    assertEquals(EXPRESSION_ESCAPE[OUTPUT], parseWhereExpression(EXPRESSION_ESCAPE[INPUT], false));
+  }
+
+  @Test
+  public void testNotEndsWithToLowerMethod() {
+    assertEquals(EXPRESSION_NOT_ENDS_WITH[OUTPUT], parseWhereExpression(EXPRESSION_NOT_ENDS_WITH[INPUT], false));
+  }
+
+  @Test
+  public void testNestedMethod() {
+    assertEquals(EXPRESSION_NESTED_METHOD[OUTPUT], parseWhereExpression(EXPRESSION_NESTED_METHOD[INPUT], false));
+  }
+
+  @Test
+  public void testNotStartsWith() {
+    assertEquals(EXPRESSION_NOT_STARTS_WITH[OUTPUT], parseWhereExpression(EXPRESSION_NOT_STARTS_WITH[INPUT], false));
+  }
+
+  @Test
+  public void testStartsWith() {
+    assertEquals(EXPRESSION_STARTS_WITH[OUTPUT], parseWhereExpression(EXPRESSION_STARTS_WITH[INPUT], false));
+  }
+
+  @Test
+  public void testSimpleEqRelation() {
+    assertEquals(EXPRESSION_EQ[OUTPUT], parseWhereExpression(EXPRESSION_EQ[INPUT], false));
+  }
+
+  @Test
+  public void testSimpleNeRelation() {
+    assertEquals(EXPRESSION_NE[OUTPUT], parseWhereExpression(EXPRESSION_NE[INPUT], false));
+  }
+
+  @Test
+  public void testBinaryAnd() {
+    assertEquals(EXPRESSION_BINARY_AND[OUTPUT], parseWhereExpression(EXPRESSION_BINARY_AND[INPUT], false));
+  }
+
+  @Test
+  public void testBinaryOr() {
+    assertEquals(EXPRESSION_BINARY_OR[OUTPUT], parseWhereExpression(EXPRESSION_BINARY_OR[INPUT], false));
+  }
+
+  @Test
+  public void testMemberOr() {
+    assertEquals(EXPRESSION_MEMBER_OR[OUTPUT], parseWhereExpression(EXPRESSION_MEMBER_OR[INPUT], false));
+  }
+
+  private String parseWhereExpression(final String input, final boolean isExceptionExpected) {
+    FilterExpression expression;
+    try {
+      expression = UriParser.parseFilter(edm, edm.getEntityType(NAMESPACE, ENTITY_NOTE), input);
+      String expressionString = ODataExpressionParser.parseToJPAWhereExpression(expression, TABLE_ALIAS);
+      return expressionString;
+    } catch (ExpressionParserException e) {
+      fail("Not expected");
+    } catch (EdmException e) {
+      fail("Not expected");
+    } catch (ODataMessageException e) {
+      fail("Not expected");
+    } catch (ODataException e) {
+      if (isExceptionExpected) {
+        assertTrue(true);
+      } else {
+        fail("Not expected");
+      }
+    }
+    return "";
+  }
+}
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataSelectExpressionParserTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataSelectExpressionParserTest.java
new file mode 100644
index 0000000..cbfab7b
--- /dev/null
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataSelectExpressionParserTest.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.jpa.processor.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.ep.EntityProvider;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.exception.ODataMessageException;
+import org.apache.olingo.odata2.api.uri.UriParser;
+import org.apache.olingo.odata2.api.uri.expression.ExpressionParserException;
+import org.apache.olingo.odata2.api.uri.expression.OrderByExpression;
+import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class ODataSelectExpressionParserTest {
+  private static final String TABLE_ALIAS = "E1";
+  private static final short INPUT = 0;
+  private static final short OUTPUT = 1;
+  private static final String NAMESPACE = "SalesOrderProcessing";
+  private static final String ENTITY_NOTE = "Note";
+  private static Edm edm = null;
+  private static final String[] EXPRESSION_ORDERBY = { "id,soId", "E1.id , E1.soId" };
+  private static final String[] EXPRESSION_ORDERBY_ASC = { "id asc,soId", "E1.id , E1.soId" };
+  private static final String[] EXPRESSION_ORDERBY_DESC = { "id desc,soId", "E1.id DESC , E1.soId" };
+  private static final String[] EXPRESSION_ORDERBY_ASC_DESC = { "id desc,soId asc", "E1.id DESC , E1.soId" };
+  private static final String[] EXPRESSION_ORDERBY_SINGLE = { "id desc", "E1.id DESC" };
+
+  @BeforeClass
+  public static void setup() {
+    InputStream metadataStream =
+        ODataFilterExpressionParserTest.class.getClassLoader().getResourceAsStream("metadata.xml");
+    try {
+      edm = EntityProvider.readMetadata(metadataStream, true);
+    } catch (EntityProviderException e) {
+      fail("Not expected");
+    }
+  }
+
+  @Test
+  public void testSelectExpression() {
+    ArrayList<String> selectedFields = new ArrayList<String>();
+    selectedFields.add("id");
+    selectedFields.add("oValue/Currency");
+    assertEquals("E1.id, E1.oValue/Currency",
+        ODataExpressionParser.parseToJPASelectExpression(TABLE_ALIAS, selectedFields));
+  }
+
+  @Test
+  public void testOrderByExpressionSingle() {
+    assertEquals(EXPRESSION_ORDERBY_SINGLE[OUTPUT], parseOrderByExpression(EXPRESSION_ORDERBY_SINGLE[INPUT], false));
+  }
+
+  @Test
+  public void testOrderByExpression() {
+    assertEquals(EXPRESSION_ORDERBY[OUTPUT], parseOrderByExpression(EXPRESSION_ORDERBY[INPUT], false));
+  }
+
+  @Test
+  public void testOrderByExpressionAsc() {
+    assertEquals(EXPRESSION_ORDERBY_ASC[OUTPUT], parseOrderByExpression(EXPRESSION_ORDERBY_ASC[INPUT], false));
+  }
+
+  @Test
+  public void testOrderByExpressionDesc() {
+    assertEquals(EXPRESSION_ORDERBY_DESC[OUTPUT], parseOrderByExpression(EXPRESSION_ORDERBY_DESC[INPUT], false));
+  }
+
+  @Test
+  public void testOrderByExpressionAscDesc() {
+    assertEquals(EXPRESSION_ORDERBY_ASC_DESC[OUTPUT], parseOrderByExpression(EXPRESSION_ORDERBY_ASC_DESC[INPUT], 
+        false));
+  }
+
+  @Test
+  public void testOrderByKeyPredicates() {
+    try {
+      assertEquals("E1.id", ODataExpressionParser.parseKeyPropertiesToJPAOrderByExpression(edm.getEntityType(NAMESPACE,
+          ENTITY_NOTE)
+          .getKeyProperties(), TABLE_ALIAS));
+    } catch (ODataJPARuntimeException e) {
+      fail("Not expected");
+    } catch (EdmException e) {
+      fail("Not expected");
+    }
+  }
+
+  @Test
+  public void testOrderByKeyPredicatesNull() {
+    try {
+      assertEquals("", ODataExpressionParser.parseKeyPropertiesToJPAOrderByExpression(null, TABLE_ALIAS));
+    } catch (ODataJPARuntimeException e) {
+      fail("Not expected");
+    }
+  }
+
+  private String parseOrderByExpression(final String input, final boolean isExceptionExpected) {
+    OrderByExpression expression;
+    try {
+      expression = UriParser.parseOrderBy(edm, edm.getEntityType(NAMESPACE, ENTITY_NOTE), input);
+      String expressionString = ODataExpressionParser.parseToJPAOrderByExpression(expression, TABLE_ALIAS);
+      return expressionString;
+    } catch (ExpressionParserException e) {
+      fail("Not expected");
+    } catch (EdmException e) {
+      fail("Not expected");
+    } catch (ODataMessageException e) {
+      fail("Not expected");
+    } catch (ODataException e) {
+      if (isExceptionExpected) {
+        assertTrue(true);
+      } else {
+        fail("Not expected");
+      }
+    }
+    return "";
+  }
+}
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinContextTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinContextTest.java
index c94160c..293b0af 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinContextTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinContextTest.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContextTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContextTest.java
index 117d21f..73b93c4 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContextTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleContextTest.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilderTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilderTest.java
index b5412a8..7b6b8c4 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilderTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinSelectSingleStatementBuilderTest.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -88,7 +88,7 @@
       assertEquals(
           "SELECT gt1 FROM SOHeader soh JOIN soh.soItem soi JOIN soi.material mat WHERE soh.soId = 1 AND " +
               "soi.shId = soh.soId AND mat.id = 'abc'",
-          jpqlStatement.toString());
+              jpqlStatement.toString());
     } catch (ODataJPARuntimeException e) {
       fail("Should not have come here");
     }
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilderTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilderTest.java
index 2a0d4f7..5701a4c 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilderTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLJoinStatementBuilderTest.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -23,7 +23,6 @@
 import static org.junit.Assert.fail;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 
 import org.apache.olingo.odata2.jpa.processor.api.access.JPAJoinClause;
@@ -53,9 +52,7 @@
     EasyMock.expect(context.getType()).andStubReturn(JPQLContextType.SELECT);
     EasyMock.expect(context.getSelectExpression()).andStubReturn("mat");
     EasyMock.expect(context.getWhereExpression()).andStubReturn("soh.buyerId = 2");
-    HashMap<String, String> orderByMap = new HashMap<String, String>();
-    orderByMap.put("mat.buyerId", "asc");
-    orderByMap.put("mat.city", "desc");
+    String orderByMap = new String("mat.buyerId asc , mat.city desc");
     EasyMock.expect(context.getOrderByCollection()).andStubReturn(orderByMap);
     EasyMock.expect(context.getJPAJoinClauses()).andStubReturn(joinClauseList);
     EasyMock.replay(context);
@@ -90,7 +87,7 @@
               "soh.createdBy = 'Peter' AND soi.shId = soh.soId AND mat.id = 'abc' "
               +
               "ORDER BY mat.buyerId asc , mat.city desc",
-          jpqlStatement.toString());
+              jpqlStatement.toString());
     } catch (ODataJPARuntimeException e) {
       fail("Should not have come here");
     }
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContextImplTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContextImplTest.java
index e793817..2f81bf4 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContextImplTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectContextImplTest.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -269,11 +269,7 @@
   @Test
   public void testGetOrderByCollection() {
     buildSelectContext(false, false, true, true, true);
-    assertEquals(true, selectContext.getOrderByCollection().containsKey("E1." + JPQLSelectContextImplTest.fields[0]));
-    assertEquals("", selectContext.getOrderByCollection().get("E1." + JPQLSelectContextImplTest.fields[0]));
-
-    assertEquals(true, selectContext.getOrderByCollection().containsKey("E1." + JPQLSelectContextImplTest.fields[1]));
-    assertEquals("DESC", selectContext.getOrderByCollection().get("E1." + JPQLSelectContextImplTest.fields[1]));
+    assertEquals("E1.Field1 , E1.Field2 DESC", selectContext.getOrderByCollection());
   }
 
   @Test
@@ -324,21 +320,14 @@
   @Test
   public void testOrderingWithSkip() {
     buildSelectContext(true, false, true, true, false);
-    assertEquals(true, selectContext.getOrderByCollection().containsKey("E1." + JPQLSelectContextImplTest.fields[0]));
-    assertEquals("", selectContext.getOrderByCollection().get("E1." + JPQLSelectContextImplTest.fields[0]));
-
-    assertEquals(false, selectContext.getOrderByCollection().containsKey("E1." + JPQLSelectContextImplTest.fields[1]));
+    assertEquals("E1.Field1", selectContext.getOrderByCollection());
 
   }
 
   @Test
   public void testOrderingWithTop() {
     buildSelectContext(true, false, true, false, true);
-    assertEquals(true, selectContext.getOrderByCollection().containsKey("E1." + JPQLSelectContextImplTest.fields[0]));
-    assertEquals("", selectContext.getOrderByCollection().get("E1." + JPQLSelectContextImplTest.fields[0]));
-
-    assertEquals(false, selectContext.getOrderByCollection().containsKey("E1." + JPQLSelectContextImplTest.fields[1]));
-
+    assertEquals("E1.Field1", selectContext.getOrderByCollection());
   }
 
   @Test
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleContextImplTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleContextImplTest.java
index 0394e54..7c4ecbb 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleContextImplTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleContextImplTest.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilderTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilderTest.java
index 25fd5ae..58cddc7 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilderTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectSingleStatementBuilderTest.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilderTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilderTest.java
index 617365b..843ace4 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilderTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/jpql/JPQLSelectStatementBuilderTest.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -17,14 +17,13 @@
  * under the License.
  ******************************************************************************/
 /**
- * 
+ *
  */
 package org.apache.olingo.odata2.jpa.processor.core.jpql;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
-import java.util.HashMap;
 import java.util.List;
 
 import org.apache.olingo.odata2.api.edm.EdmEntitySet;
@@ -109,10 +108,7 @@
     OrderByExpression orderByExpression = EasyMock.createMock(OrderByExpression.class);
 
     JPQLSelectContext jpqlSelectContextImpl = createSelectContext(orderByExpression, null);
-    HashMap<String, String> orderByCollection = new HashMap<String, String>();
-    orderByCollection.put("E1.soID", "ASC");
-    orderByCollection.put("E1.buyerId", "DESC");
-    jpqlSelectContextImpl.setOrderByCollection(orderByCollection);
+    jpqlSelectContextImpl.setOrderByCollection("E1.soID ASC , E1.buyerId DESC");
     jpqlSelectStatementBuilder = new JPQLSelectStatementBuilder(jpqlSelectContextImpl);
 
     assertEquals("SELECT E1 FROM SalesOrderHeader E1 ORDER BY E1.soID ASC , E1.buyerId DESC",
diff --git a/odata2-jpa-processor/jpa-core/src/test/resources/metadata.xml b/odata2-jpa-processor/jpa-core/src/test/resources/metadata.xml
index 1fd46a4..96f7c99 100644
--- a/odata2-jpa-processor/jpa-core/src/test/resources/metadata.xml
+++ b/odata2-jpa-processor/jpa-core/src/test/resources/metadata.xml
@@ -1,62 +1,71 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-         or more contributor license agreements.  See the NOTICE file
-         distributed with this work for additional information
-         regarding copyright ownership.  The ASF licenses this file
-         to you under the Apache License, Version 2.0 (the
-         "License"); you may not use this file except in compliance
-         with the License.  You may obtain a copy of the License at
-  
-           http://www.apache.org/licenses/LICENSE-2.0
-  
-         Unless required by applicable law or agreed to in writing,
-         software distributed under the License is distributed on an
-         "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-         KIND, either express or implied.  See the License for the
-         specific language governing permissions and limitations
-         under the License.
--->
-<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
-	<edmx:DataServices m:DataServiceVersion="1.0" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
-		<Schema Namespace="SalesOrderProcessing" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor 
+	license agreements. See the NOTICE file distributed with this work for additional 
+	information regarding copyright ownership. The ASF licenses this file to 
+	you under the Apache License, Version 2.0 (the "License"); you may not use 
+	this file except in compliance with the License. You may obtain a copy of 
+	the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required 
+	by applicable law or agreed to in writing, software distributed under the 
+	License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 
+	OF ANY KIND, either express or implied. See the License for the specific 
+	language governing permissions and limitations under the License. -->
+<edmx:Edmx Version="1.0"
+	xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
+	<edmx:DataServices m:DataServiceVersion="1.0"
+		xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
+		<Schema Namespace="SalesOrderProcessing"
+			xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
 			<EntityType Name="Note">
 				<Key>
-					<PropertyRef Name="id"/>
+					<PropertyRef Name="id" />
 				</Key>
-				<Property Name="id" Type="Edm.String" Nullable="false"/>
-				<Property Name="soId" Type="Edm.Int64" Nullable="true"/>
-				<Property Name="text" Type="Edm.String" Nullable="true" MaxLength="255"/>
-				<NavigationProperty Name="salesOrderHeader" Relationship="SalesOrderProcessing.Note_SalesOrder" FromRole="Note" ToRole="SalesOrder"/>
+				<Property Name="id" Type="Edm.String" Nullable="false" />
+				<Property Name="soId" Type="Edm.Int64" Nullable="true" />
+				<Property Name="oValue" Type="SalesOrderProcessing.OrderValue" />
+				<Property Name="date" Type="Edm.DateTime" Nullable="false" />
+				<Property Name="time" Type="Edm.Time" Nullable="false" />
+				<Property Name="text" Type="Edm.String" Nullable="true"
+					MaxLength="255" />
+				<NavigationProperty Name="salesOrderHeader"
+					Relationship="SalesOrderProcessing.Note_SalesOrder" FromRole="Note"
+					ToRole="SalesOrder" />
 			</EntityType>
 			<EntityType Name="SalesOrder">
 				<Key>
-					<PropertyRef Name="ID"/>
+					<PropertyRef Name="ID" />
 				</Key>
-				<Property Name="ID" Type="Edm.Int64" Nullable="false"/>
-				<NavigationProperty Name="NotesDetails" Relationship="SalesOrderProcessing.Note_SalesOrder" FromRole="SalesOrder" ToRole="Note"/>
+				<Property Name="ID" Type="Edm.Int64" Nullable="false" />
+				<NavigationProperty Name="NotesDetails"
+					Relationship="SalesOrderProcessing.Note_SalesOrder" FromRole="SalesOrder"
+					ToRole="Note" />
 			</EntityType>
-
+			<ComplexType Name="OrderValue">
+				<Property Name="Amount" Type="Edm.Double" />
+				<Property Name="Currency" Type="Edm.String" />
+			</ComplexType>
 			<Association Name="Note_SalesOrder">
-				<End Type="SalesOrderProcessing.Note" Multiplicity="*" Role="Note"/>
-				<End Type="SalesOrderProcessing.SalesOrder" Multiplicity="1" Role="SalesOrder"/>
+				<End Type="SalesOrderProcessing.Note" Multiplicity="*" Role="Note" />
+				<End Type="SalesOrderProcessing.SalesOrder" Multiplicity="1"
+					Role="SalesOrder" />
 				<ReferentialConstraint>
 					<Principal Role="SalesOrder">
-						<PropertyRef Name="ID"/>
+						<PropertyRef Name="ID" />
 					</Principal>
 					<Dependent Role="Note">
-						<PropertyRef Name="soId"/>
+						<PropertyRef Name="soId" />
 					</Dependent>
 				</ReferentialConstraint>
 			</Association>
 
-			<EntityContainer Name="SalesOrderProcessingContainer" m:IsDefaultEntityContainer="true">
-				<EntitySet Name="Notes" EntityType="SalesOrderProcessing.Note"/>
-				<EntitySet Name="SalesOrders" EntityType="SalesOrderProcessing.SalesOrder"/>
+			<EntityContainer Name="SalesOrderProcessingContainer"
+				m:IsDefaultEntityContainer="true">
+				<EntitySet Name="Notes" EntityType="SalesOrderProcessing.Note" />
+				<EntitySet Name="SalesOrders" EntityType="SalesOrderProcessing.SalesOrder" />
 
-				<AssociationSet Name="Note_SalesOrderSet" Association="SalesOrderProcessing.Note_SalesOrder">
-					<End EntitySet="Notes" Role="Note"/>
-					<End EntitySet="SalesOrders" Role="SalesOrder"/>
+				<AssociationSet Name="Note_SalesOrderSet"
+					Association="SalesOrderProcessing.Note_SalesOrder">
+					<End EntitySet="Notes" Role="Note" />
+					<End EntitySet="SalesOrders" Role="SalesOrder" />
 				</AssociationSet>
 
 			</EntityContainer>