[OLINGO-1583] Added 'strictFilter' option for UriParser
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/UriParser.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/UriParser.java
index 11426d0..f7fb425 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/UriParser.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/UriParser.java
@@ -54,9 +54,24 @@
   }
 
   /**
+   * Parses path segments and query parameters for the given EDM.
+   * Will not be available in higher versions
+   * @param edm Entity Data Model
+   * @param pathSegments list of path segments
+   * @param queryParameters query parameters
+   * @param strictFilter for URI Parsing of filter parameters
+   * @return {@link UriInfo} information about the parsed URI
+   * @throws ODataException
+   */
+  public static UriInfo parse(final Edm edm, final List<PathSegment> pathSegments,
+                              final Map<String, String> queryParameters, boolean strictFilter) throws ODataException {
+    return RuntimeDelegate.getUriParser(edm).parse(pathSegments, queryParameters, strictFilter);
+  }
+
+  /**
    * Parses path segments and query parameters.
    * This method ignores redundant system query parameters.
-   * 
+   *
    * @param pathSegments list of path segments
    * @param queryParameters query parameters
    * @return {@link UriInfo} information about the parsed URI
@@ -69,6 +84,23 @@
 
   /**
    * Parses path segments and query parameters.
+   * This method ignores redundant system query parameters.
+   *
+   * @param pathSegments list of path segments
+   * @param queryParameters query parameters
+   * @param strictFilter for URI Parsing of filter parameters
+   * @return {@link UriInfo} information about the parsed URI
+   * @throws UriSyntaxException
+   * @throws UriNotMatchingException
+   * @throws EdmException
+   */
+  public abstract UriInfo parse(List<PathSegment> pathSegments,
+                                Map<String, String> queryParameters, boolean strictFilter)
+      throws UriSyntaxException, UriNotMatchingException, EdmException;
+
+
+  /**
+   * Parses path segments and query parameters.
    * Throws an exception if there are redundant system query parameters.
    * 
    * @param pathSegments list of path segments
diff --git a/odata2-lib/odata-client-api/src/main/java/org/apache/olingo/odata2/client/api/ODataClient.java b/odata2-lib/odata-client-api/src/main/java/org/apache/olingo/odata2/client/api/ODataClient.java
index b3282a7..5a18978 100644
--- a/odata2-lib/odata-client-api/src/main/java/org/apache/olingo/odata2/client/api/ODataClient.java
+++ b/odata2-lib/odata-client-api/src/main/java/org/apache/olingo/odata2/client/api/ODataClient.java
@@ -109,16 +109,45 @@
   /**
    * Parses the uri and returns UriInfo
    * @param edm
+   * @param pathSegments
+   * @param queryParameters
+   * @param strictFilter
+   * @return UriInfo
+   * @throws EntityProviderException
+   * @throws EdmException
+   */
+
+  public abstract UriInfo parseUri(final Edm edm, final List<PathSegment> pathSegments,
+      final Map<String, String> queryParameters, boolean strictFilter)
+      throws UriSyntaxException, UriNotMatchingException, EdmException; //NOPMD  - suppressed
+
+  /**
+   * Parses the uri and returns UriInfo
+   * @param edm
    * @param uri
    * @return UriInfo
    * @throws UriSyntaxException
    * @throws UriNotMatchingException
    * @throws EdmException
    */
-  
-  public abstract UriInfo parseUri(final Edm edm, final String uri) 
+
+  public abstract UriInfo parseUri(final Edm edm, final String uri)
       throws UriSyntaxException, UriNotMatchingException, EdmException; //NOPMD  - suppressed
-   
+
+  /**
+   * Parses the uri and returns UriInfo
+   * @param edm
+   * @param uri
+   * @param strictFilter
+   * @return UriInfo
+   * @throws UriSyntaxException
+   * @throws UriNotMatchingException
+   * @throws EdmException
+   */
+
+  public abstract UriInfo parseUri(final Edm edm, final String uri, boolean strictFilter)
+      throws UriSyntaxException, UriNotMatchingException, EdmException; //NOPMD  - suppressed
+
   
   
   /**
diff --git a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ODataClientImpl.java b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ODataClientImpl.java
index 60b2b88..1323063 100644
--- a/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ODataClientImpl.java
+++ b/odata2-lib/odata-client-core/src/main/java/org/apache/olingo/odata2/client/core/ODataClientImpl.java
@@ -125,6 +125,13 @@
   }
 
   @Override
+  public UriInfo parseUri(Edm edm, List<PathSegment> pathSegments,
+                          Map<String, String> queryParameters, boolean strictFilter)
+      throws UriSyntaxException, UriNotMatchingException, EdmException {
+    return new UriParserImpl(edm).parse(pathSegments, queryParameters, strictFilter);
+  }
+
+  @Override
   public UriInfo parseUri(Edm edm, String uri) throws UriSyntaxException, UriNotMatchingException, EdmException {
     final String[] path = uri.split(QUESTIONMARK, -1);
     if (path.length > 2) {
@@ -142,6 +149,28 @@
     
     return new UriParserImpl(edm).parseAll(pathSegments, queryParameters);
   }
+
+  @Override
+  public UriInfo parseUri(Edm edm, String uri, boolean strictFilter)
+      throws UriSyntaxException, UriNotMatchingException, EdmException {
+
+    final String[] path = uri.split(QUESTIONMARK, -1);
+    if (path.length > 2) {
+      throw new UriSyntaxException(UriSyntaxException.URISYNTAX);
+    }
+
+    final List<PathSegment> pathSegments = getPathSegments(path[0]);
+
+    Map<String, String> queryParameters;
+    if (path.length == 2) {
+      queryParameters = getQueryParametersWithStrictFilter(unescape(path[1]));
+    } else {
+      queryParameters = new HashMap<String, String>();
+    }
+
+    return new UriParserImpl(edm).parse(pathSegments, queryParameters, strictFilter);
+  }
+
   /**
    * Fetch query parameters
    * @param uri
@@ -162,6 +191,25 @@
 
     return allQueryParameters;
   }
+
+  /**
+   * Fetch Query parameters
+   * @param uri
+   * @return
+   */
+  private Map<String, String> getQueryParametersWithStrictFilter(String uri) {
+    Map<String, String> queryParameters = new HashMap<String, String>();
+    for (final String option : uri.split(AMP)) {
+      final String[] keyAndValue = option.split(EQUAL);
+      if (keyAndValue.length == 2) {
+        queryParameters.put(keyAndValue[0], keyAndValue[1]);
+      } else {
+        queryParameters.put(keyAndValue[0], "");
+      }
+    }
+    return queryParameters;
+  }
+
   /**
    * Fetch path segments
    * @param uri
diff --git a/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/uri/UriParserTest.java b/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/uri/UriParserTest.java
index a61420b..0183d0d 100644
--- a/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/uri/UriParserTest.java
+++ b/odata2-lib/odata-client-core/src/test/java/org/apache/olingo/odata2/client/core/uri/UriParserTest.java
@@ -68,27 +68,27 @@
   public void getEdm() throws ODataException {
     edm = MockFacade.getMockEdm();
   }
-  
+
   @Test
   public void copyPathSegmentsTest() throws Exception {
     List<PathSegment> pathSegments = new ArrayList<PathSegment>();
     pathSegments.add(UriParser.createPathSegment("$metadata", null));
-    UriInfo result = new UriParserImpl(edm).parse(pathSegments, Collections.<String, String> emptyMap());
+    UriInfo result = new UriParserImpl(edm).parse(pathSegments, Collections.<String, String>emptyMap());
     assertNotNull(result);
     assertEquals(1, pathSegments.size());
     assertEquals("$metadata", pathSegments.get(0).getPath());
   }
-  
+
   @Test
   public void copyPathSegmentsTestEncoded() throws Exception {
     List<PathSegment> pathSegments = new ArrayList<PathSegment>();
     pathSegments.add(UriParser.createPathSegment("%24metadata", null));
     UriInfoImpl result = (UriInfoImpl) new UriParserImpl(edm).parse(pathSegments,
-        Collections.<String, String> emptyMap());
+        Collections.<String, String>emptyMap());
     assertNotNull(result);
     assertEquals(UriType.URI8, result.getUriType());
   }
-  
+
   @Test
   public void parseNonsense() throws Exception {
     parseWrongUri("/bla", UriNotMatchingException.NOTFOUND);
@@ -103,8 +103,8 @@
     assertEquals(UriType.URI0, result.getUriType());
 
     result =
-        (UriInfoImpl) new UriParserImpl(edm).parse(Collections.<PathSegment> emptyList(), Collections
-            .<String, String> emptyMap());
+        (UriInfoImpl) new UriParserImpl(edm).parse(Collections.<PathSegment>emptyList(), Collections
+            .<String, String>emptyMap());
     assertEquals(UriType.URI0, result.getUriType());
   }
 
@@ -237,7 +237,7 @@
     assertEquals("1", result.getKeyPredicates().get(0).getLiteral());
     assertEquals("EmployeeId", result.getKeyPredicates().get(0).getProperty().getName());
   }
-  
+
   @Test
   public void parseEmployeesEntity() throws Exception {
     UriInfoImpl result = parse("/Employees('1')");
@@ -310,7 +310,7 @@
     assertEquals("1", result.getKeyPredicates().get(0).getLiteral());
     assertEquals("EmployeeId", result.getKeyPredicates().get(0).getProperty().getName());
   }
-  
+
   @Test
   public void parseEmployeesEntityWithKeyCountEncoded() throws Exception {
     UriInfoImpl result = parse("/Employees('1')/%24count");
@@ -322,7 +322,7 @@
     assertEquals("1", result.getKeyPredicates().get(0).getLiteral());
     assertEquals("EmployeeId", result.getKeyPredicates().get(0).getProperty().getName());
   }
-  
+
   @Test
   public void parseEmployeesSimpleProperty() throws Exception {
     UriInfoImpl result = parse("/Employees('1')/EmployeeName");
@@ -341,7 +341,7 @@
     assertEquals("EmployeeName", result.getPropertyPath().get(0).getName());
     assertTrue(result.isValue());
   }
-  
+
   @Test
   public void parseEmployeesSimplePropertyValueEncoded() throws Exception {
     UriInfoImpl result = parse("/Employees('1')/EmployeeName/%24value");
@@ -351,7 +351,7 @@
     assertEquals("EmployeeName", result.getPropertyPath().get(0).getName());
     assertTrue(result.isValue());
   }
-  
+
   @Test
   public void parseEmployeesComplexProperty() throws Exception {
     UriInfoImpl result = parse("/Employees('1')/Location");
@@ -444,7 +444,7 @@
     assertTrue(result.isLinks());
     assertEquals(UriType.URI7B, result.getUriType());
   }
-  
+
   @Test
   public void parseNavigationPropertyWithLinksManyEncoded() throws Exception {
     UriInfoImpl result = parse("/Managers('1')/%24links/nm_Employees");
@@ -452,7 +452,7 @@
     assertTrue(result.isLinks());
     assertEquals(UriType.URI7B, result.getUriType());
   }
-  
+
   @Test
   public void parseNavigationPropertyWithManagersCount() throws Exception {
     UriInfoImpl result = parse("/Employees('1')/ne_Manager/$count");
@@ -640,12 +640,12 @@
     assertEquals("MaximalAge", result.getFunctionImport().getName());
     assertTrue(result.isValue());
     assertEquals(UriType.URI14, result.getUriType());
-    
+
     result = parse("MaximalAge/%24value");
     assertEquals("MaximalAge", result.getFunctionImport().getName());
     assertTrue(result.isValue());
     assertEquals(UriType.URI14, result.getUriType());
-    
+
     result = parse("MostCommonLocation");
     assertEquals("MostCommonLocation", result.getFunctionImport().getName());
     assertEquals(UriType.URI12, result.getUriType());
@@ -657,7 +657,7 @@
     result = parse("OldestEmployee");
     assertEquals("OldestEmployee", result.getFunctionImport().getName());
     assertEquals(UriType.URI10, result.getUriType());
-    
+
     result = parse("EmployeeSearch?$filter=EmployeeId%20eq%20%271%27&$select=EmployeeName");
     assertEquals("Employee", result.getFunctionImport().getReturnType().getType().getName());
     assertEquals(EdmMultiplicity.MANY, result.getFunctionImport().getReturnType().getMultiplicity());
@@ -675,13 +675,13 @@
         .getType());
     assertEquals("Hugo", result.getFunctionImportParameters().get("q").getLiteral());
   }
-  
+
   @Test
   public void parseFunctionImportParametersWithFacets() throws Exception {
     UriInfoImpl result = parse("FINullableParameter");
     assertEquals("FINullableParameter", result.getFunctionImport().getName());
     assertTrue(result.getFunctionImportParameters().isEmpty());
-    
+
     result = parse("FINullableParameter?Id='A'");
     assertEquals("FINullableParameter", result.getFunctionImport().getName());
     assertFalse(result.getFunctionImportParameters().isEmpty());
@@ -720,7 +720,7 @@
     assertEquals("abc", result.getSkipToken());
     assertEquals(2, result.getSkip().intValue());
     assertEquals(1, result.getTop().intValue());
-    
+
     result = parse("Employees?$format=json&%24inlinecount=allpages&%24skiptoken=abc&%24skip=2&$top=1");
     assertEquals("Employees", result.getTargetEntitySet().getName());
     assertEquals(UriType.URI1, result.getUriType());
@@ -729,7 +729,7 @@
     assertEquals("abc", result.getSkipToken());
     assertEquals(2, result.getSkip().intValue());
     assertEquals(1, result.getTop().intValue());
-    
+
     result = parse("Employees?$format=atom&$inlinecount=none&$skip=0&$top=0");
     assertEquals("Employees", result.getTargetEntitySet().getName());
     assertEquals(UriType.URI1, result.getUriType());
@@ -777,16 +777,40 @@
     assertNotNull(result.getFilter());
     assertNotNull(result.getOrderBy());
     assertEquals("EmployeeName desc", result.getOrderBy().getUriLiteral());
-    
+
     result = parse("EmployeeSearch?$filter=EmployeeId%20eq%20%271%27");
     assertEquals("Employee", result.getFunctionImport().getReturnType().getType().getName());
     assertEquals(EdmMultiplicity.MANY, result.getFunctionImport().getReturnType().getMultiplicity());
     assertEquals(UriType.URI10a, result.getUriType());
     assertNotNull(result.getFilter());
   }
-  
-  @Test(expected=UriSyntaxException.class)
-  public void parseFilterOptionsWithError1() throws Exception {       
+
+  @Test
+  public void parseFilterOptions() throws Exception {
+    UriInfoImpl result = parse("Employees?$filter=Age%20gt%2020", false);
+    assertEquals("Employees", result.getTargetEntitySet().getName());
+    assertEquals(UriType.URI1, result.getUriType());
+    assertNotNull(result.getFilter());
+
+    result = parse("Employees?$filter=EmployeeName%20gt%20%27Archana%27", false);
+    assertEquals("Employees", result.getTargetEntitySet().getName());
+    assertEquals(UriType.URI1, result.getUriType());
+    assertNotNull(result.getFilter());
+
+    result = parse("Managers?$filter=nm_Employees%20eq%20null", false);
+    assertEquals("Managers", result.getTargetEntitySet().getName());
+    assertEquals(UriType.URI1, result.getUriType());
+    assertNotNull(result.getFilter());
+
+
+    result = parse("Managers?$filter=nm_Employees/EmployeeName%20eq%20%27Archana%27", false);
+    assertEquals("Managers", result.getTargetEntitySet().getName());
+    assertEquals(UriType.URI1, result.getUriType());
+    assertNotNull(result.getFilter());
+  }
+
+  @Test(expected = UriSyntaxException.class)
+  public void parseFilterOptionsWithError1() throws Exception {
     ODataClient.newInstance().parseUri(edm, "Managers?count?$filter=nm_Employees/EmployeeName%20eq%20%27Archana%27");
   }
 
@@ -918,13 +942,13 @@
     assertEquals(UriType.URI1, result.getUriType());
     assertEquals(1, result.getSelect().size());
     assertEquals("EmployeeName", result.getSelect().get(0).getProperty().getName());
-    
+
     result = parse("Employees?%24select=EmployeeName");
     assertEquals("Employees", result.getTargetEntitySet().getName());
     assertEquals(UriType.URI1, result.getUriType());
     assertEquals(1, result.getSelect().size());
     assertEquals("EmployeeName", result.getSelect().get(0).getProperty().getName());
-    
+
     result = parse("Employees?$select=*");
     assertEquals("Employees", result.getTargetEntitySet().getName());
     assertEquals(UriType.URI1, result.getUriType());
@@ -1010,7 +1034,7 @@
     assertEquals("Employees", result.getExpand().get(0).get(0).getTargetEntitySet().getName());
     assertEquals(result.getTargetEntitySet().getEntityType().getProperty("nm_Employees"),
         result.getExpand().get(0).get(0).getNavigationProperty());
-    
+
     result = parse("Managers('1')?%24expand=nm_Employees");
     assertEquals("Managers", result.getTargetEntitySet().getName());
     assertEquals(UriType.URI2, result.getUriType());
@@ -1043,7 +1067,7 @@
   }
 
   private void wrongGetKey(final EdmEntitySet entitySet, final String link, final String serviceRoot,
-      final MessageReference exceptionContext) throws ODataException {
+                           final MessageReference exceptionContext) throws ODataException {
     try {
       new UriParserImpl(null).getKeyFromEntityLink(entitySet, link,
           serviceRoot == null ? null : URI.create(serviceRoot));
@@ -1101,14 +1125,28 @@
     assertTrue(segmentWithMatrix.getMatrixParameters().get("parameter1").contains("one"));
     assertTrue(segmentWithMatrix.getMatrixParameters().get("parameter1").contains("two"));
   }
-  
+
+  /**
+   * Parse the URI part after an OData service root, given as string.
+   * Query parameters can be included.
+   *
+   * @param uri the URI part
+   * @return a {@link UriInfoImpl} instance containing the parsed information
+   */
+  private UriInfoImpl parse(final String uri)
+      throws UriSyntaxException, UriNotMatchingException, EdmException {
+    return parse(uri, true);
+  }
+
   /**
    * Parse the URI part after an OData service root, given as string.
    * Query parameters can be included.
    * @param uri the URI part
    * @return a {@link UriInfoImpl} instance containing the parsed information
    */
-  private UriInfoImpl parse(final String uri) throws UriSyntaxException, UriNotMatchingException, EdmException {
+  private UriInfoImpl parse(final String uri, boolean strictFilter)
+      throws UriSyntaxException, UriNotMatchingException, EdmException {
+
     final String[] path = uri.split("\\?", -1);
     if (path.length > 2) {
       throw new UriSyntaxException(UriSyntaxException.URISYNTAX);
@@ -1116,9 +1154,14 @@
 
     final List<PathSegment> pathSegments =
         MockFacade.getPathSegmentsAsODataPathSegmentMock(Arrays.asList(path[0].split("/", -1)));
-    final Map<String, List<String>> queryParameters = getQueryParameters(path.length == 2 ? unescape(path[1]) : "");
-
-    return (UriInfoImpl) ODataClient.newInstance().parseUri(edm, pathSegments, queryParameters);
+    if (strictFilter) {
+      final Map<String, List<String>> queryParameters = getQueryParameters(path.length == 2 ? unescape(path[1]) : "");
+      return (UriInfoImpl) ODataClient.newInstance().parseUri(edm, pathSegments, queryParameters);
+    } else {
+      final Map<String, String> queryParameters =
+          getQueryParametersWithStrictFilter(path.length == 2 ? unescape(path[1]) : "");
+      return (UriInfoImpl) ODataClient.newInstance().parseUri(edm, pathSegments, queryParameters, false);
+    }
   }
   
   private Map<String, List<String>> getQueryParameters(final String uri) {
@@ -1136,7 +1179,25 @@
 
     return allQueryParameters;
   }
-  
+
+  /**
+   * Fetch Query parameters
+   * @param uri
+   * @return
+   */
+  private Map<String, String> getQueryParametersWithStrictFilter(String uri) {
+    Map<String, String> queryParameters = new HashMap<String, String>();
+    for (final String option : uri.split("&")) {
+      final String[] keyAndValue = option.split("=");
+      if (keyAndValue.length == 2) {
+        queryParameters.put(keyAndValue[0], keyAndValue[1]);
+      } else {
+        queryParameters.put(keyAndValue[0], "");
+      }
+    }
+    return queryParameters;
+  }
+
   private String unescape(final String s) throws UriSyntaxException {
     try {
       return new URI(s).getPath();
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/UriParserImpl.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/UriParserImpl.java
index 6ebab2f..528151a 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/UriParserImpl.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/UriParserImpl.java
@@ -93,6 +93,7 @@
   private Map<SystemQueryOption, String> systemQueryOptions;
   private Map<String, String> otherQueryParameters;
   private String originalFilterString = "";
+  private boolean strictFilter = true;
 
   public UriParserImpl(final Edm edm) {
     this.edm = edm;
@@ -115,6 +116,13 @@
   }
 
   @Override
+  public UriInfo parse(List<PathSegment> pathSegments, Map<String, String> queryParameters, boolean strictFilter)
+      throws UriSyntaxException, UriNotMatchingException, EdmException {
+    this.strictFilter = strictFilter;
+    return parseAll(pathSegments, convertFromSingleMapToMultiMap(queryParameters));
+  }
+
+  @Override
   public UriInfo parseAll(final List<PathSegment> pathSegments, final Map<String, List<String>> allQueryParameters)
       throws UriSyntaxException, UriNotMatchingException, EdmException {
 
@@ -735,7 +743,7 @@
     final EdmType targetType = uriResult.getTargetType();
     if (targetType instanceof EdmEntityType) {
       try {
-        uriResult.setFilter(new FilterParserImpl((EdmEntityType) targetType,originalFilterString).
+        uriResult.setFilter(new FilterParserImpl((EdmEntityType) targetType, strictFilter, originalFilterString).
         		parseFilterString(filter, true));
       } catch (ExpressionParserException e) {
         throw new UriSyntaxException(UriSyntaxException.INVALIDFILTEREXPRESSION.addContent(filter), e);
@@ -1004,7 +1012,7 @@
   @Override
   public FilterExpression parseFilterString(final EdmEntityType entityType, final String expression)
       throws ODataMessageException {
-    return new FilterParserImpl(entityType).parseFilterString(expression);
+    return new FilterParserImpl(entityType, strictFilter).parseFilterString(expression);
   }
 
   @Override
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/FilterParserImpl.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/FilterParserImpl.java
index b8f5c88..b37a804 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/FilterParserImpl.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/uri/expression/FilterParserImpl.java
@@ -67,6 +67,8 @@
   protected String curExpression;
   protected String originalFilterString = "";
   protected String decodedFilterString  = "";
+  private boolean strictFilter = true;
+
 
   /**
    * Creates a new FilterParser implementation
@@ -75,16 +77,29 @@
   public FilterParserImpl(final EdmEntityType resourceEntityType) {
     this.resourceEntityType = resourceEntityType;
   }
-  
+
   /**
    * Creates a new FilterParser implementation
    * @param resourceEntityType EntityType of the resource on which the filter is applied
-   * @param originalFilterString String original filter string prior to decoding 
+   * @param strictFilter boolean check to decide weather to validate filter
    */
-  public FilterParserImpl(final EdmEntityType resourceEntityType,  String originalFilterString) {
+  public FilterParserImpl(final EdmEntityType resourceEntityType, boolean strictFilter) {
     this.resourceEntityType = resourceEntityType;
+    this.strictFilter = strictFilter;
+  }
+
+  /**
+   * Creates a new FilterParser implementation
+   * @param resourceEntityType EntityType of the resource on which the filter is applied
+   * @param strictFilter boolean check to decide weather to validate filter
+   * @param originalFilterString String original filter string prior to decoding
+   */
+  public FilterParserImpl(final EdmEntityType resourceEntityType, boolean strictFilter,
+                          String originalFilterString) {
+    this.resourceEntityType = resourceEntityType;
+    this.strictFilter = strictFilter;
     this.originalFilterString = originalFilterString;
-  }    
+  }
 
   @Override
   public FilterExpression parseFilterString(final String filterExpression) throws ExpressionParserException,
@@ -524,7 +539,7 @@
         property.setEdmProperty(edmProperty);
         property.setEdmType(edmProperty.getType());
         if(isLastFilterElement(propertyName)) {
-          if (edmProperty.getMultiplicity() == EdmMultiplicity.MANY) {
+          if (edmProperty.getMultiplicity() == EdmMultiplicity.MANY && strictFilter) {
             throw new ExpressionParserException(
                 ExpressionParserException.INVALID_MULTIPLICITY.create()
                     .addContent(propertyName)