You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ra...@apache.org on 2021/01/22 10:10:31 UTC

[olingo-odata2] branch master updated: [OLINGO-1497]Bug Fix in support for system query options for function import calls in JPA

This is an automated email from the ASF dual-hosted git repository.

ramyav pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/olingo-odata2.git


The following commit(s) were added to refs/heads/master by this push:
     new 4e23489  [OLINGO-1497]Bug Fix in support for system query options for function import calls in JPA
4e23489 is described below

commit 4e234890f1f8c800b505dc22710f11fc410c6e82
Author: ramya vasanth <ra...@sap.com>
AuthorDate: Fri Jan 22 15:40:19 2021 +0530

    [OLINGO-1497]Bug Fix in support for system query options for function import calls in JPA
---
 .../core/ODataJPAResponseBuilderDefault.java       | 137 ++++++++++++++++++---
 .../core/callback/JPATombstoneCallBackFI.java      |  66 ++++++++++
 .../core/ODataJPAResponseBuilderTest.java          | 118 ++++++++++++++++++
 .../api/uri/info/GetFunctionImportUriInfo.java     |  26 ++++
 4 files changed, 328 insertions(+), 19 deletions(-)

diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderDefault.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderDefault.java
index 693453b..80cea7d 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderDefault.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderDefault.java
@@ -71,6 +71,7 @@ import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeExcep
 import org.apache.olingo.odata2.jpa.processor.core.access.data.JPAEntityParser;
 import org.apache.olingo.odata2.jpa.processor.core.callback.JPAExpandCallBack;
 import org.apache.olingo.odata2.jpa.processor.core.callback.JPATombstoneCallBack;
+import org.apache.olingo.odata2.jpa.processor.core.callback.JPATombstoneCallBackFI;
 
 public final class ODataJPAResponseBuilderDefault implements ODataJPAResponseBuilder {
 
@@ -301,37 +302,54 @@ public final class ODataJPAResponseBuilderDefault implements ODataJPAResponseBui
       JPAEntityParser jpaResultParser = new JPAEntityParser();
       EdmType edmType = null;
       EdmFunctionImport functionImport = null;
-      Map<String, Object> edmPropertyValueMap = null;
       List<Map<String, Object>> edmEntityList = null;
       Object result = null;
       try {
-        EntityProviderWriteProperties feedProperties =
-            EntityProviderWriteProperties.serviceRoot(oDataJPAContext.getODataContext().getPathInfo().getServiceRoot())
-                .build();
-
+      
         functionImport = resultsView.getFunctionImport();
         edmType = functionImport.getReturnType().getType();
+        
+        final List<SelectItem> selectedItems = resultsView.getSelect();
+        List<ArrayList<NavigationPropertySegment>> expandList = null;
+        EntityProviderWriteProperties feedProperties = null;
 
         if (edmType.getKind().equals(EdmTypeKind.ENTITY) || edmType.getKind().equals(EdmTypeKind.COMPLEX)) {
-          if (functionImport.getReturnType().getMultiplicity().equals(EdmMultiplicity.MANY)) {
-            edmEntityList = new ArrayList<Map<String, Object>>();
-            for (Object jpaEntity : resultList) {
-              edmPropertyValueMap = jpaResultParser.parse2EdmPropertyValueMap(jpaEntity, (EdmStructuralType) edmType);
-              edmEntityList.add(edmPropertyValueMap);
-            }
-            result = edmEntityList;
-          } else {
+	    	if (selectedItems != null && !selectedItems.isEmpty()) {
+	            edmEntityList =
+	                jpaResultParser.parse2EdmEntityList(resultList, 
+	                		buildSelectItemList(selectedItems, (EdmEntityType) edmType));
+	          } else {
+	              edmEntityList = jpaResultParser.parse2EdmEntityList(resultList, (EdmEntityType) edmType);
+	          }
+	    	expandList = resultsView.getExpand();
+	        if (expandList != null && !expandList.isEmpty()) {
+	          int count = 0;
+	          List<EdmNavigationProperty> edmNavPropertyList = constructListofNavProperty(expandList);
+	          for (Object jpaEntity : resultList) {
+	            Map<String, Object> relationShipMap = edmEntityList.get(count);
+	            HashMap<String, Object> navigationMap =
+	                jpaResultParser.parse2EdmNavigationValueMap(jpaEntity, edmNavPropertyList);
+	            relationShipMap.putAll(navigationMap);
+	            count++;
+	          }
+	        }
+	        if (functionImport.getReturnType().getMultiplicity().equals(EdmMultiplicity.MANY)) {
+	        	result = edmEntityList;
+	        } else {
+	        	result = edmEntityList.get(0);
+	        }
+	    	feedProperties = 
+	        		getEntityProviderProperties(oDataJPAContext, resultsView, edmEntityList);
 
-            Object resultObject = resultList.get(0);
-            edmPropertyValueMap = jpaResultParser.parse2EdmPropertyValueMap(resultObject, (EdmStructuralType) edmType);
-
-            result = edmPropertyValueMap;
-          }
 
         } else if (edmType.getKind().equals(EdmTypeKind.SIMPLE)) {
           result = resultList.get(0);
+          feedProperties =
+                  EntityProviderWriteProperties.serviceRoot(
+                		  oDataJPAContext.getODataContext().getPathInfo().getServiceRoot())
+                      .build();
         }
-
+        
         odataResponse =
             EntityProvider.writeFunctionImport(contentType, resultsView.getFunctionImport(), result, feedProperties);
         odataResponse = ODataResponse.fromResponse(odataResponse).status(HttpStatusCodes.OK).build();
@@ -471,6 +489,63 @@ public final class ODataJPAResponseBuilderDefault implements ODataJPAResponseBui
     }// Inlinecount of None is handled by default - null
     return count;
   }
+  
+  /*
+   * Method to build the entity provider Property.Callbacks for $expand would
+   * be registered here
+   */
+  private static EntityProviderWriteProperties getEntityProviderProperties(final ODataJPAContext odataJPAContext,
+      final GetFunctionImportUriInfo resultsView, final List<Map<String, Object>> edmEntityList)
+      throws ODataJPARuntimeException {
+    ODataEntityProviderPropertiesBuilder entityFeedPropertiesBuilder = null;
+    ODataContext context = odataJPAContext.getODataContext();
+
+    Integer count = null;
+    if (resultsView.getInlineCount() != null) {
+       count = getInlineCountForNonFilterQueryEntitySet(edmEntityList, resultsView);
+    }
+
+    try {
+      PathInfo pathInfo = context.getPathInfo();
+      URI serviceRoot = pathInfo.getServiceRoot();
+
+      entityFeedPropertiesBuilder =
+          EntityProviderWriteProperties.serviceRoot(pathInfo.getServiceRoot());
+      JPAPaging paging = odataJPAContext.getPaging();
+      if (odataJPAContext.getPageSize() > 0 && paging != null && paging.getNextPage() > 0) {
+        String nextLink =
+            serviceRoot.relativize(pathInfo.getRequestUri()).toString();
+        nextLink = percentEncodeNextLink(nextLink);
+        nextLink += (nextLink != null ? nextLink.contains("?") ? "&" : "?" : "?")
+            + "$skiptoken=" + odataJPAContext.getPaging().getNextPage();
+        entityFeedPropertiesBuilder.nextLink(nextLink);
+      }
+      entityFeedPropertiesBuilder.inlineCount(count);
+      entityFeedPropertiesBuilder.inlineCountType(resultsView.getInlineCount());
+      ExpandSelectTreeNode expandSelectTree =
+          UriParser.createExpandSelectTree(resultsView.getSelect(), resultsView.getExpand());
+
+      Map<String, ODataCallback> expandCallBack =
+          JPAExpandCallBack.getCallbacks(serviceRoot, expandSelectTree, resultsView.getExpand());
+
+      Map<String, ODataCallback> callBackMap = new HashMap<String, ODataCallback>();
+      callBackMap.putAll(expandCallBack);
+      
+      String deltaToken = ODataJPATombstoneContext.getDeltaToken();
+      if (deltaToken != null) {
+        callBackMap.put(TombstoneCallback.CALLBACK_KEY_TOMBSTONE, new JPATombstoneCallBackFI(serviceRoot.toString(),
+            resultsView, deltaToken));
+      }
+
+      entityFeedPropertiesBuilder.callbacks(callBackMap);
+      entityFeedPropertiesBuilder.expandSelectTree(expandSelectTree);
+      
+    } catch (ODataException e) {
+      throw ODataJPARuntimeException.throwException(ODataJPARuntimeException.INNER_EXCEPTION, e);
+    }
+
+    return entityFeedPropertiesBuilder.build();
+  }
 
   /*
    * Method to build the entity provider Property.Callbacks for $expand would
@@ -566,6 +641,30 @@ public final class ODataJPAResponseBuilderDefault implements ODataJPAResponseBui
     }// Inlinecount of None is handled by default - null
     return count;
   }
+  
+  /*
+   * This method handles $inlinecount request. It also modifies the list of results in case of
+   * $inlinecount and $top/$skip combinations. Specific to Entity Set.
+   */
+  private static Integer getInlineCountForNonFilterQueryEntitySet(final List<Map<String, Object>> edmEntityList,
+      final GetFunctionImportUriInfo resultsView) {
+    // when $skip and/or $top is present with $inlinecount, first get the total count
+    Integer count = null;
+    if (resultsView.getInlineCount() == InlineCount.ALLPAGES) {
+      count = edmEntityList.size();
+      if (resultsView.getCustomQueryOptions() != null) {
+        String countValue = resultsView.getCustomQueryOptions().get(COUNT);
+        if (countValue != null && isNumeric(countValue)) {
+          count = Integer.parseInt(countValue);
+          resultsView.getCustomQueryOptions().remove(COUNT);
+          if (resultsView.getCustomQueryOptions().size() == 0) {
+            ((UriInfoImpl) resultsView).setCustomQueryOptions(null);
+          }
+        }
+      }
+    }// Inlinecount of None is handled by default - null
+    return count;
+  }
 
   private static EntityProviderWriteProperties getEntityProviderProperties(final ODataJPAContext odataJPAContext,
       final GetEntityUriInfo resultsView) throws ODataJPARuntimeException {
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/callback/JPATombstoneCallBackFI.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/callback/JPATombstoneCallBackFI.java
new file mode 100644
index 0000000..82c4f9c
--- /dev/null
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/callback/JPATombstoneCallBackFI.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * 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.callback;
+
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.ep.callback.TombstoneCallback;
+import org.apache.olingo.odata2.api.ep.callback.TombstoneCallbackResult;
+import org.apache.olingo.odata2.api.uri.info.GetFunctionImportUriInfo;
+
+public class JPATombstoneCallBackFI implements TombstoneCallback {
+
+  private static final String DELTA_TOKEN_STRING = "?!deltatoken=";
+  private String baseUri;
+  private String deltaTokenValue;
+  private GetFunctionImportUriInfo resultsView;
+
+  public JPATombstoneCallBackFI(final String baseUri, final GetFunctionImportUriInfo resultsView,
+      final String deltaTokenValue) {
+    this.baseUri = baseUri;
+    this.deltaTokenValue = deltaTokenValue;
+    this.resultsView = resultsView;
+  }
+
+  @Override
+  public TombstoneCallbackResult getTombstoneCallbackResult() {
+    TombstoneCallbackResult jpaTombstoneCallBackResult = new TombstoneCallbackResult();
+
+    jpaTombstoneCallBackResult.setDeltaLink(buildToken());
+    return jpaTombstoneCallBackResult;
+  }
+
+  private String buildToken() {
+    StringBuilder tokenBuilder = new StringBuilder();
+    if (baseUri != null) {
+      tokenBuilder.append(baseUri);
+    }
+    try {
+      if (resultsView != null) {
+        tokenBuilder.append(resultsView.getFunctionImport().getEntitySet().getName());
+      }
+    } catch (EdmException e) {
+      // Nothing
+    }
+    tokenBuilder.append(DELTA_TOKEN_STRING);
+    if (deltaTokenValue != null) {
+      tokenBuilder.append(deltaTokenValue);
+    }
+    return tokenBuilder.toString();
+  }
+}
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderTest.java
index 09f9cc1..7105c3d 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAResponseBuilderTest.java
@@ -28,6 +28,7 @@ import java.lang.reflect.Method;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -37,14 +38,17 @@ import org.apache.olingo.odata2.api.edm.EdmEntityContainer;
 import org.apache.olingo.odata2.api.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.edm.EdmEntityType;
 import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
 import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
 import org.apache.olingo.odata2.api.edm.EdmMapping;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
 import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
 import org.apache.olingo.odata2.api.edm.EdmProperty;
 import org.apache.olingo.odata2.api.edm.EdmSimpleType;
 import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
 import org.apache.olingo.odata2.api.edm.EdmType;
 import org.apache.olingo.odata2.api.edm.EdmTypeKind;
+import org.apache.olingo.odata2.api.edm.EdmTyped;
 import org.apache.olingo.odata2.api.edm.provider.EntityType;
 import org.apache.olingo.odata2.api.edm.provider.Facets;
 import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties;
@@ -57,6 +61,7 @@ import org.apache.olingo.odata2.api.uri.PathInfo;
 import org.apache.olingo.odata2.api.uri.SelectItem;
 import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo;
 import org.apache.olingo.odata2.api.uri.info.GetEntityUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetFunctionImportUriInfo;
 import org.apache.olingo.odata2.core.uri.UriInfoImpl;
 import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
 import org.apache.olingo.odata2.jpa.processor.api.ODataJPAResponseBuilder;
@@ -440,6 +445,7 @@ public class ODataJPAResponseBuilderTest extends JPAEdmTestModelView {
     try {
       EasyMock.expect(objEdmEntityType.getName()).andStubReturn("SalesOderHeaders");
       EasyMock.expect(objEdmEntityType.getNamespace()).andStubReturn("SalesOderHeaders");
+      EasyMock.expect(objEdmEntityType.getKind()).andStubReturn(EdmTypeKind.ENTITY);
       EasyMock.expect(objEdmEntityType.hasStream()).andStubReturn(false);
       EasyMock.expect(objEdmEntityType.hasStream()).andStubReturn(false);
       ArrayList<String> propertyNames = new ArrayList<String>();
@@ -611,5 +617,117 @@ public class ODataJPAResponseBuilderTest extends JPAEdmTestModelView {
     EasyMock.replay(navPropertySegment);
     return navPropertySegment;
   }
+  
+  private GetFunctionImportUriInfo mockFunctionImportUriInfo() {
 
+    List<SelectItem> selectItemList = new ArrayList<SelectItem>();
+    List<ArrayList<NavigationPropertySegment>> expandList = new 
+    		ArrayList<ArrayList<NavigationPropertySegment>>();
+    ArrayList<NavigationPropertySegment> navigationPropertyList = new ArrayList<NavigationPropertySegment>();
+    // Mocking the navigation property
+    EdmNavigationProperty navigationProperty = EasyMock.createMock(EdmNavigationProperty.class);
+    try {
+      EasyMock.expect(navigationProperty.getName()).andStubReturn("SalesOrderItemDetails");
+    } catch (EdmException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + 
+    		  ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    }
+    EasyMock.replay(navigationProperty);
+    
+    // Mocking the navigation property segments and adding to expand list
+    NavigationPropertySegment navigationPropertySegment = EasyMock.createMock(NavigationPropertySegment.class);
+    EasyMock.expect(navigationPropertySegment.getNavigationProperty()).andStubReturn(navigationProperty);
+    EasyMock.expect(navigationPropertySegment.getTargetEntitySet())
+    .andStubReturn(getTargetEntitySetForExpand());
+    EasyMock.replay(navigationPropertySegment);
+    navigationPropertyList.add(navigationPropertySegment);
+    expandList.add(navigationPropertyList);
+    // Mocking EntityUriInfo
+    UriInfoImpl functionImportUriInfo = EasyMock.createMock(UriInfoImpl.class);
+    EasyMock.expect(functionImportUriInfo.getSelect()).andStubReturn(selectItemList);
+    EasyMock.expect(functionImportUriInfo.getExpand()).andStubReturn(expandList);
+    EasyMock.expect(functionImportUriInfo.getInlineCount()).andStubReturn(InlineCount.ALLPAGES);
+    EasyMock.expect(functionImportUriInfo.getFunctionImport()).andStubReturn(mockEdmFunctionImport());
+    EasyMock.expect(functionImportUriInfo.getCustomQueryOptions()).andStubReturn(null);
+    EasyMock.replay(functionImportUriInfo);
+    return functionImportUriInfo;
+  }
+  
+  private EdmFunctionImport mockEdmFunctionImport() {
+  EdmFunctionImport funcImport = EasyMock.createMock(EdmFunctionImport.class);
+    try {
+		EasyMock.expect(funcImport.getName()).andStubReturn("FindAllSalesOrders");
+		EasyMock.expect(funcImport.getEntitySet()).andStubReturn(getLocalTargetEntitySet());
+		EasyMock.expect(funcImport.getParameterNames()).andStubReturn(
+				Arrays.asList("DeliveryStatusCode"));
+		EdmTyped typed = EasyMock.createMock(EdmTyped.class);
+		EasyMock.expect(typed.getName()).andStubReturn("SalesOrder");
+		EasyMock.expect(typed.getMultiplicity()).andStubReturn(EdmMultiplicity.MANY);
+		EasyMock.expect(typed.getType()).andStubReturn(getLocalEdmEntityType());
+		EasyMock.replay(typed);
+		EasyMock.expect(funcImport.getReturnType()).andStubReturn(typed);
+	} catch (EdmException e) {
+		fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + 
+				e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+	}
+    EasyMock.replay(funcImport);
+    return funcImport;
+  }
+  /*
+   * This Unit is supposed to test the building of Entity Provider Properties for function import
+   */
+  @Test
+  public void testFunctionImportProviderProperties() {
+
+    // Getting the EntityUriInfo
+    GetFunctionImportUriInfo getfuncImportUriInfo = mockFunctionImportUriInfo();
+    ODataJPAContext oDataJPAContext = getODataJPAContext();
+    Class<?> clazz = ODataJPAResponseBuilderDefault.class;
+ // Building the edm entity
+    List<Map<String, Object>> edmEntityList = new ArrayList<Map<String, Object>>();
+    Map<String, Object> edmEntity = new HashMap<String, Object>();
+    edmEntity.put("ID", 1);
+    edmEntityList.add(edmEntity);
+    Object[] actualParameters = { oDataJPAContext, getfuncImportUriInfo, edmEntityList };
+    Class<?>[] formalParameters = { ODataJPAContext.class, GetFunctionImportUriInfo.class, List.class };
+    EntityProviderWriteProperties providerProperties = null;
+    try {
+      Method method = clazz.getDeclaredMethod("getEntityProviderProperties", formalParameters);
+      method.setAccessible(true);
+      providerProperties = (EntityProviderWriteProperties) method.invoke(responseBuilder, actualParameters);
+      assertEquals(1, providerProperties.getExpandSelectTree().getLinks().size());
+      assertEquals(InlineCount.ALLPAGES, providerProperties.getInlineCountType());
+    } catch (SecurityException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    } catch (NoSuchMethodException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    } catch (IllegalArgumentException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    } catch (IllegalAccessException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    } catch (InvocationTargetException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    }
+
+  }
+
+  @Test
+  public void testBuildListOfGetFunctionimportUriInfo() throws Exception {
+    try {
+      assertNotNull(responseBuilder.build(getFIResultsView(), getJPAEntities(), "application/xml"));
+    } catch (ODataJPARuntimeException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    }
+
+  }
+  
+  private GetFunctionImportUriInfo getFIResultsView() {
+	GetFunctionImportUriInfo objGetFunctionImportUriInfo = EasyMock.createMock(GetFunctionImportUriInfo.class);
+    EasyMock.expect(objGetFunctionImportUriInfo.getInlineCount()).andStubReturn(getLocalInlineCount());
+    EasyMock.expect(objGetFunctionImportUriInfo.getFunctionImport()).andStubReturn(mockEdmFunctionImport());
+    EasyMock.expect(objGetFunctionImportUriInfo.getSelect()).andStubReturn(getSelectItemList());
+    EasyMock.expect(objGetFunctionImportUriInfo.getExpand()).andStubReturn(getExpandList());
+    EasyMock.replay(objGetFunctionImportUriInfo);
+    return objGetFunctionImportUriInfo;
+  }
 }
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/info/GetFunctionImportUriInfo.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/info/GetFunctionImportUriInfo.java
index 56ad943..92c5886 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/info/GetFunctionImportUriInfo.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/info/GetFunctionImportUriInfo.java
@@ -18,10 +18,15 @@
  ******************************************************************************/
 package org.apache.olingo.odata2.api.uri.info;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
+import org.apache.olingo.odata2.api.commons.InlineCount;
 import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
 import org.apache.olingo.odata2.api.edm.EdmLiteral;
+import org.apache.olingo.odata2.api.uri.NavigationPropertySegment;
+import org.apache.olingo.odata2.api.uri.SelectItem;
 
 /**
  * Access to the parts of the request URI that are relevant for requests
@@ -57,4 +62,25 @@ public interface GetFunctionImportUriInfo {
    * @return Map of {@literal <String, String>} custom query options
    */
   public Map<String, String> getCustomQueryOptions();
+  
+  /**
+   * Gets the value of the $inlinecount system query option.
+   * @return {@link InlineCount} the inline count or null
+   */
+  public InlineCount getInlineCount();
+  
+  /**
+   * Gets the value of the $select system query option as a list of select items,
+   * or an empty list if not used.
+   * @return List of {@link SelectItem} to be selected
+   */
+  public List<SelectItem> getSelect();
+  
+  /**
+   * Gets the value of the $expand system query option as a list of
+   * lists of navigation-property segments, or an empty list if not used.
+   * @return List of a list of {@link NavigationPropertySegment} to be expanded
+   */
+  public List<ArrayList<NavigationPropertySegment>> getExpand();
+
 }