[OLINGO-1143] Support of Expand of a navigation property of a complex type

Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/aaff527d
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/aaff527d
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/aaff527d

Branch: refs/heads/master
Commit: aaff527dcd43d5f68d6407c8ab9b031a0e53c38e
Parents: fd8bfa3
Author: ramya vasanth <ramya.vasa...@sap.com>
Authored: Wed Apr 11 11:15:38 2018 +0530
Committer: ramya vasanth <ramya.vasa...@sap.com>
Committed: Wed Apr 11 11:15:38 2018 +0530

----------------------------------------------------------------------
 .../client/ExpandWithComplexPropertyITCase.java | 348 +++++++++++++++++++
 .../http/DerivedAndMixedTypeTestITCase.java     |  81 ++---
 .../serializer/json/ODataJsonSerializer.java    |  91 ++++-
 .../serializer/utils/ExpandSelectHelper.java    | 130 ++++++-
 .../core/serializer/xml/ODataXmlSerializer.java |  87 ++++-
 .../server/core/uri/parser/ExpandParser.java    |   2 +-
 .../olingo/server/tecsvc/data/ActionData.java   |   8 +-
 .../olingo/server/tecsvc/data/DataCreator.java  | 133 ++++++-
 .../olingo/server/tecsvc/data/FunctionData.java |   2 +
 .../tecsvc/provider/ComplexTypeProvider.java    |  13 +-
 .../json/ODataJsonSerializerTest.java           |  84 ++++-
 .../json/ODataJsonSerializerv01Test.java        |  12 +-
 .../serializer/xml/ODataXmlSerializerTest.java  | 112 +++++-
 13 files changed, 997 insertions(+), 106 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ExpandWithComplexPropertyITCase.java
----------------------------------------------------------------------
diff --git 
a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ExpandWithComplexPropertyITCase.java
 
b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ExpandWithComplexPropertyITCase.java
new file mode 100644
index 0000000..43f9671
--- /dev/null
+++ 
b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ExpandWithComplexPropertyITCase.java
@@ -0,0 +1,348 @@
+/*
+ * 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.fit.tecsvc.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import 
org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest;
+import 
org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
+import org.apache.olingo.client.api.domain.ClientCollectionValue;
+import org.apache.olingo.client.api.domain.ClientComplexValue;
+import org.apache.olingo.client.api.domain.ClientEntity;
+import org.apache.olingo.client.api.domain.ClientLink;
+import org.apache.olingo.client.api.domain.ClientProperty;
+import org.apache.olingo.client.api.domain.ClientValue;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.fit.tecsvc.TecSvcConst;
+import org.junit.Test;
+
+public class ExpandWithComplexPropertyITCase extends AbstractParamTecSvcITCase 
{
+
+  @Test
+  public void readExpandHavingComplexProperty1() {
+    ODataEntityRequest<ClientEntity> request = 
getClient().getRetrieveRequestFactory()
+        .getEntityRequest(getClient().newURIBuilder(TecSvcConst.BASE_URI)
+            
.appendEntitySetSegment("ESCompMixPrimCollComp").appendKeySegment(1)
+            
.expand("PropertyMixedPrimCollComp/PropertyComp/NavPropertyETTwoKeyNavOne($expand=NavPropertySINav),"
+                + 
"PropertyMixedPrimCollComp/PropertyComp/NavPropertyETMediaOne")
+            .build());
+    assertNotNull(request);
+    setCookieHeader(request);
+
+    final ODataRetrieveResponse<ClientEntity> response = request.execute();
+    saveCookieHeader(response);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ClientEntity entity = response.getBody();
+    assertNotNull(entity);
+
+    assertNotNull(entity.getProperties());
+    assertEquals(2, entity.getProperties().size());
+    assertNotNull(entity.getProperty("PropertyMixedPrimCollComp"));
+
+    ClientProperty property = entity.getProperty("PropertyInt16");
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertShortOrInt(Integer.valueOf(1), 
property.getPrimitiveValue().toValue());
+
+    property = entity.getProperty("PropertyMixedPrimCollComp");
+    assertNotNull(property);
+    ClientComplexValue complexValue = property.getComplexValue();
+    assertNotNull(complexValue);
+    property = complexValue.get("PropertyComp");
+    assertNotNull(property);
+    complexValue = property.getComplexValue();
+    assertNotNull(complexValue);
+    if (isJson()) {
+      property = complexValue.get("NavPropertyETTwoKeyNavOne");
+      assertNotNull(property);
+      assertNotNull(complexValue.get("NavPropertyETMediaOne"));
+      complexValue = property.getComplexValue();
+      assertNotNull(complexValue);
+      assertNotNull(complexValue.get("NavPropertySINav"));
+    } else {
+      ClientLink etkeyNavOneLink = 
complexValue.getNavigationLink("NavPropertyETTwoKeyNavOne");
+      assertNotNull(etkeyNavOneLink);
+      ClientEntity navEntity = etkeyNavOneLink.asInlineEntity().getEntity();
+      assertNotNull(navEntity.getNavigationLink("NavPropertySINav"));
+      
assertNotNull(navEntity.getNavigationLink("NavPropertySINav").asInlineEntity().getEntity());
+      assertNotNull(complexValue.getNavigationLink("NavPropertyETMediaOne"));
+    }
+  }
+  
+  @Test
+  public void readExpandHavingComplexProperty2() {
+    ODataEntityRequest<ClientEntity> request = 
getClient().getRetrieveRequestFactory()
+        .getEntityRequest(getClient().newURIBuilder(TecSvcConst.BASE_URI)
+            
.appendEntitySetSegment("ESCompMixPrimCollComp").appendKeySegment(1)
+            .expand("PropertyMixedPrimCollComp/NavPropertyETTwoKeyNavOne,"
+                + 
"PropertyMixedPrimCollComp/PropertyComp/NavPropertyETMediaOne")
+            .build());
+    assertNotNull(request);
+    setCookieHeader(request);
+    if (isJson()) {
+      request.setAccept("application/json;odata.metadata=full");
+    }
+
+    final ODataRetrieveResponse<ClientEntity> response = request.execute();
+    saveCookieHeader(response);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ClientEntity entity = response.getBody();
+    assertNotNull(entity);
+
+    assertNotNull(entity.getProperties());
+    assertEquals(2, entity.getProperties().size());
+    assertNotNull(entity.getProperty("PropertyMixedPrimCollComp"));
+
+    ClientProperty property = entity.getProperty("PropertyInt16");
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertShortOrInt(Integer.valueOf(1), 
property.getPrimitiveValue().toValue());
+
+    property = entity.getProperty("PropertyMixedPrimCollComp");
+    assertNotNull(property);
+    ClientComplexValue complexValue = property.getComplexValue();
+    assertNotNull(complexValue);
+    ClientLink etkeyNavLink = 
complexValue.getNavigationLink("NavPropertyETTwoKeyNavOne");
+    assertNotNull(etkeyNavLink);
+    assertNotNull(etkeyNavLink.asInlineEntity().getEntity());
+    property = complexValue.get("PropertyComp");
+    assertNotNull(property);
+    complexValue = property.getComplexValue();
+    assertNotNull(complexValue);
+    ClientLink etMediaOneNav = 
complexValue.getNavigationLink("NavPropertyETMediaOne");
+    assertNotNull(etMediaOneNav);
+    assertNotNull(etMediaOneNav.asInlineEntity().getEntity());
+  }
+  
+  @Test
+  public void readExpandHavingComplexProperty3() {
+    ODataEntityRequest<ClientEntity> request = 
getClient().getRetrieveRequestFactory()
+        .getEntityRequest(getClient().newURIBuilder(TecSvcConst.BASE_URI)
+            
.appendEntitySetSegment("ESCompMixPrimCollComp").appendKeySegment(1)
+            .expand("PropertyMixedPrimCollComp/NavPropertyETTwoKeyNavOne,"
+                + 
"PropertyMixedPrimCollComp/PropertyComp/NavPropertyETMediaOne,"
+                + 
"PropertyMixedPrimCollComp/PropertyComp/NavPropertyETTwoKeyNavOne")
+            .build());
+    assertNotNull(request);
+    setCookieHeader(request);
+
+    final ODataRetrieveResponse<ClientEntity> response = request.execute();
+    saveCookieHeader(response);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ClientEntity entity = response.getBody();
+    assertNotNull(entity);
+
+    assertNotNull(entity.getProperties());
+    assertEquals(2, entity.getProperties().size());
+    assertNotNull(entity.getProperty("PropertyMixedPrimCollComp"));
+
+    ClientProperty property = entity.getProperty("PropertyInt16");
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertShortOrInt(Integer.valueOf(1), 
property.getPrimitiveValue().toValue());
+
+    property = entity.getProperty("PropertyMixedPrimCollComp");
+    assertNotNull(property);
+    ClientComplexValue complexValue = property.getComplexValue();
+    assertNotNull(complexValue);
+    if (isJson()) {
+      assertNotNull(complexValue.get("NavPropertyETTwoKeyNavOne"));
+    } else {
+      
assertNotNull(complexValue.getNavigationLink("NavPropertyETTwoKeyNavOne"));
+    }
+    property = complexValue.get("PropertyComp");
+    assertNotNull(property);
+    complexValue = property.getComplexValue();
+    assertNotNull(complexValue);
+    if (isJson()) {
+      assertNotNull(complexValue.get("NavPropertyETMediaOne"));
+      assertNotNull(complexValue.get("NavPropertyETTwoKeyNavOne"));
+    } else {
+      assertNotNull(complexValue.getNavigationLink("NavPropertyETMediaOne"));
+      
assertNotNull(complexValue.getNavigationLink("NavPropertyETMediaOne").asInlineEntity().getEntity());
+      
assertNotNull(complexValue.getNavigationLink("NavPropertyETTwoKeyNavOne"));
+      
assertNotNull(complexValue.getNavigationLink("NavPropertyETTwoKeyNavOne").asInlineEntity().getEntity());
+    }
+  }
+  
+  @Test
+  public void readExpandHavingCollComplexProperty1() {
+    ODataEntityRequest<ClientEntity> request = 
getClient().getRetrieveRequestFactory()
+        .getEntityRequest(getClient().newURIBuilder(TecSvcConst.BASE_URI)
+            
.appendEntitySetSegment("ESCompMixPrimCollComp").appendKeySegment(1)
+            
.expand("PropertyMixedPrimCollComp/CollPropertyComp/NavPropertyETTwoKeyNavOne")
+            .build());
+    assertNotNull(request);
+    setCookieHeader(request);
+
+    final ODataRetrieveResponse<ClientEntity> response = request.execute();
+    saveCookieHeader(response);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ClientEntity entity = response.getBody();
+    assertNotNull(entity);
+
+    assertNotNull(entity.getProperties());
+    assertEquals(2, entity.getProperties().size());
+    assertNotNull(entity.getProperty("PropertyMixedPrimCollComp"));
+
+    ClientProperty property = entity.getProperty("PropertyInt16");
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertShortOrInt(Integer.valueOf(1), 
property.getPrimitiveValue().toValue());
+
+    property = entity.getProperty("PropertyMixedPrimCollComp");
+    assertNotNull(property);
+    ClientComplexValue complexValue = property.getComplexValue();
+    assertNotNull(complexValue);
+    property = complexValue.get("CollPropertyComp");
+    assertNotNull(property);
+    ClientCollectionValue<ClientValue> complexValues = 
property.getCollectionValue();
+    assertNotNull(complexValues);
+    for (ClientValue value : complexValues) {
+      if (isJson()) {
+        ClientComplexValue innerComplexValue = value.asComplex();
+        assertNotNull(innerComplexValue.get("NavPropertyETTwoKeyNavOne"));
+        property = innerComplexValue.get("NavPropertyETTwoKeyNavOne");
+        assertEquals(8, property.getValue().asComplex().size());
+      } else {
+        ClientComplexValue innerComplexValue = value.asComplex();
+        ClientLink link = 
innerComplexValue.getNavigationLink("NavPropertyETTwoKeyNavOne");
+        assertNotNull(link);
+        assertNotNull(link.asInlineEntity());
+        assertEquals(8, 
link.asInlineEntity().getEntity().getProperties().size());
+      }
+    }
+  }
+  
+  @Test
+  public void readExpandHavingCollComplexProperty2() {
+    ODataEntityRequest<ClientEntity> request = 
getClient().getRetrieveRequestFactory()
+        .getEntityRequest(getClient().newURIBuilder(TecSvcConst.BASE_URI)
+            
.appendEntitySetSegment("ESMixPrimCollComp").appendKeySegment(32767)
+            
.expand("CollPropertyComp/NavPropertyETTwoKeyNavOne,PropertyComp/NavPropertyETTwoKeyNavOne")
+            .build());
+    assertNotNull(request);
+    setCookieHeader(request);
+    
+    if (isJson()) {
+      request.setAccept("application/json;odata.metadata=full");
+    }
+
+    final ODataRetrieveResponse<ClientEntity> response = request.execute();
+    saveCookieHeader(response);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ClientEntity entity = response.getBody();
+    assertNotNull(entity);
+
+    assertNotNull(entity.getProperties());
+    assertEquals(4, entity.getProperties().size());
+    assertNotNull(entity.getProperty("CollPropertyComp"));
+
+    ClientProperty property = entity.getProperty("CollPropertyComp");
+    assertNotNull(property);
+    ClientCollectionValue<ClientValue> complexValues = 
property.getCollectionValue();
+    assertNotNull(complexValues);
+    assertEquals(3, complexValues.size());
+    for (ClientValue value : complexValues) {
+      ClientComplexValue complexValue = value.asComplex();
+      ClientLink link = 
complexValue.getNavigationLink("NavPropertyETTwoKeyNavOne");
+      assertNotNull(link);
+      assertNotNull(link.asInlineEntity());
+      assertEquals(8, 
link.asInlineEntity().getEntity().getProperties().size());
+    }
+    property = entity.getProperty("PropertyComp");
+    assertNotNull(property);
+    ClientComplexValue complexValue = property.getComplexValue();
+    assertNotNull(complexValue);
+    ClientLink link = 
complexValue.getNavigationLink("NavPropertyETTwoKeyNavOne");
+    assertNotNull(link);
+    assertNotNull(link.asInlineEntity());
+    assertEquals(8, link.asInlineEntity().getEntity().getProperties().size());
+  }
+  
+  @Test
+  public void readExpandHavingCollComplexPropertyWith$ref$count() {
+    ODataEntityRequest<ClientEntity> request = 
getClient().getRetrieveRequestFactory()
+        .getEntityRequest(getClient().newURIBuilder(TecSvcConst.BASE_URI)
+            
.appendEntitySetSegment("ESCompMixPrimCollComp").appendKeySegment(1)
+            
.expand("PropertyMixedPrimCollComp/PropertyComp/NavPropertyETTwoKeyNavOne/$ref,"
+                + 
"PropertyMixedPrimCollComp/PropertyComp/NavPropertyETMediaOne/$ref,"
+                + 
"PropertyMixedPrimCollComp/NavPropertyETTwoKeyNavMany/$count")
+            .build());
+    assertNotNull(request);
+    setCookieHeader(request);
+    
+    final ODataRetrieveResponse<ClientEntity> response = request.execute();
+    saveCookieHeader(response);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    final ClientEntity entity = response.getBody();
+    assertNotNull(entity);
+
+    assertNotNull(entity.getProperties());
+    assertEquals(2, entity.getProperties().size());
+
+    ClientProperty property = entity.getProperty("PropertyMixedPrimCollComp");
+    assertNotNull(property);
+    ClientComplexValue complexValue = property.getComplexValue();
+    assertNotNull(complexValue);
+    ClientLink link = null;
+    if (isJson()) {
+      property = complexValue.get("NavPropertyETTwoKeyNavMany@odata.count");
+      assertNotNull(property.getPrimitiveValue());
+      assertEquals(Integer.valueOf(2), property.getPrimitiveValue().toValue());
+    } else {
+      link = complexValue.getNavigationLink("NavPropertyETTwoKeyNavMany");
+      assertNotNull(link);
+      assertNotNull(link.getLink());
+      assertNotNull(link.asInlineEntitySet().getEntitySet());
+      assertEquals(Integer.valueOf(2), 
link.asInlineEntitySet().getEntitySet().getCount());
+    }
+    
+    property = complexValue.get("PropertyComp");
+    assertNotNull(property);
+    ClientComplexValue innerComplexValue = property.getComplexValue();
+    assertNotNull(innerComplexValue);
+    if (isJson()) {
+      property = innerComplexValue.get("NavPropertyETTwoKeyNavOne");
+      assertNotNull(property);
+      assertEquals("odata.id", 
property.getComplexValue().getAnnotations().get(0).getTerm());
+      
assertEquals(String.valueOf("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')"), 
+          
property.getComplexValue().getAnnotations().get(0).getPrimitiveValue().toValue());
+      property = innerComplexValue.get("NavPropertyETMediaOne");
+      assertNotNull(property);
+      assertEquals("odata.id", 
property.getComplexValue().getAnnotations().get(3).getTerm());
+      assertEquals(String.valueOf("ESMedia(2)"), 
+          
property.getComplexValue().getAnnotations().get(3).getPrimitiveValue().toValue());
+    } else {
+      link = innerComplexValue.getNavigationLink("NavPropertyETTwoKeyNavOne");
+      assertNotNull(link);
+      assertNotNull(link.getLink());
+      link = innerComplexValue.getNavigationLink("NavPropertyETMediaOne");
+      assertNotNull(link);
+      assertNotNull(link.getLink());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/DerivedAndMixedTypeTestITCase.java
----------------------------------------------------------------------
diff --git 
a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/DerivedAndMixedTypeTestITCase.java
 
b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/DerivedAndMixedTypeTestITCase.java
index 69fe65e..ce41951 100644
--- 
a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/DerivedAndMixedTypeTestITCase.java
+++ 
b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/DerivedAndMixedTypeTestITCase.java
@@ -188,70 +188,65 @@ public class DerivedAndMixedTypeTestITCase extends 
AbstractBaseTestITCase {
         
ContentType.create(connection.getHeaderField(HttpHeader.CONTENT_TYPE)));
 
     final String content = IOUtils.toString(connection.getInputStream());
-    final String actualContent = "\"value\":"
-        + "[{\"@odata.type\":\"#olingo.odata.test1.ETMixPrimCollComp\","
+    final String actualContent = 
"\"value\":[{\"@odata.type\":\"#olingo.odata.test1.ETMixPrimCollComp\","
         + "\"@odata.id\":\"ESMixPrimCollComp(32767)\","
-        + "\"propertyin...@odata.type\":\"#Int16\","
-        + "\"PropertyInt16\":32767,"
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":32767,"
         + "\"collpropertystr...@odata.type\":\"#Collection(String)\","
-        + "\"CollPropertyString\":"
-        + "[\"Employee1@company.example\",\"Employee2@company.example\","
+        + 
"\"CollPropertyString\":[\"Employee1@company.example\",\"Employee2@company.example\","
         + "\"Employee3@company.example\"],"
-        + "\"PropertyComp\":"
-        + "{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+        + 
"\"PropertyComp\":{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
         + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":111,"
-        + "\"PropertyString\":\"TEST A\"},"
+        + "\"PropertyString\":\"TEST A\","
+        + 
"\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='1')\"},"
         + 
"\"collpropertyc...@odata.type\":\"#Collection(olingo.odata.test1.CTTwoPrim)\","
-        + "\"CollPropertyComp\":"
-        + "[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+        + 
"\"CollPropertyComp\":[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
         + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":123,"
-        + "\"PropertyString\":\"TEST 1\"},"
+        + "\"PropertyString\":\"TEST 1\","
+        + 
"\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"},"
         + "{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
-        + "\"propertyin...@odata.type\":\"#Int16\","
-        + "\"PropertyInt16\":456,"
-        + "\"PropertyString\":\"TEST 2\"},"
-        + "{\"@odata.type\":\"#olingo.odata.test1.CTBase\","
-        + "\"propertyin...@odata.type\":\"#Int16\","
-        + "\"PropertyInt16\":789,"
-        + "\"PropertyString\":\"TEST 3\","
-        + "\"AdditionalPropString\":\"ADD TEST\"}],"
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":456,"
+        + "\"PropertyString\":\"TEST 2\","
+        + 
"\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"},"
+        + 
"{\"@odata.type\":\"#olingo.odata.test1.CTBase\",\"propertyin...@odata.type\":\"#Int16\","
+        + "\"PropertyInt16\":789,\"PropertyString\":\"TEST 3\","
+        + "\"AdditionalPropString\":\"ADD TEST\","
+        + 
"\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"}],"
         + "\"#olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\":"
         + "{\"title\":\"olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\","
         + 
"\"target\":\"ESMixPrimCollComp(32767)/olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\"}},"
         + "{\"@odata.type\":\"#olingo.odata.test1.ETMixPrimCollComp\","
         + "\"@odata.id\":\"ESMixPrimCollComp(7)\","
-        + "\"propertyin...@odata.type\":\"#Int16\","
-        + 
"\"PropertyInt16\":7,\"collpropertystr...@odata.type\":\"#Collection(String)\","
-        + "\"CollPropertyString\":[\"Employee1@company.example\","
-        + "\"Employee2@company.example\","
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":7,"
+        + "\"collpropertystr...@odata.type\":\"#Collection(String)\","
+        + 
"\"CollPropertyString\":[\"Employee1@company.example\",\"Employee2@company.example\","
         + "\"Employee3@company.example\"],"
         + 
"\"PropertyComp\":{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
-        + 
"\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":222,\"PropertyString\":\"TEST
 B\"},"
+        + "\"propertyin...@odata.type\":\"#Int16\","
+        + "\"PropertyInt16\":222,\"PropertyString\":\"TEST B\"},"
         + 
"\"collpropertyc...@odata.type\":\"#Collection(olingo.odata.test1.CTTwoPrim)\","
         + 
"\"CollPropertyComp\":[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
-        + 
"\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":123,\"PropertyString\":\"TEST
 1\"},"
-        + 
"{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\",\"propertyin...@odata.type\":\"#Int16\","
-        + "\"PropertyInt16\":456,\"PropertyString\":\"TEST 
2\"},{\"@odata.type\":\"#olingo.odata.test1.CTBase\","
-        + 
"\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":789,\"PropertyString\":\"TEST
 3\","
-        + "\"AdditionalPropString\":\"ADD TEST\"}],"
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":123,"
+        + "\"PropertyString\":\"TEST 
1\"},{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+        + 
"\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":456,\"PropertyString\":\"TEST
 2\"},"
+        + 
"{\"@odata.type\":\"#olingo.odata.test1.CTBase\",\"propertyin...@odata.type\":\"#Int16\","
+        + "\"PropertyInt16\":789,\"PropertyString\":\"TEST 
3\",\"AdditionalPropString\":\"ADD TEST\"}],"
         + "\"#olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\":"
         + "{\"title\":\"olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\","
         + 
"\"target\":\"ESMixPrimCollComp(7)/olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\"}},"
-        + "{\"@odata.type\":\"#olingo.odata.test1.ETMixPrimCollComp\","
-        + 
"\"@odata.id\":\"ESMixPrimCollComp(0)\",\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":0,"
-        + 
"\"collpropertystr...@odata.type\":\"#Collection(String)\",\"CollPropertyString\":"
-        + 
"[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
-        + 
"\"PropertyComp\":{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\",\"propertyin...@odata.type\":\"#Int16\","
-        + "\"PropertyInt16\":333,\"PropertyString\":\"TEST C\"},"
+        + 
"{\"@odata.type\":\"#olingo.odata.test1.ETMixPrimCollComp\",\"@odata.id\":\"ESMixPrimCollComp(0)\","
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":0,"
+        + "\"collpropertystr...@odata.type\":\"#Collection(String)\","
+        + 
"\"CollPropertyString\":[\"Employee1@company.example\",\"Employee2@company.example\","
+        + "\"Employee3@company.example\"],"
+        + 
"\"PropertyComp\":{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+        + 
"\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":333,\"PropertyString\":\"TEST
 C\"},"
         + 
"\"collpropertyc...@odata.type\":\"#Collection(olingo.odata.test1.CTTwoPrim)\","
-        + "\"CollPropertyComp\":"
-        + "[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
-        + 
"\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":123,\"PropertyString\":\"TEST
 1\"},"
-        + "{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+        + 
"\"CollPropertyComp\":[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":123,"
+        + "\"PropertyString\":\"TEST 
1\"},{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
         + 
"\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":456,\"PropertyString\":\"TEST
 2\"},"
-        + "{\"@odata.type\":\"#olingo.odata.test1.CTBase\","
-        + 
"\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":789,\"PropertyString\":\"TEST
 3\","
-        + "\"AdditionalPropString\":\"ADD TEST\"}],"
+        + 
"{\"@odata.type\":\"#olingo.odata.test1.CTBase\",\"propertyin...@odata.type\":\"#Int16\","
+        + "\"PropertyInt16\":789,\"PropertyString\":\"TEST 
3\",\"AdditionalPropString\":\"ADD TEST\"}],"
         + "\"#olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\":"
         + "{\"title\":\"olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\","
         + 
"\"target\":\"ESMixPrimCollComp(0)/olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\"}}]";

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
index 970d0c2..9f9ab97 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
@@ -450,7 +450,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
           }
         }
         
-        writeProperties(metadata, resolvedType, entity.getProperties(), 
select, json);
+        writeProperties(metadata, resolvedType, entity.getProperties(), 
select, json, entity, expand);
         writeExpandedStreamProperties(metadata, resolvedType, entity, expand, 
toDepth, ancestors, name, json);
         writeNavigationProperties(metadata, resolvedType, entity, expand, 
toDepth, ancestors, name, json);
         writeOperations(entity.getOperations(), json);      
@@ -525,19 +525,20 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
 
   protected void writeProperties(final ServiceMetadata metadata, final 
EdmStructuredType type,
       final List<Property> properties,
-      final SelectOption select, final JsonGenerator json)
+      final SelectOption select, final JsonGenerator json, Linked linked, 
ExpandOption expand)
       throws IOException, SerializerException {
     final boolean all = ExpandSelectHelper.isAll(select);
     final Set<String> selected = all ? new HashSet<String>() :
         ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems());
     addKeyPropertiesToSelected(selected, type);
+    Set<List<String>> expandedPaths = 
ExpandSelectHelper.getExpandedItemsPath(expand);
     for (final String propertyName : type.getPropertyNames()) {
       if (all || selected.contains(propertyName)) {
         final EdmProperty edmProperty = 
type.getStructuralProperty(propertyName);
         final Property property = findProperty(propertyName, properties);
         final Set<List<String>> selectedPaths = all || 
edmProperty.isPrimitive() ? null :
             ExpandSelectHelper.getSelectedPaths(select.getSelectItems(), 
propertyName);
-        writeProperty(metadata, edmProperty, property, selectedPaths, json);
+        writeProperty(metadata, edmProperty, property, selectedPaths, json, 
expandedPaths, linked, expand);
       }
     }
   }
@@ -572,7 +573,8 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
     if ((toDepth != null && toDepth > 1) || (toDepth == null && 
ExpandSelectHelper.hasExpand(expand))) {
       final ExpandItem expandAll = ExpandSelectHelper.getExpandAll(expand);
       for (final String propertyName : type.getNavigationPropertyNames()) {
-        final ExpandItem innerOptions = 
ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
+        final ExpandItem innerOptions = 
ExpandSelectHelper.getExpandItemBasedOnType(expand.getExpandItems(), 
+            propertyName, type, name);
         if (innerOptions != null || expandAll != null || toDepth != null) {
           Integer levels = null;
           final EdmNavigationProperty property = 
type.getNavigationProperty(propertyName);
@@ -698,7 +700,8 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
 
   protected void writeProperty(final ServiceMetadata metadata,
       final EdmProperty edmProperty, final Property property,
-      final Set<List<String>> selectedPaths, final JsonGenerator json)
+      final Set<List<String>> selectedPaths, final JsonGenerator json, 
+      Set<List<String>> expandedPaths, Linked linked, ExpandOption expand)
       throws IOException, SerializerException {
     boolean isStreamProperty = isStreamProperty(edmProperty);
     writePropertyType(edmProperty, json);
@@ -720,7 +723,8 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
         }
       }
     } else {
-      writePropertyValue(metadata, edmProperty, property, selectedPaths, json);
+      writePropertyValue(metadata, edmProperty, property, selectedPaths, json, 
+          expandedPaths, linked, expand);
     }
   }
   
@@ -762,7 +766,8 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
   }
 
   private void writePropertyValue(final ServiceMetadata metadata, final 
EdmProperty edmProperty,
-      final Property property, final Set<List<String>> selectedPaths, final 
JsonGenerator json)
+      final Property property, final Set<List<String>> selectedPaths, final 
JsonGenerator json, 
+      Set<List<String>> expandedPaths, Linked linked, ExpandOption expand)
       throws IOException, SerializerException {
     final EdmType type = edmProperty.getType();
     try {
@@ -779,9 +784,11 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
         }
       } else if (property.isComplex()) {
         if (edmProperty.isCollection()) {
-          writeComplexCollection(metadata, (EdmComplexType) type, property, 
selectedPaths, json);
+          writeComplexCollection(metadata, (EdmComplexType) type, property, 
selectedPaths, 
+              json, expandedPaths, linked, expand);
         } else {
-         writeComplex(metadata, (EdmComplexType) type, property, 
selectedPaths, json);
+         writeComplex(metadata, (EdmComplexType) type, property, 
selectedPaths, json, 
+             expandedPaths, linked, expand);
         }
       } else {
         throw new SerializerException("Property type not yet supported!",
@@ -795,7 +802,8 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
   }
 
   private void writeComplex(final ServiceMetadata metadata, final 
EdmComplexType type,
-      final Property property, final Set<List<String>> selectedPaths, final 
JsonGenerator json) 
+      final Property property, final Set<List<String>> selectedPaths, final 
JsonGenerator json, 
+      Set<List<String>> expandedPaths, Linked linked, ExpandOption expand) 
           throws IOException, SerializerException{
         json.writeStartObject();        
         String derivedName = property.getType();
@@ -816,9 +824,26 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
         if (!isODataMetadataNone && !resolvedType.equals(type) || 
isODataMetadataFull) {
            json.writeStringField(constants.getType(), "#" + 
         resolvedType.getFullQualifiedName().getFullQualifiedNameAsString());
-        }          
+        }
+        
+        if (null != linked) {
+          if (linked instanceof Entity) {
+            linked = 
((Entity)linked).getProperty(property.getName()).asComplex();
+          } else if (linked instanceof ComplexValue) {
+            List<Property> complexProperties = 
((ComplexValue)linked).getValue();
+            for (Property prop : complexProperties) {
+              if (prop.getName().equals(property.getName())) {
+                linked = prop.asComplex();
+                break;
+              }
+            }
+          }
+          expandedPaths = expandedPaths == null || expandedPaths.isEmpty() ? 
null :
+            ExpandSelectHelper.getReducedExpandItemsPaths(expandedPaths, 
property.getName());
+        }
+        
         writeComplexValue(metadata, resolvedType, 
property.asComplex().getValue(), selectedPaths,
-             json);
+             json, expandedPaths, linked, expand, property.getName());
         json.writeEndObject();
   }
 
@@ -851,13 +876,17 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
 
   private void writeComplexCollection(final ServiceMetadata metadata, final 
EdmComplexType type,
       final Property property,
-      final Set<List<String>> selectedPaths, final JsonGenerator json)
+      final Set<List<String>> selectedPaths, final JsonGenerator json, 
+      Set<List<String>> expandedPaths, Linked linked, ExpandOption expand)
       throws IOException, SerializerException {
     json.writeStartArray();
     EdmComplexType derivedType = type;
+    Set<List<String>> expandedPaths1 = expandedPaths != null && 
!expandedPaths.isEmpty() ? 
+        expandedPaths : ExpandSelectHelper.getExpandedItemsPath(expand);
     for (Object value : property.asCollection()) {
+      expandedPaths = expandedPaths1;
       derivedType = ((ComplexValue) value).getTypeName()!=null ? 
metadata.getEdm().getComplexType
-          (new FullQualifiedName(((ComplexValue) value).getTypeName())): type;
+          (new FullQualifiedName(((ComplexValue) value).getTypeName())): type; 
         
       switch (property.getValueType()) {
       case COLLECTION_COMPLEX:
         json.writeStartObject();
@@ -865,7 +894,10 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
              json.writeStringField(constants.getType(), "#" + 
                  
derivedType.getFullQualifiedName().getFullQualifiedNameAsString());
         }
-        writeComplexValue(metadata, derivedType, ((ComplexValue) 
value).getValue(), selectedPaths, json);
+        expandedPaths = expandedPaths == null || expandedPaths.isEmpty() ? 
null :
+          ExpandSelectHelper.getReducedExpandItemsPaths(expandedPaths, 
property.getName());
+        writeComplexValue(metadata, derivedType, ((ComplexValue) 
value).getValue(), 
+            selectedPaths, json, expandedPaths, (ComplexValue) value, expand, 
property.getName());
         json.writeEndObject();
         break;
       default:
@@ -1033,17 +1065,31 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
 
   protected void writeComplexValue(final ServiceMetadata metadata,
       final EdmComplexType type, final List<Property> properties,
-      final Set<List<String>> selectedPaths, final JsonGenerator json)
+      final Set<List<String>> selectedPaths, final JsonGenerator json, 
+      Set<List<String>> expandedPaths, Linked linked, ExpandOption expand, 
String complexPropName)
       throws IOException, SerializerException {
 
+    if (null != expandedPaths) {
+      for(List<String> paths : expandedPaths) {
+        if (!paths.isEmpty() && paths.size() == 1) {
+          expandedPaths = 
ExpandSelectHelper.getReducedExpandItemsPaths(expandedPaths, paths.get(0));
+        }
+      }
+    }
+    
     for (final String propertyName : type.getPropertyNames()) {
       final Property property = findProperty(propertyName, properties);
       if (selectedPaths == null || 
ExpandSelectHelper.isSelected(selectedPaths, propertyName)) {
         writeProperty(metadata, (EdmProperty) type.getProperty(propertyName), 
property,
             selectedPaths == null ? null : 
ExpandSelectHelper.getReducedSelectedPaths(selectedPaths, propertyName),
-            json);
+            json, expandedPaths, linked, expand);
       }
     }
+    try {
+      writeNavigationProperties(metadata, type, linked, expand, null, null, 
complexPropName, json);
+    } catch (DecoderException e) {
+      throw new SerializerException(IO_EXCEPTION_TEXT, e, 
SerializerException.MessageKeys.IO_EXCEPTION);
+    }
   }
 
   private Property findProperty(final String propertyName, final 
List<Property> properties) {
@@ -1135,7 +1181,9 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
       writeOperations(property.getOperations(), json);      
       final List<Property> values =
           property.isNull() ? Collections.<Property> emptyList() : 
property.asComplex().getValue();
-      writeProperties(metadata, type, values, options == null ? null : 
options.getSelect(), json);
+      writeProperties(metadata, type, values, options == null ? null : options 
== null ? null : options.getSelect(), 
+          json, 
+          property.asComplex(), options == null ? null : options.getExpand());
       if (!property.isNull() && property.isComplex()) {
         writeNavigationProperties(metadata, type, property.asComplex(),
             options == null ? null : options.getExpand(), null, null, name, 
json);
@@ -1221,7 +1269,12 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
         selectedPaths = all || property.isPrimitive() ? null : 
ExpandSelectHelper
             .getSelectedPaths(options.getSelect().getSelectItems());
       }
-      writeComplexCollection(metadata, type, property, selectedPaths, json);
+      Set<List<String>> expandPaths = null;
+      if (null != options && null != options.getExpand()) {
+        expandPaths = 
ExpandSelectHelper.getExpandedItemsPath(options.getExpand());
+      }
+      writeComplexCollection(metadata, type, property, selectedPaths, json, 
expandPaths, null, 
+          options == null ? null : options.getExpand());
       json.writeEndObject();
 
       json.close();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
index 2fe3b4f..99cb32b 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
@@ -23,14 +23,17 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.uri.UriResource;
 import org.apache.olingo.server.api.uri.UriResourceAction;
 import org.apache.olingo.server.api.uri.UriResourceComplexProperty;
+import org.apache.olingo.server.api.uri.UriResourceCount;
 import org.apache.olingo.server.api.uri.UriResourceEntitySet;
 import org.apache.olingo.server.api.uri.UriResourceFunction;
 import org.apache.olingo.server.api.uri.UriResourceNavigation;
 import org.apache.olingo.server.api.uri.UriResourceProperty;
+import org.apache.olingo.server.api.uri.UriResourceRef;
 import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectItem;
@@ -222,7 +225,7 @@ public abstract class ExpandSelectHelper {
       for (final ExpandItem item : expand.getExpandItems()) {
         if (item.isStar()) {
           return item;
-        }
+        } 
       }
       return null;
     }
@@ -245,7 +248,8 @@ public abstract class ExpandSelectHelper {
       if (item.isStar()) {
           continue;
       }
-      final UriResource resource = 
item.getResourcePath().getUriResourceParts().get(0);
+      final List<UriResource> resourceParts = 
item.getResourcePath().getUriResourceParts();
+      final UriResource resource = resourceParts.get(0);
       if ((resource instanceof UriResourceNavigation
           && propertyName.equals(((UriResourceNavigation) 
resource).getProperty().getName())) ||
           resource instanceof UriResourceProperty
@@ -256,4 +260,126 @@ public abstract class ExpandSelectHelper {
     return null;
   }
 
+  public static Set<List<String>> getExpandedItemsPath(ExpandOption expand) {
+    Set<List<String>> expandPaths = new HashSet<List<String>>();
+    if (expand != null) {
+      List<ExpandItem> expandItems = expand.getExpandItems();
+      for (ExpandItem item : expandItems) {
+        if (item.isStar()) {
+          continue;
+        }
+        List<UriResource> resourceParts = 
item.getResourcePath().getUriResourceParts();
+        if (resourceParts.get(0) instanceof UriResourceComplexProperty) {
+          List<String> path = new ArrayList<String>();
+          for (UriResource resource : resourceParts) {
+            if (resource instanceof UriResourceNavigation) {
+              path.add(((UriResourceNavigation) 
resource).getProperty().getName());
+            } else if (resource instanceof UriResourceProperty) {
+              path.add(((UriResourceProperty) 
resource).getProperty().getName());
+            }
+          }
+          expandPaths.add(path); 
+        }
+      }
+    }
+    return expandPaths;
+  }
+  
+  public static Set<List<String>> getReducedExpandItemsPaths(final 
Set<List<String>> expandItemsPaths,
+      final String propertyName) {
+    Set<List<String>> reducedPaths = new HashSet<List<String>>();
+    for (final List<String> path : expandItemsPaths) {
+      if (propertyName.equals(path.get(0))) {
+        if (path.size() > 1) {
+          reducedPaths.add(path.subList(1, path.size()));
+        }
+      } else {
+        reducedPaths.add(path);
+      }
+    }
+    return reducedPaths.isEmpty() ? null : reducedPaths;
+  }
+  
+  /**
+   * Fetches the expand Item depending upon the type
+   * @param expandItems
+   * @param propertyName
+   * @param type
+   * @param resourceName
+   * @return
+   */
+  public static ExpandItem getExpandItemBasedOnType(final List<ExpandItem> 
expandItems, 
+      final String propertyName, final EdmStructuredType type, String 
resourceName) {
+    ExpandItem expandItem = null;
+    for (final ExpandItem item : expandItems) {
+      boolean matched = false;
+      if (item.isStar()) {
+          continue;
+      }
+      final List<UriResource> resourceParts = 
item.getResourcePath().getUriResourceParts();
+      UriResource resource = null;
+      if (resourceParts.size() == 1) {
+        resource = resourceParts.get(0);
+        matched = true;
+        expandItem = getMatchedExpandItem(propertyName, item, matched, 
resource);
+      } else if (resourceParts.get(resourceParts.size() - 1) instanceof 
UriResourceRef ||
+          resourceParts.get(resourceParts.size() - 1) instanceof 
UriResourceCount) {
+        if (resourceParts.size() == 2) {
+          resource = resourceParts.get(0);
+          matched = true;
+          expandItem = getMatchedExpandItem(propertyName, item, matched, 
resource);
+        } else {
+          resource = resourceParts.get(resourceParts.size() - 3);
+          matched = resource.getSegmentValue().equalsIgnoreCase(resourceName) 
? 
+              isFoundExpandItem(type, matched, resource) : false;
+          expandItem = getMatchedExpandItem(propertyName, item, matched, 
resourceParts.get(resourceParts.size() - 2));
+        }
+      } else {
+        resource = resourceParts.get(resourceParts.size() - 2);
+        matched = resource.getSegmentValue().equalsIgnoreCase(resourceName) ? 
+            isFoundExpandItem(type, matched, resource) : false;
+        expandItem = getMatchedExpandItem(propertyName, item, matched, 
resourceParts.get(resourceParts.size() - 1));
+      }
+      if (expandItem != null) {
+        return expandItem;
+      }
+    }
+    return expandItem;
+  }
+
+  /**
+   * @param propertyName
+   * @param item
+   * @param matched
+   * @param resource
+   */
+  private static ExpandItem getMatchedExpandItem(final String propertyName, 
final ExpandItem item, boolean matched,
+      UriResource resource) {
+    if (matched && ((resource instanceof UriResourceNavigation
+        && propertyName.equals(((UriResourceNavigation) 
resource).getProperty().getName())) ||
+        resource instanceof UriResourceProperty
+        && propertyName.equals(((UriResourceProperty) 
resource).getProperty().getName()))) {
+      return item;
+    }
+    return null;
+  }
+
+  /**
+   * @param type
+   * @param matched
+   * @param resource
+   * @return
+   */
+  private static boolean isFoundExpandItem(final EdmStructuredType type, 
+      boolean matched, UriResource resource) {
+    if (!matched) {
+      if ((resource instanceof UriResourceProperty && 
+              type.compatibleTo(((UriResourceProperty) resource).getType())) ||
+          (resource instanceof UriResourceNavigation && 
+              type.compatibleTo(((UriResourceNavigation) 
resource).getType()))) {
+        matched = true;
+      }
+    }
+    return matched;
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
index 120638c..6697cce 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
@@ -32,11 +32,11 @@ import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 
 import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.AbstractEntityCollection;
 import org.apache.olingo.commons.api.data.ComplexValue;
 import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntityCollection;
-import org.apache.olingo.commons.api.data.AbstractEntityCollection;
 import org.apache.olingo.commons.api.data.EntityIterator;
 import org.apache.olingo.commons.api.data.Link;
 import org.apache.olingo.commons.api.data.Linked;
@@ -527,7 +527,8 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
       }
   
       writer.writeStartElement(METADATA, Constants.PROPERTIES, NS_METADATA);
-      writeProperties(metadata, resolvedType, entity.getProperties(), select, 
xml10InvalidCharReplacement, writer);
+      writeProperties(metadata, resolvedType, entity.getProperties(), select, 
+          xml10InvalidCharReplacement, writer, entity, expand);
       writer.writeEndElement(); // properties
   
       if (!entityType.hasStream()) { // content
@@ -626,18 +627,21 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
 
   protected void writeProperties(final ServiceMetadata metadata, final 
EdmStructuredType type,
       final List<Property> properties, final SelectOption select, final String 
xml10InvalidCharReplacement, 
-      final XMLStreamWriter writer) throws XMLStreamException, 
SerializerException {
+      final XMLStreamWriter writer, Linked linked, ExpandOption expand) 
+          throws XMLStreamException, SerializerException {
     final boolean all = ExpandSelectHelper.isAll(select);
     final Set<String> selected = all ? new HashSet<String>() :
         ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems());
     addKeyPropertiesToSelected(selected, type);
+    Set<List<String>> expandedPaths = 
ExpandSelectHelper.getExpandedItemsPath(expand);
     for (final String propertyName : type.getPropertyNames()) {
       if (all || selected.contains(propertyName)) {
         final EdmProperty edmProperty = 
type.getStructuralProperty(propertyName);
         final Property property = findProperty(propertyName, properties);
         final Set<List<String>> selectedPaths = all || 
edmProperty.isPrimitive() ? null :
             ExpandSelectHelper.getSelectedPaths(select.getSelectItems(), 
propertyName);
-        writeProperty(metadata, edmProperty, property, selectedPaths, 
xml10InvalidCharReplacement, writer);
+        writeProperty(metadata, edmProperty, property, selectedPaths, 
+            xml10InvalidCharReplacement, writer, expandedPaths, linked, 
expand);
       }
     }
   }
@@ -660,7 +664,8 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
     if ((toDepth != null && toDepth > 1) || (toDepth == null && 
ExpandSelectHelper.hasExpand(expand))) {
       final ExpandItem expandAll = ExpandSelectHelper.getExpandAll(expand);
       for (final String propertyName : type.getNavigationPropertyNames()) {
-        final ExpandItem innerOptions = 
ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
+        final ExpandItem innerOptions = 
ExpandSelectHelper.getExpandItemBasedOnType(expand.getExpandItems(), 
+            propertyName, type, name);
         if (expandAll != null || innerOptions != null || toDepth != null) {
           Integer levels = null;
           final EdmNavigationProperty property = 
type.getNavigationProperty(propertyName);
@@ -782,7 +787,8 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
   protected void writeProperty(final ServiceMetadata metadata,
       final EdmProperty edmProperty, final Property property,
       final Set<List<String>> selectedPaths,
-      final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
+      final String xml10InvalidCharReplacement, final XMLStreamWriter writer, 
+      Set<List<String>> expandedPaths, Linked linked, ExpandOption expand)
       throws XMLStreamException, SerializerException {
     writer.writeStartElement(DATA, edmProperty.getName(), NS_DATA);
     if (property == null || property.isNull()) {
@@ -793,7 +799,8 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
             SerializerException.MessageKeys.MISSING_PROPERTY, 
edmProperty.getName());
       }
     } else {
-      writePropertyValue(metadata, edmProperty, property, selectedPaths, 
xml10InvalidCharReplacement, writer);
+      writePropertyValue(metadata, edmProperty, property, selectedPaths, 
+          xml10InvalidCharReplacement, writer, expandedPaths, linked, expand);
     }
     writer.writeEndElement();
   }
@@ -820,7 +827,8 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
   private void writePropertyValue(final ServiceMetadata metadata,
       final EdmProperty edmProperty, final Property property,
       final Set<List<String>> selectedPaths,
-      final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
+      final String xml10InvalidCharReplacement, final XMLStreamWriter writer, 
+      Set<List<String>> expandedPaths, Linked linked, ExpandOption expand)
       throws XMLStreamException, SerializerException {
     try {
       if (edmProperty.isPrimitive()
@@ -845,9 +853,10 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
         if (edmProperty.isCollection()) {
           writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE, 
collectionType(edmProperty.getType()));
           writeComplexCollection(metadata, (EdmComplexType) 
edmProperty.getType(), property, selectedPaths, 
-              xml10InvalidCharReplacement, writer);
+              xml10InvalidCharReplacement, writer, expandedPaths, linked, 
expand);
         } else {
-            writeComplex(metadata, edmProperty, property, selectedPaths, 
xml10InvalidCharReplacement, writer);
+            writeComplex(metadata, edmProperty, property, selectedPaths, 
+                xml10InvalidCharReplacement, writer, expandedPaths, linked, 
expand);
         }
       } else {
         throw new SerializerException("Property type not yet supported!",
@@ -863,7 +872,8 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
   private void writeComplex(final ServiceMetadata metadata,
       final EdmProperty edmProperty, final Property property,
       final Set<List<String>> selectedPaths,
-      final String xml10InvalidCharReplacement, final XMLStreamWriter writer) 
+      final String xml10InvalidCharReplacement, final XMLStreamWriter writer, 
+      Set<List<String>> expandedPaths, Linked linked, ExpandOption expand) 
           throws XMLStreamException, SerializerException{
       
        writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE,
@@ -873,8 +883,24 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
        final EdmComplexType resolvedType = resolveComplexType(metadata,
         (EdmComplexType) edmProperty.getType(), derivedName);
        
+       if (null != linked) {
+         if (linked instanceof Entity) {
+           linked = 
((Entity)linked).getProperty(property.getName()).asComplex();
+         } else if (linked instanceof ComplexValue) {
+           List<Property> complexProperties = 
((ComplexValue)linked).getValue();
+           for (Property prop : complexProperties) {
+             if (prop.getName().equals(property.getName())) {
+               linked = prop.asComplex();
+               break;
+             }
+           }
+         }
+         expandedPaths = expandedPaths == null || expandedPaths.isEmpty() ? 
null :
+           ExpandSelectHelper.getReducedExpandItemsPaths(expandedPaths, 
property.getName());
+       }
+       
         writeComplexValue(metadata, resolvedType, 
property.asComplex().getValue(),
-           selectedPaths, xml10InvalidCharReplacement, writer);
+           selectedPaths, xml10InvalidCharReplacement, writer, expandedPaths, 
linked, expand, property.getName());
   }
   private void writePrimitiveCollection(final EdmPrimitiveType type, final 
Property property,
       final Boolean isNullable, final Integer maxLength, final Integer 
precision, final Integer scale,
@@ -901,10 +927,14 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
 
   private void writeComplexCollection(final ServiceMetadata metadata,
       final EdmComplexType type, final Property property, final 
Set<List<String>> selectedPaths,
-      final String xml10InvalidCharReplacement, final XMLStreamWriter writer)
+      final String xml10InvalidCharReplacement, final XMLStreamWriter writer, 
+      Set<List<String>> expandedPaths, Linked linked, ExpandOption expand)
       throws XMLStreamException, SerializerException {
     EdmComplexType complexType = type;
+    Set<List<String>> expandedPaths1 = expandedPaths != null && 
!expandedPaths.isEmpty() ? 
+        expandedPaths : ExpandSelectHelper.getExpandedItemsPath(expand);
     for (Object value : property.asCollection()) {
+      expandedPaths = expandedPaths1;
       writer.writeStartElement(METADATA, Constants.ELEM_ELEMENT, NS_METADATA);
       String typeName = ((ComplexValue)value).getTypeName();
       String propertyType = typeName != null ? typeName :property.getType();
@@ -918,9 +948,11 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
       }
       switch (property.getValueType()) {
       case COLLECTION_COMPLEX:
+        expandedPaths = expandedPaths == null || expandedPaths.isEmpty() ? 
null :
+          ExpandSelectHelper.getReducedExpandItemsPaths(expandedPaths, 
property.getName());
         writeComplexValue(metadata, complexType,
             ((ComplexValue) value).getValue(), selectedPaths,
-            xml10InvalidCharReplacement, writer);
+            xml10InvalidCharReplacement, writer, expandedPaths, (ComplexValue) 
value, expand, property.getName());
         break;
       default:
         throw new SerializerException("Property type not yet supported!",
@@ -975,16 +1007,27 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
   protected void writeComplexValue(final ServiceMetadata metadata,
       final EdmComplexType type, final List<Property> properties, 
       final Set<List<String>> selectedPaths, final String 
xml10InvalidCharReplacement, 
-      final XMLStreamWriter writer) throws XMLStreamException, 
SerializerException {   
+      final XMLStreamWriter writer, Set<List<String>> expandedPaths, 
+      Linked linked, ExpandOption expand, String complexPropName) throws 
XMLStreamException, SerializerException {   
+    
+    if (null != expandedPaths) {
+      for(List<String> paths : expandedPaths) {
+        if (!paths.isEmpty() && paths.size() == 1) {
+          expandedPaths = 
ExpandSelectHelper.getReducedExpandItemsPaths(expandedPaths, paths.get(0));
+        }
+      }
+    }
     
     for (final String propertyName : type.getPropertyNames()) {
       final Property property = findProperty(propertyName, properties);
       if (selectedPaths == null || 
ExpandSelectHelper.isSelected(selectedPaths, propertyName)) {
         writeProperty(metadata, (EdmProperty) type.getProperty(propertyName), 
property,
             selectedPaths == null ? null : 
ExpandSelectHelper.getReducedSelectedPaths(selectedPaths, propertyName),
-            xml10InvalidCharReplacement, writer);
+            xml10InvalidCharReplacement, writer, expandedPaths, linked, 
expand);
       }
     }
+    writeNavigationProperties(metadata, type, linked, 
+        expand, null, xml10InvalidCharReplacement, null, complexPropName, 
writer);
   }
 
   private Property findProperty(final String propertyName, final 
List<Property> properties) {
@@ -1082,6 +1125,7 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
       writer.writeStartElement(METADATA, Constants.VALUE, NS_METADATA);
       writer.writeNamespace(METADATA, NS_METADATA);
       writer.writeNamespace(DATA, NS_DATA);
+      writer.writeNamespace(ATOM, NS_ATOM);
       writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE,
           "#" + 
resolvedType.getFullQualifiedName().getFullQualifiedNameAsString());
       writer.writeAttribute(METADATA, NS_METADATA, Constants.CONTEXT,
@@ -1094,7 +1138,7 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
         writeProperties(metadata, resolvedType, values, 
             options == null ? null : options.getSelect(),
             options == null ? null : options.xml10InvalidCharReplacement(),
-            writer);
+            writer, property.asComplex(), options == null ? null : 
options.getExpand());
       }
       writer.writeEndDocument();
       writer.flush();
@@ -1184,6 +1228,7 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
       writer.writeStartElement(METADATA, Constants.VALUE, NS_METADATA);
       writer.writeNamespace(METADATA, NS_METADATA);
       writer.writeNamespace(DATA, NS_DATA);
+      writer.writeNamespace(ATOM, NS_ATOM);
       writer.writeAttribute(METADATA, NS_METADATA, Constants.ATTR_TYPE, 
collectionType(type));
       writer.writeAttribute(METADATA, NS_METADATA, Constants.CONTEXT,
           ContextURLBuilder.create(contextURL).toASCIIString());
@@ -1194,8 +1239,14 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
         selectedPaths = all || property.isPrimitive() ? null : 
ExpandSelectHelper
             .getSelectedPaths(options.getSelect().getSelectItems());
       }
+      Set<List<String>> expandPaths = null;
+      if (null != options && null != options.getExpand()) {
+        expandPaths = 
ExpandSelectHelper.getExpandedItemsPath(options.getExpand());
+      }
+      
       writeComplexCollection(metadata, type, property, selectedPaths, 
-          options == null ? null:options.xml10InvalidCharReplacement(), 
writer);
+          options == null ? null:options.xml10InvalidCharReplacement(), 
writer, expandPaths, null, 
+              options == null ? null : options.getExpand());
       writer.writeEndElement();
       writer.writeEndDocument();
       writer.flush();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
index 1138a57..94a4bfb 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ExpandParser.java
@@ -194,7 +194,7 @@ public class ExpandParser {
     String name = null;
     while (tokenizer.next(TokenKind.ODataIdentifier)) {
       name = tokenizer.getText();
-      final EdmProperty property = referencedType.getStructuralProperty(name);
+      final EdmProperty property = type.getStructuralProperty(name);
       if (property != null && property.getType().getKind() == 
EdmTypeKind.COMPLEX) {
         type = (EdmStructuredType) property.getType();
         UriResourceComplexPropertyImpl complexResource = new 
UriResourceComplexPropertyImpl(property);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
index ab9705b..53ab55a 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/ActionData.java
@@ -203,15 +203,15 @@ public class ActionData {
       final Parameter paramInt16 = parameters.get("ParameterInt16");
       final Short number = paramInt16 == null || paramInt16.isNull() ? 0 : 
(Short) paramInt16.asPrimitive();
       if (number >= 1) {
-        complexCollection.add(createCTTwoPrimComplexProperty(null, (short) 16, 
"Test123").asComplex());
+        complexCollection.add(createCTTwoPrimComplexProperty("PropertyComp", 
(short) 16, "Test123").asComplex());
       }
       if (number >= 2) {
-        complexCollection.add(createCTTwoPrimComplexProperty(null, (short) 17, 
"Test456").asComplex());
+        complexCollection.add(createCTTwoPrimComplexProperty("PropertyComp", 
(short) 17, "Test456").asComplex());
       }
       if (number >= 3) {
-        complexCollection.add(createCTTwoPrimComplexProperty(null, (short) 18, 
"Test678").asComplex());
+        complexCollection.add(createCTTwoPrimComplexProperty("PropertyComp", 
(short) 18, "Test678").asComplex());
       }
-      return new Property(null, name, ValueType.COLLECTION_COMPLEX, 
complexCollection);
+      return new Property("PropertyCollComp", name, 
ValueType.COLLECTION_COMPLEX, complexCollection);
     }
     throw new DataProviderException("Action " + name + " is not yet 
implemented.",
         HttpStatusCode.NOT_IMPLEMENTED);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
index 10e951c..94b16cf 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataCreator.java
@@ -110,8 +110,122 @@ public class DataCreator {
     linkESDelta(data);
     linkESKeyNavCont(data);
     linkETBaseCont(data);
+    linkPropCompInESCompMixPrimCollCompToETTwoKeyNav(data);
+    linkCollPropCompInESCompMixPrimCollCompToETTwoKeyNav(data);
+    linkPropCompInESCompMixPrimCollCompToETMedia(data);
+    linkPropMixPrimCompInESCompMixPrimCollCompToETTwoKeyNav(data);
+    linkPropMixPrimCompInESCompMixPrimCollCompToCollETTwoKeyNav(data);
+    linkColPropCompInESMixPrimCollCompToETTwoKeyNav(data);
   }
   
+  @SuppressWarnings("unchecked")
+  private void 
linkCollPropCompInESCompMixPrimCollCompToETTwoKeyNav(Map<String, 
EntityCollection> data2) {
+    EntityCollection collection = data.get("ESCompMixPrimCollComp");
+    Entity entity = collection.getEntities().get(0);
+    ComplexValue complexValue = entity.getProperties().get(1).asComplex();
+    List<ComplexValue> innerComplexValue = (List<ComplexValue>) 
complexValue.getValue().get(3).asCollection();
+    final List<Entity> esTwoKeyNavTargets = 
data.get("ESTwoKeyNav").getEntities();
+    for (ComplexValue innerValue : innerComplexValue) {
+      Link link = new Link();
+      link.setRel(Constants.NS_NAVIGATION_LINK_REL + 
"NavPropertyETTwoKeyNavOne");
+      link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
+      link.setTitle("NavPropertyETTwoKeyNavOne");
+      link.setHref(esTwoKeyNavTargets.get(1).getId().toASCIIString());
+      innerValue.getNavigationLinks().add(link);
+      link.setInlineEntity(esTwoKeyNavTargets.get(1));
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  private void linkColPropCompInESMixPrimCollCompToETTwoKeyNav(Map<String, 
EntityCollection> data2) {
+    EntityCollection collection = data.get("ESMixPrimCollComp");
+    Entity entity = collection.getEntities().get(0);
+    List<ComplexValue> list = (List<ComplexValue>) 
entity.getProperties().get(3).asCollection();
+    final List<Entity> esTwoKeyNavTargets = 
data.get("ESTwoKeyNav").getEntities();
+    for (ComplexValue complexValue : list) {
+      Link link = new Link();
+      link.setRel(Constants.NS_NAVIGATION_LINK_REL + 
"NavPropertyETTwoKeyNavOne");
+      link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
+      link.setTitle("NavPropertyETTwoKeyNavOne");
+      link.setHref(esTwoKeyNavTargets.get(1).getId().toASCIIString());
+      complexValue.getNavigationLinks().add(link);
+      link.setInlineEntity(esTwoKeyNavTargets.get(1)); 
+    }
+    
+    ComplexValue complexValue = (ComplexValue) 
entity.getProperties().get(2).asComplex();
+    Link link = new Link();
+    link.setRel(Constants.NS_NAVIGATION_LINK_REL + 
"NavPropertyETTwoKeyNavOne");
+    link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
+    link.setTitle("NavPropertyETTwoKeyNavOne");
+    link.setHref(esTwoKeyNavTargets.get(0).getId().toASCIIString());
+    complexValue.getNavigationLinks().add(link);
+    link.setInlineEntity(esTwoKeyNavTargets.get(0)); 
+  }
+
+  private void linkPropMixPrimCompInESCompMixPrimCollCompToETTwoKeyNav(
+      Map<String, EntityCollection> data) {
+    EntityCollection collection = data.get("ESCompMixPrimCollComp");
+    Entity entity = collection.getEntities().get(0);
+    ComplexValue complexValue = entity.getProperties().get(1).asComplex();
+    final List<Entity> esTwoKeyNavTargets = 
data.get("ESTwoKeyNav").getEntities();
+    Link link = new Link();
+    link.setRel(Constants.NS_NAVIGATION_LINK_REL + 
"NavPropertyETTwoKeyNavOne");
+    link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
+    link.setTitle("NavPropertyETTwoKeyNavOne");
+    link.setInlineEntity(esTwoKeyNavTargets.get(1));
+    link.setHref(esTwoKeyNavTargets.get(1).getId().toASCIIString());
+    complexValue.getNavigationLinks().add(link);
+  }
+  
+  private void linkPropMixPrimCompInESCompMixPrimCollCompToCollETTwoKeyNav(
+      Map<String, EntityCollection> data) {
+    EntityCollection collection = data.get("ESCompMixPrimCollComp");
+    Entity entity = collection.getEntities().get(0);
+    ComplexValue complexValue = entity.getProperties().get(1).asComplex();
+    final List<Entity> esTwoKeyNavTargets = 
data.get("ESTwoKeyNav").getEntities();
+    Link link = new Link();
+    link.setRel(Constants.NS_NAVIGATION_LINK_REL + 
"NavPropertyETTwoKeyNavMany");
+    link.setType(Constants.ENTITY_SET_NAVIGATION_LINK_TYPE);
+    link.setTitle("NavPropertyETTwoKeyNavMany");
+    EntityCollection target = new EntityCollection();
+    target.setCount(2);
+    target.getEntities().addAll(Arrays.asList(esTwoKeyNavTargets.get(0), 
esTwoKeyNavTargets.get(2)));
+    link.setInlineEntitySet(target);
+    link.setHref(entity.getId().toASCIIString() + "/" + 
+    entity.getProperties().get(1).getName() + "/"
+        + "NavPropertyETTwoKeyNavMany");
+    complexValue.getNavigationLinks().add(link);
+  }
+
+  private void linkPropCompInESCompMixPrimCollCompToETMedia(Map<String, 
EntityCollection> data) {
+    EntityCollection collection = data.get("ESCompMixPrimCollComp");
+    Entity entity = collection.getEntities().get(0);
+    ComplexValue complexValue = entity.getProperties().get(1).asComplex();
+    ComplexValue innerComplexValue = 
complexValue.getValue().get(2).asComplex();
+    final List<Entity> esMediaTargets = data.get("ESMedia").getEntities();
+    Link link = new Link();
+    link.setRel(Constants.NS_NAVIGATION_LINK_REL + "NavPropertyETMediaOne");
+    link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
+    link.setTitle("NavPropertyETMediaOne");
+    link.setHref(esMediaTargets.get(1).getId().toASCIIString());
+    innerComplexValue.getNavigationLinks().add(link);
+    link.setInlineEntity(esMediaTargets.get(1));
+  }
+
+  private void linkPropCompInESCompMixPrimCollCompToETTwoKeyNav(Map<String, 
EntityCollection> data) {
+    EntityCollection collection = data.get("ESCompMixPrimCollComp");
+    Entity entity = collection.getEntities().get(0);
+    ComplexValue complexValue = entity.getProperties().get(1).asComplex();
+    ComplexValue innerComplexValue = 
complexValue.getValue().get(2).asComplex();
+    final List<Entity> esTwoKeyNavTargets = 
data.get("ESTwoKeyNav").getEntities();
+    Link link = new Link();
+    link.setRel(Constants.NS_NAVIGATION_LINK_REL + 
"NavPropertyETTwoKeyNavOne");
+    link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
+    link.setTitle("NavPropertyETTwoKeyNavOne");
+    link.setHref(esTwoKeyNavTargets.get(1).getId().toASCIIString());
+    innerComplexValue.getNavigationLinks().add(link);
+    link.setInlineEntity(esTwoKeyNavTargets.get(1));
+   }
 
   private EntityCollection createESDelta(final Edm edm, final OData odata) {
    EntityCollection entityCollection = new EntityCollection();
@@ -181,7 +295,7 @@ public class DataCreator {
                 
ComplexTypeProvider.nameCTTwoPrimAno.getFullQualifiedNameAsString(),
                 Arrays.asList(new ComplexValue[] {
                 
createComplexValue(ComplexTypeProvider.nameCTBaseAno.getFullQualifiedNameAsString(),
-                    Arrays.asList(new Property[] {
+                    "CollPropertyCompAno", Arrays.asList(new Property[] {
                         createDerived("AdditionalPropString",
                             
ComplexTypeProvider.nameCTBaseAno.getFullQualifiedNameAsString(),
                             "Additional12345"),
@@ -191,7 +305,7 @@ public class DataCreator {
                     }
               )),
                 
createComplexValue(ComplexTypeProvider.nameCTTwoPrimAno.getFullQualifiedNameAsString(),
-                    Arrays.asList(new Property[] {
+                    "CollPropertyCompAno", Arrays.asList(new Property[] {
                         createDerived("PropertyString", 
                             
ComplexTypeProvider.nameCTTwoPrimAno.getFullQualifiedNameAsString(),
                             "TESTabcd")
@@ -206,10 +320,11 @@ public class DataCreator {
     return entityCollection;
   }
 
-  private ComplexValue createComplexValue(String type, List<Property> 
properties) {
+  private ComplexValue createComplexValue(String type, String name, 
List<Property> properties) {
     ComplexValue complexValue = new ComplexValue();
     complexValue.getValue().addAll(properties);
     complexValue.setTypeName(type);  
+    complexValue.setId(URI.create(name));
     return complexValue;
   }
 
@@ -1416,19 +1531,19 @@ public class DataCreator {
         ComplexTypeProvider.nameCTTwoPrim.getFullQualifiedNameAsString(),
         Arrays.asList(new ComplexValue[] {
             
createComplexValue(ComplexTypeProvider.nameCTTwoPrim.getFullQualifiedNameAsString(),
-                Arrays.asList(new Property[] {
+                "CollPropertyComp", Arrays.asList(new Property[] {
                     createPrimitive("PropertyInt16", (short) 123),
                     createPrimitive("PropertyString", "TEST 1")
                 }
           )),
             
createComplexValue(ComplexTypeProvider.nameCTTwoPrim.getFullQualifiedNameAsString(),
-                Arrays.asList(new Property[] {
+                "CollPropertyComp", Arrays.asList(new Property[] {
                     createPrimitive("PropertyInt16", (short) 456),
                     createPrimitive("PropertyString", "TEST 2")
                 }
           )),
             
createComplexValue(ComplexTypeProvider.nameCTBase.getFullQualifiedNameAsString(),
-                Arrays.asList(new Property[] {
+                "CollPropertyComp", Arrays.asList(new Property[] {
                     createPrimitive("PropertyInt16", (short) 789),
                     createPrimitive("PropertyString", "TEST 3"),
                     createPrimitive("AdditionalPropString", "ADD TEST")
@@ -1753,6 +1868,9 @@ public class DataCreator {
     for (final Property property : properties) {
       complexValue.getValue().add(property);
     }
+    if (null != name) {
+      complexValue.setId(URI.create(name));
+    }
     Property property = new Property(type, name, ValueType.COMPLEX, 
complexValue);
     createOperations(name, type, property);
     return property;
@@ -1784,6 +1902,9 @@ public class DataCreator {
     for (final List<Property> properties : propertiesList) {
       ComplexValue complexValue = new ComplexValue();
       complexValue.getValue().addAll(properties);
+      if (null != name) {
+        complexValue.setId(URI.create(name));
+      }
       complexCollection.add(complexValue);
     }
     Property property =  new Property(type, name, 
ValueType.COLLECTION_COMPLEX, complexCollection);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/FunctionData.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/FunctionData.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/FunctionData.java
index 42c9f2e..8e37d16 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/FunctionData.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/FunctionData.java
@@ -19,6 +19,7 @@
 package org.apache.olingo.server.tecsvc.data;
 
 import java.math.BigDecimal;
+import java.net.URI;
 import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -164,6 +165,7 @@ public class FunctionData {
           complexValue.getValue().add(new Property(null, "PropertyInt16", 
ValueType.PRIMITIVE, counter++));
           complexValue.getValue().add(new Property(null, "PropertyString", 
ValueType.PRIMITIVE, 
               name + " string value: " + parameterString));
+          complexValue.setId(URI.create(""));
           complexValues.add(complexValue);
         }
         return new Property(null, name, ValueType.COLLECTION_COMPLEX, 
complexValues);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/ComplexTypeProvider.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/ComplexTypeProvider.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/ComplexTypeProvider.java
index 0b4d726..8e24965 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/ComplexTypeProvider.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/provider/ComplexTypeProvider.java
@@ -115,8 +115,12 @@ public class ComplexTypeProvider {
       return new CsdlComplexType()
           .setName("CTTwoPrim")
           
.setProperties(Arrays.asList(PropertyProvider.propertyInt16_NotNullable,
-              PropertyProvider.propertyString_NotNullable));
-
+              PropertyProvider.propertyString_NotNullable))
+          .setNavigationProperties((Arrays.asList(
+              PropertyProvider.collectionNavPropertyETTwoKeyNavOne_ETTwoKeyNav,
+              new CsdlNavigationProperty()
+                  .setName("NavPropertyETMediaOne")
+                  .setType(EntityTypeProvider.nameETMedia))));
     } else if (complexTypeName.equals(nameCTCompNav)) {
       return new CsdlComplexType()
           .setName("CTCompNav")
@@ -128,7 +132,10 @@ public class ComplexTypeProvider {
           .setName("CTMixPrimCollComp")
           .setProperties(
               Arrays.asList(PropertyProvider.propertyInt16, 
PropertyProvider.collPropertyString,
-                  PropertyProvider.propertyComp_CTTwoPrim, 
PropertyProvider.collPropertyComp_CTTwoPrim));
+                  PropertyProvider.propertyComp_CTTwoPrim, 
PropertyProvider.collPropertyComp_CTTwoPrim))
+          .setNavigationProperties((Arrays.asList(
+              PropertyProvider.collectionNavPropertyETTwoKeyNavOne_ETTwoKeyNav,
+              
PropertyProvider.collectionNavPropertyETTwoKeyNavMany_ETTwoKeyNav)));
 
     } else if (complexTypeName.equals(nameCTBase)) {
       return new CsdlComplexType()

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/aaff527d/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
index 378ad1d..e95728a 100644
--- 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
@@ -1813,7 +1813,8 @@ public class ODataJsonSerializerTest {
                 "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," +
                 "\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," +
                 
"\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":111," +
-                "\"PropertyString\":\"TEST A\"}",resultString);
+                "\"PropertyString\":\"TEST 
A\",\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":"
+                + 
"\"ESTwoKeyNav(PropertyInt16=1,PropertyString='1')\"}",resultString);
   }
 
   @Test
@@ -1870,13 +1871,16 @@ public class ODataJsonSerializerTest {
         + "\"@odata.type\":\"#Collection(olingo.odata.test1.CTTwoPrim)\","
         + "\"value\":[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
         + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":123,"
-        + "\"PropertyString\":\"TEST 1\"},"
+        + "\"PropertyString\":\"TEST 1\","
+        + 
"\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"},"
         + "{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
         + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":456,"
-        + "\"PropertyString\":\"TEST 2\"},"
+        + "\"PropertyString\":\"TEST 2\","
+        + 
"\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"},"
         + "{\"@odata.type\":\"#olingo.odata.test1.CTBase\","
         + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":789,"
-        + "\"PropertyString\":\"TEST 3\",\"AdditionalPropString\":\"ADD 
TEST\"}]}";
+        + "\"PropertyString\":\"TEST 3\",\"AdditionalPropString\":\"ADD 
TEST\","
+        + 
"\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"}]}";
     Assert.assertEquals(expectedResult, resultString);
   }
   
@@ -2700,4 +2704,76 @@ public class ODataJsonSerializerTest {
         + 
"\"PropertyInt16\":1,\"PropertyString\":\"1\",\"CollPropertyCompNav\":[{}]}";
     Assert.assertEquals(expectedResult, resultString);
   }
+  
+  @Test
+  public void entityWithExtendedComplexTypeWithMetadata() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESCompMixPrimCollComp");
+    final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    final String resultString = IOUtils.toString(serializerFullMetadata
+        .entity(metadata, edmEntitySet.getEntityType(), entity, 
+            EntitySerializerOptions.with()
+            
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build()).getContent());
+    final String expectedResult = 
"{\"@odata.context\":\"$metadata#ESCompMixPrimCollComp/$entity\","
+        + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+        + "\"@odata.type\":\"#olingo.odata.test1.ETCompMixPrimCollComp\","
+        + "\"@odata.id\":\"ESCompMixPrimCollComp(1)\","
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":1,"
+        + "\"PropertyMixedPrimCollComp\":"
+        + "{\"@odata.type\":\"#olingo.odata.test1.CTMixPrimCollComp\","
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":1,"
+        + "\"collpropertystr...@odata.type\":\"#Collection(String)\","
+        + "\"CollPropertyString\":[\"Employee1@company.example\","
+        + "\"Employee2@company.example\",\"Employee3@company.example\"],"
+        + 
"\"PropertyComp\":{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":333,"
+        + "\"PropertyString\":\"TEST123\","
+        + "\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":"
+        + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\","
+        + "\"NavPropertyETMediaOne@odata.navigationLink\":\"ESMedia(2)\"},"
+        + 
"\"collpropertyc...@odata.type\":\"#Collection(olingo.odata.test1.CTTwoPrim)\","
+        + 
"\"CollPropertyComp\":[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":222,"
+        + "\"PropertyString\":\"TEST9876\","
+        + 
"\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"},"
+        + "{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":333,"
+        + "\"PropertyString\":\"TEST123\","
+        + 
"\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"}],"
+        + "\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":"
+        + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\","
+        + "\"NavPropertyETTwoKeyNavMany@odata.navigationLink\":"
+        + 
"\"ESCompMixPrimCollComp(1)/PropertyMixedPrimCollComp/NavPropertyETTwoKeyNavMany\"}}";
+    Assert.assertEquals(expectedResult, resultString);
+  }
+  
+  @Test
+  public void extendedcomplexPropertyWithNavWithMetadataFull() throws 
Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESCompMixPrimCollComp");
+    final EdmProperty edmComplexType = (EdmProperty) 
edmEntitySet.getEntityType().
+        getProperty("PropertyMixedPrimCollComp");
+    
+    final EdmComplexType complexType = metadata.getEdm().getComplexType(
+        new FullQualifiedName("olingo.odata.test1", "CTMixPrimCollComp"));
+    
+    EdmProperty edmProperty = (EdmProperty) 
complexType.getProperty("PropertyComp");
+    final ComplexValue complexValue = 
data.readAll(edmEntitySet).getEntities().get(0).
+        getProperty("PropertyMixedPrimCollComp").asComplex();
+    final Property property = complexValue.getValue().get(2);
+    final String resultString = IOUtils.toString(serializerFullMetadata
+             .complex(metadata, (EdmComplexType) edmProperty.getType(), 
property,
+                    ComplexSerializerOptions.with()
+                            .contextURL(ContextURL.with()
+                                    .entitySet(edmEntitySet).keyPath("1")
+                                    
.navOrPropertyPath(edmComplexType.getName()+"/"+property.getName())
+                                        .build()).build()).getContent());
+    
Assert.assertEquals("{\"@odata.context\":\"$metadata#ESCompMixPrimCollComp(1)/"
+        + 
"PropertyMixedPrimCollComp/PropertyComp\",\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+        + "\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+        + "\"propertyin...@odata.type\":\"#Int16\",\"PropertyInt16\":333,"
+        + "\"PropertyString\":\"TEST123\","
+        + "\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":"
+        + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\","
+        + 
"\"NavPropertyETMediaOne@odata.navigationLink\":\"ESMedia(2)\"}",resultString);
+  }
 }

Reply via email to