From aaff527dcd43d5f68d6407c8ab9b031a0e53c38e Mon Sep 17 00:00:00 2001 From: ramya vasanth Date: Wed, 11 Apr 2018 11:15:38 +0530 Subject: [PATCH] [OLINGO-1143] Support of Expand of a navigation property of a complex type --- .../ExpandWithComplexPropertyITCase.java | 348 ++++++++++++++++++ .../http/DerivedAndMixedTypeTestITCase.java | 81 ++-- .../serializer/json/ODataJsonSerializer.java | 91 ++++- .../serializer/utils/ExpandSelectHelper.java | 130 ++++++- .../serializer/xml/ODataXmlSerializer.java | 87 ++++- .../server/core/uri/parser/ExpandParser.java | 2 +- .../olingo/server/tecsvc/data/ActionData.java | 8 +- .../server/tecsvc/data/DataCreator.java | 133 ++++++- .../server/tecsvc/data/FunctionData.java | 2 + .../tecsvc/provider/ComplexTypeProvider.java | 13 +- .../json/ODataJsonSerializerTest.java | 84 ++++- .../json/ODataJsonSerializerv01Test.java | 12 +- .../xml/ODataXmlSerializerTest.java | 112 +++++- 13 files changed, 997 insertions(+), 106 deletions(-) create mode 100644 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 000000000..43f9671a3 --- /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 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 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 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 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 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 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 request = getClient().getRetrieveRequestFactory() + .getEntityRequest(getClient().newURIBuilder(TecSvcConst.BASE_URI) + .appendEntitySetSegment("ESCompMixPrimCollComp").appendKeySegment(1) + .expand("PropertyMixedPrimCollComp/CollPropertyComp/NavPropertyETTwoKeyNavOne") + .build()); + assertNotNull(request); + setCookieHeader(request); + + final ODataRetrieveResponse 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 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 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 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 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 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 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()); + } + } +} 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 69fe65ec1..ce41951c1 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)\"," - + "\"PropertyInt16@odata.type\":\"#Int16\"," - + "\"PropertyInt16\":32767," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":32767," + "\"CollPropertyString@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\"," + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":111," - + "\"PropertyString\":\"TEST A\"}," + + "\"PropertyString\":\"TEST A\"," + + "\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='1')\"}," + "\"CollPropertyComp@odata.type\":\"#Collection(olingo.odata.test1.CTTwoPrim)\"," - + "\"CollPropertyComp\":" - + "[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," + + "\"CollPropertyComp\":[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," + "\"PropertyInt16@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\"," - + "\"PropertyInt16@odata.type\":\"#Int16\"," - + "\"PropertyInt16\":456," - + "\"PropertyString\":\"TEST 2\"}," - + "{\"@odata.type\":\"#olingo.odata.test1.CTBase\"," - + "\"PropertyInt16@odata.type\":\"#Int16\"," - + "\"PropertyInt16\":789," - + "\"PropertyString\":\"TEST 3\"," - + "\"AdditionalPropString\":\"ADD TEST\"}]," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":456," + + "\"PropertyString\":\"TEST 2\"," + + "\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"}," + + "{\"@odata.type\":\"#olingo.odata.test1.CTBase\",\"PropertyInt16@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)\"," - + "\"PropertyInt16@odata.type\":\"#Int16\"," - + "\"PropertyInt16\":7,\"CollPropertyString@odata.type\":\"#Collection(String)\"," - + "\"CollPropertyString\":[\"Employee1@company.example\"," - + "\"Employee2@company.example\"," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":7," + + "\"CollPropertyString@odata.type\":\"#Collection(String)\"," + + "\"CollPropertyString\":[\"Employee1@company.example\",\"Employee2@company.example\"," + "\"Employee3@company.example\"]," + "\"PropertyComp\":{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," - + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":222,\"PropertyString\":\"TEST B\"}," + + "\"PropertyInt16@odata.type\":\"#Int16\"," + + "\"PropertyInt16\":222,\"PropertyString\":\"TEST B\"}," + "\"CollPropertyComp@odata.type\":\"#Collection(olingo.odata.test1.CTTwoPrim)\"," + "\"CollPropertyComp\":[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," - + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":123,\"PropertyString\":\"TEST 1\"}," - + "{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\",\"PropertyInt16@odata.type\":\"#Int16\"," - + "\"PropertyInt16\":456,\"PropertyString\":\"TEST 2\"},{\"@odata.type\":\"#olingo.odata.test1.CTBase\"," - + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":789,\"PropertyString\":\"TEST 3\"," - + "\"AdditionalPropString\":\"ADD TEST\"}]," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":123," + + "\"PropertyString\":\"TEST 1\"},{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":456,\"PropertyString\":\"TEST 2\"}," + + "{\"@odata.type\":\"#olingo.odata.test1.CTBase\",\"PropertyInt16@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)\",\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":0," - + "\"CollPropertyString@odata.type\":\"#Collection(String)\",\"CollPropertyString\":" - + "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"]," - + "\"PropertyComp\":{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\",\"PropertyInt16@odata.type\":\"#Int16\"," - + "\"PropertyInt16\":333,\"PropertyString\":\"TEST C\"}," + + "{\"@odata.type\":\"#olingo.odata.test1.ETMixPrimCollComp\",\"@odata.id\":\"ESMixPrimCollComp(0)\"," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":0," + + "\"CollPropertyString@odata.type\":\"#Collection(String)\"," + + "\"CollPropertyString\":[\"Employee1@company.example\",\"Employee2@company.example\"," + + "\"Employee3@company.example\"]," + + "\"PropertyComp\":{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":333,\"PropertyString\":\"TEST C\"}," + "\"CollPropertyComp@odata.type\":\"#Collection(olingo.odata.test1.CTTwoPrim)\"," - + "\"CollPropertyComp\":" - + "[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," - + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":123,\"PropertyString\":\"TEST 1\"}," - + "{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," + + "\"CollPropertyComp\":[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":123," + + "\"PropertyString\":\"TEST 1\"},{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":456,\"PropertyString\":\"TEST 2\"}," - + "{\"@odata.type\":\"#olingo.odata.test1.CTBase\"," - + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":789,\"PropertyString\":\"TEST 3\"," - + "\"AdditionalPropString\":\"ADD TEST\"}]," + + "{\"@odata.type\":\"#olingo.odata.test1.CTBase\",\"PropertyInt16@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\"}}]"; 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 970d0c281..9f9ab9780 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 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 selected = all ? new HashSet() : ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems()); addKeyPropertiesToSelected(selected, type); + Set> 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> 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> selectedPaths, final JsonGenerator json) + final Set> selectedPaths, final JsonGenerator json, + Set> 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> selectedPaths, final JsonGenerator json) + final Property property, final Set> selectedPaths, final JsonGenerator json, + Set> 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> selectedPaths, final JsonGenerator json) + final Property property, final Set> selectedPaths, final JsonGenerator json, + Set> 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 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> selectedPaths, final JsonGenerator json) + final Set> selectedPaths, final JsonGenerator json, + Set> expandedPaths, Linked linked, ExpandOption expand) throws IOException, SerializerException { json.writeStartArray(); EdmComplexType derivedType = type; + Set> 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 properties, - final Set> selectedPaths, final JsonGenerator json) + final Set> selectedPaths, final JsonGenerator json, + Set> expandedPaths, Linked linked, ExpandOption expand, String complexPropName) throws IOException, SerializerException { + if (null != expandedPaths) { + for(List 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 properties) { @@ -1135,7 +1181,9 @@ public class ODataJsonSerializer extends AbstractODataSerializer { writeOperations(property.getOperations(), json); final List values = property.isNull() ? Collections. 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> 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(); 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 2fe3b4f00..99cb32bef 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 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> getExpandedItemsPath(ExpandOption expand) { + Set> expandPaths = new HashSet>(); + if (expand != null) { + List expandItems = expand.getExpandItems(); + for (ExpandItem item : expandItems) { + if (item.isStar()) { + continue; + } + List resourceParts = item.getResourcePath().getUriResourceParts(); + if (resourceParts.get(0) instanceof UriResourceComplexProperty) { + List path = new ArrayList(); + 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> getReducedExpandItemsPaths(final Set> expandItemsPaths, + final String propertyName) { + Set> reducedPaths = new HashSet>(); + for (final List 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 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 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 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 120638c86..6697ccef6 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 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 selected = all ? new HashSet() : ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems()); addKeyPropertiesToSelected(selected, type); + Set> 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> 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> selectedPaths, - final String xml10InvalidCharReplacement, final XMLStreamWriter writer) + final String xml10InvalidCharReplacement, final XMLStreamWriter writer, + Set> 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> selectedPaths, - final String xml10InvalidCharReplacement, final XMLStreamWriter writer) + final String xml10InvalidCharReplacement, final XMLStreamWriter writer, + Set> 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> selectedPaths, - final String xml10InvalidCharReplacement, final XMLStreamWriter writer) + final String xml10InvalidCharReplacement, final XMLStreamWriter writer, + Set> 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 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> selectedPaths, - final String xml10InvalidCharReplacement, final XMLStreamWriter writer) + final String xml10InvalidCharReplacement, final XMLStreamWriter writer, + Set> expandedPaths, Linked linked, ExpandOption expand) throws XMLStreamException, SerializerException { EdmComplexType complexType = type; + Set> 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 properties, final Set> selectedPaths, final String xml10InvalidCharReplacement, - final XMLStreamWriter writer) throws XMLStreamException, SerializerException { + final XMLStreamWriter writer, Set> expandedPaths, + Linked linked, ExpandOption expand, String complexPropName) throws XMLStreamException, SerializerException { + + if (null != expandedPaths) { + for(List 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 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> 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(); 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 1138a572f..94a4bfb94 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); 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 ab9705b5b..53ab55a0f 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); 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 10e951c12..94b16cf47 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 data2) { + EntityCollection collection = data.get("ESCompMixPrimCollComp"); + Entity entity = collection.getEntities().get(0); + ComplexValue complexValue = entity.getProperties().get(1).asComplex(); + List innerComplexValue = (List) complexValue.getValue().get(3).asCollection(); + final List 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 data2) { + EntityCollection collection = data.get("ESMixPrimCollComp"); + Entity entity = collection.getEntities().get(0); + List list = (List) entity.getProperties().get(3).asCollection(); + final List 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 data) { + EntityCollection collection = data.get("ESCompMixPrimCollComp"); + Entity entity = collection.getEntities().get(0); + ComplexValue complexValue = entity.getProperties().get(1).asComplex(); + final List 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 data) { + EntityCollection collection = data.get("ESCompMixPrimCollComp"); + Entity entity = collection.getEntities().get(0); + ComplexValue complexValue = entity.getProperties().get(1).asComplex(); + final List 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 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 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 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 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 properties) { + private ComplexValue createComplexValue(String type, String name, List 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 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); 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 42c9f2e80..8e37d16e7 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); 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 0b4d72688..8e24965fc 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() 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 378ad1d2d..e95728a42 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\"," + "\"PropertyInt16@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\"," + "\"PropertyInt16@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\"," + "\"PropertyInt16@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\"," + "\"PropertyInt16@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)\"," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":1," + + "\"PropertyMixedPrimCollComp\":" + + "{\"@odata.type\":\"#olingo.odata.test1.CTMixPrimCollComp\"," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":1," + + "\"CollPropertyString@odata.type\":\"#Collection(String)\"," + + "\"CollPropertyString\":[\"Employee1@company.example\"," + + "\"Employee2@company.example\",\"Employee3@company.example\"]," + + "\"PropertyComp\":{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":333," + + "\"PropertyString\":\"TEST123\"," + + "\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":" + + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"," + + "\"NavPropertyETMediaOne@odata.navigationLink\":\"ESMedia(2)\"}," + + "\"CollPropertyComp@odata.type\":\"#Collection(olingo.odata.test1.CTTwoPrim)\"," + + "\"CollPropertyComp\":[{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":222," + + "\"PropertyString\":\"TEST9876\"," + + "\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"}," + + "{\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\"," + + "\"PropertyInt16@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\"," + + "\"PropertyInt16@odata.type\":\"#Int16\",\"PropertyInt16\":333," + + "\"PropertyString\":\"TEST123\"," + + "\"NavPropertyETTwoKeyNavOne@odata.navigationLink\":" + + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"," + + "\"NavPropertyETMediaOne@odata.navigationLink\":\"ESMedia(2)\"}",resultString); + } } diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerv01Test.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerv01Test.java index 193758c8b..bece28084 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerv01Test.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerv01Test.java @@ -1826,7 +1826,8 @@ public class ODataJsonSerializerv01Test { "\"@metadataEtag\":\"W/\\\"metadataETag\\\"\"," + "\"@type\":\"#olingo.odata.test1.CTTwoPrim\"," + "\"PropertyInt16@type\":\"#Int16\",\"PropertyInt16\":111," + - "\"PropertyString\":\"TEST A\"}",resultString); + "\"PropertyString\":\"TEST A\",\"NavPropertyETTwoKeyNavOne@navigationLink\":" + + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='1')\"}",resultString); } @Test @@ -1883,13 +1884,16 @@ public class ODataJsonSerializerv01Test { + "\"@type\":\"#Collection(olingo.odata.test1.CTTwoPrim)\"," + "\"value\":[{\"@type\":\"#olingo.odata.test1.CTTwoPrim\"," + "\"PropertyInt16@type\":\"#Int16\",\"PropertyInt16\":123," - + "\"PropertyString\":\"TEST 1\"}," + + "\"PropertyString\":\"TEST 1\"," + + "\"NavPropertyETTwoKeyNavOne@navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"}," + "{\"@type\":\"#olingo.odata.test1.CTTwoPrim\"," + "\"PropertyInt16@type\":\"#Int16\",\"PropertyInt16\":456," - + "\"PropertyString\":\"TEST 2\"}," + + "\"PropertyString\":\"TEST 2\"," + + "\"NavPropertyETTwoKeyNavOne@navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"}," + "{\"@type\":\"#olingo.odata.test1.CTBase\"," + "\"PropertyInt16@type\":\"#Int16\",\"PropertyInt16\":789," - + "\"PropertyString\":\"TEST 3\",\"AdditionalPropString\":\"ADD TEST\"}]}"; + + "\"PropertyString\":\"TEST 3\",\"AdditionalPropString\":\"ADD TEST\"," + + "\"NavPropertyETTwoKeyNavOne@navigationLink\":\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\"}]}"; Assert.assertEquals(expectedResult, resultString); } diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java index 40fa334e0..f8b4c8c7e 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java @@ -662,20 +662,44 @@ public class ODataXmlSerializerTest { " \n" + " 111\n" + " TEST A\n" + + " \n" + + " \n" + " \n" + " \n" + " \n" + " 123\n" + " TEST 1\n" + + " \n" + + " \n" + " \n" + " \n" + " 456\n" + " TEST 2\n" + + " \n" + + " \n" + " \n" + " \n" + " 789\n" + " TEST 3\n" + " ADD TEST\n" + + " \n" + + " \n" + " \n" + " \n" + " \n" + @@ -1600,6 +1624,12 @@ public class ODataXmlSerializerTest { "\n" + "\n" + "Num111\n" + + "\n" + + "\n" + "\n" + "\n" + "\n" + @@ -1647,12 +1677,24 @@ public class ODataXmlSerializerTest { "\n" + "11\n" + "Num11\n" + + "\n" + + "\n" + "\n" + "\n" + "\n" + "111\n" + "Num111\n" + "Test123\n" + + "\n" + + "\n" + "\n" + "\n" + "\n" + @@ -1706,12 +1748,24 @@ public class ODataXmlSerializerTest { " 1" + "\n" + "Num11\n" + + "\n" + + "\n" + "\n" + "\n" + "\n" + "111\n" + "Num111\n" + "Test123\n" + + "\n" + + "\n" + "\n" + "\n" + "\n" + @@ -1761,14 +1815,32 @@ public class ODataXmlSerializerTest { "\n" + "555\n" + "1 Test Complex in Complex Property\n" + + "\n" + + "\n" + "\n" + "\n" + "666\n" + "2 Test Complex in Complex Property\n" + + "\n" + + "\n" + "\n" + "\n" + "777\n" + "3 Test Complex in Complex Property\n" + + "\n" + + "\n" + "\n" + "\n" + "\n" + @@ -1794,14 +1866,32 @@ public class ODataXmlSerializerTest { "\n" + "888\n" + "11 Test Complex in Complex Property\n" + + "\n" + + "\n" + "\n" + "\n" + "999\n" + "12 Test Complex in Complex Property\n" + + "\n" + + "\n" + "\n" + "\n" + "0\n" + "13 Test Complex in Complex Property\n" + + "\n" + + "\n" + "\n" + "\n" + "\n" + @@ -2666,22 +2756,40 @@ public class ODataXmlSerializerTest { .build()).getContent()); String expected = "\n" + "\n" + " \n" + " 123\n" + " TEST 1\n" + + "\n" + + "\n" + " \n" + " \n" + " 456\n" + " TEST 2\n" + + "\n" + + "\n" + " \n" + " \n" + " 789\n" + " TEST 3\n" + " ADD TEST\n" + + "\n" + + "\n" + " \n" + ""; checkXMLEqual(expected, resultString); @@ -3210,7 +3318,7 @@ public class ODataXmlSerializerTest { .build()).getContent()); final String expectedResult = "" + ""