diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AbstractODataBinder.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AbstractODataBinder.java index 423249610..afc32d0fc 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AbstractODataBinder.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AbstractODataBinder.java @@ -309,20 +309,51 @@ public abstract class AbstractODataBinder implements CommonODataBinder { odataLinked.addLink(new ODataInlineEntity(client.getServiceVersion(), URIUtils.getURI(base, link.getHref()), ODataLinkType.ENTITY_NAVIGATION, link.getTitle(), getODataEntity(new ResWrap( - inlineEntity.getBaseURI() == null ? null : inlineEntity.getBaseURI(), - metadataETag, - inlineEntity)))); + inlineEntity.getBaseURI() == null ? null : inlineEntity.getBaseURI(), + metadataETag, + inlineEntity)))); } else { odataLinked.addLink(new ODataInlineEntitySet(client.getServiceVersion(), URIUtils.getURI(base, link.getHref()), ODataLinkType.ENTITY_SET_NAVIGATION, link.getTitle(), getODataEntitySet(new ResWrap( - inlineEntitySet.getBaseURI() == null ? null : inlineEntitySet.getBaseURI(), - metadataETag, - inlineEntitySet)))); + inlineEntitySet.getBaseURI() == null ? null : inlineEntitySet.getBaseURI(), + metadataETag, + inlineEntitySet)))); } } } + private EdmEntityType findEntityType( + final String entitySetOrSingletonOrType, final EdmEntityContainer container) { + + EdmEntityType type = null; + + final String firstToken = StringUtils.substringBefore(entitySetOrSingletonOrType, "/"); + EdmBindingTarget bindingTarget = container.getEntitySet(firstToken); + if (bindingTarget == null) { + bindingTarget = container.getSingleton(firstToken); + } + if (bindingTarget != null) { + type = bindingTarget.getEntityType(); + } + + if (entitySetOrSingletonOrType.indexOf('/') != -1) { + final String[] splitted = entitySetOrSingletonOrType.split("/"); + if (splitted.length > 1) { + for (int i = 1; i < splitted.length && type != null; i++) { + final EdmNavigationProperty navProp = type.getNavigationProperty(splitted[i]); + if (navProp == null) { + type = null; + } else { + type = navProp.getType(); + } + } + } + } + + return type; + } + /** * Infer type name from various sources of information including Edm and context URL, if available. * @@ -340,19 +371,17 @@ public abstract class AbstractODataBinder implements CommonODataBinder { for (EdmSchema schema : edm.getSchemas()) { final EdmEntityContainer container = schema.getEntityContainer(); if (container != null) { - EdmBindingTarget bindingTarget = container.getEntitySet(contextURL.getEntitySetOrSingletonOrType()); - if (bindingTarget == null) { - bindingTarget = container.getSingleton(contextURL.getEntitySetOrSingletonOrType()); - } - if (bindingTarget != null) { + final EdmEntityType entityType = findEntityType(contextURL.getEntitySetOrSingletonOrType(), container); + + if (entityType != null) { if (contextURL.getNavOrPropertyPath() == null) { - type = bindingTarget.getEntityType(); + type = entityType; } else { - final EdmNavigationProperty navProp = bindingTarget.getEntityType(). - getNavigationProperty(contextURL.getNavOrPropertyPath()); + final EdmNavigationProperty navProp = + entityType.getNavigationProperty(contextURL.getNavOrPropertyPath()); type = navProp == null - ? bindingTarget.getEntityType() + ? entityType : navProp.getType(); } } @@ -397,7 +426,7 @@ public abstract class AbstractODataBinder implements CommonODataBinder { final CommonODataEntity entity = resource.getPayload().getSelfLink() == null ? client.getObjectFactory().newEntity(typeName) : client.getObjectFactory().newEntity(typeName, - URIUtils.getURI(base, resource.getPayload().getSelfLink().getHref())); + URIUtils.getURI(base, resource.getPayload().getSelfLink().getHref())); if (StringUtils.isNotBlank(resource.getPayload().getETag())) { entity.setETag(resource.getPayload().getETag()); @@ -489,15 +518,15 @@ public abstract class AbstractODataBinder implements CommonODataBinder { value = client.getObjectFactory().newPrimitiveValueBuilder() .setValue(valuable.asGeospatial()) .setType(type == null - || EdmPrimitiveTypeKind.Geography.getFullQualifiedName().equals(type) - || EdmPrimitiveTypeKind.Geometry.getFullQualifiedName().equals(type) - ? valuable.asGeospatial().getEdmPrimitiveTypeKind() - : EdmPrimitiveTypeKind.valueOfFQN(client.getServiceVersion(), type.toString())).build(); + || EdmPrimitiveTypeKind.Geography.getFullQualifiedName().equals(type) + || EdmPrimitiveTypeKind.Geometry.getFullQualifiedName().equals(type) + ? valuable.asGeospatial().getEdmPrimitiveTypeKind() + : EdmPrimitiveTypeKind.valueOfFQN(client.getServiceVersion(), type.toString())).build(); } else if (valuable.isPrimitive() || valuable.getValueType() == null) { value = client.getObjectFactory().newPrimitiveValueBuilder() .setValue(valuable.asPrimitive()) .setType(type == null || !EdmPrimitiveType.EDM_NAMESPACE.equals(type.getNamespace()) ? null - : EdmPrimitiveTypeKind.valueOfFQN(client.getServiceVersion(), type.toString())).build(); + : EdmPrimitiveTypeKind.valueOfFQN(client.getServiceVersion(), type.toString())).build(); } else if (valuable.isComplex() || valuable.isLinkedComplex()) { value = client.getObjectFactory().newComplexValue(type == null ? null : type.toString()); if (!valuable.isNull()) { diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/JSONTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/JSONTest.java index b46f42204..277aff044 100644 --- a/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/JSONTest.java +++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/JSONTest.java @@ -18,6 +18,10 @@ */ package org.apache.olingo.client.core.v4; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -30,7 +34,6 @@ import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; import org.apache.olingo.commons.api.format.ODataFormat; import org.junit.Test; - import java.io.ByteArrayInputStream; import java.io.StringWriter; import java.util.ArrayList; @@ -38,10 +41,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - public class JSONTest extends AbstractTest { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @@ -94,11 +93,11 @@ public class JSONTest extends AbstractTest { final String key = field.getKey(); if (key.charAt(0) == '#' - || key.endsWith(version.getJsonName(ODataServiceVersion.JsonKey.TYPE)) - || key.endsWith(version.getJsonName(ODataServiceVersion.JsonKey.MEDIA_EDIT_LINK)) - || key.endsWith(version.getJsonName(ODataServiceVersion.JsonKey.MEDIA_CONTENT_TYPE)) - || key.endsWith(version.getJsonName(ODataServiceVersion.JsonKey.ASSOCIATION_LINK)) - || key.endsWith(version.getJsonName(ODataServiceVersion.JsonKey.MEDIA_ETAG))) { + || key.endsWith(version.getJsonName(ODataServiceVersion.JsonKey.TYPE)) + || key.endsWith(version.getJsonName(ODataServiceVersion.JsonKey.MEDIA_EDIT_LINK)) + || key.endsWith(version.getJsonName(ODataServiceVersion.JsonKey.MEDIA_CONTENT_TYPE)) + || key.endsWith(version.getJsonName(ODataServiceVersion.JsonKey.ASSOCIATION_LINK)) + || key.endsWith(version.getJsonName(ODataServiceVersion.JsonKey.MEDIA_ETAG))) { toRemove.add(key); } else if (field.getValue().isObject()) { @@ -117,8 +116,8 @@ public class JSONTest extends AbstractTest { protected void assertSimilar(final String filename, final String actual) throws Exception { final JsonNode expected = OBJECT_MAPPER.readTree(IOUtils.toString(getClass().getResourceAsStream(filename)). - replace(getClient().getServiceVersion().getJsonName(ODataServiceVersion.JsonKey.NAVIGATION_LINK), - Constants.JSON_BIND_LINK_SUFFIX)); + replace(getClient().getServiceVersion().getJsonName(ODataServiceVersion.JsonKey.NAVIGATION_LINK), + Constants.JSON_BIND_LINK_SUFFIX)); cleanup((ObjectNode) expected); final ObjectNode actualNode = (ObjectNode) OBJECT_MAPPER.readTree(new ByteArrayInputStream(actual.getBytes())); cleanup(actualNode); @@ -128,7 +127,7 @@ public class JSONTest extends AbstractTest { protected void entitySet(final String filename, final ODataFormat format) throws Exception { final StringWriter writer = new StringWriter(); getClient().getSerializer(format).write(writer, getClient().getDeserializer(format).toEntitySet( - getClass().getResourceAsStream(filename + "." + getSuffix(format))).getPayload()); + getClass().getResourceAsStream(filename + "." + getSuffix(format))).getPayload()); assertSimilar(filename + "." + getSuffix(format), writer.toString()); } @@ -142,7 +141,7 @@ public class JSONTest extends AbstractTest { protected void entity(final String filename, final ODataFormat format) throws Exception { final StringWriter writer = new StringWriter(); getClient().getSerializer(format).write(writer, getClient().getDeserializer(format).toEntity( - getClass().getResourceAsStream(filename + "." + getSuffix(format))).getPayload()); + getClass().getResourceAsStream(filename + "." + getSuffix(format))).getPayload()); assertSimilar(filename + "." + getSuffix(format), writer.toString()); } @@ -169,7 +168,7 @@ public class JSONTest extends AbstractTest { protected void property(final String filename, final ODataFormat format) throws Exception { final StringWriter writer = new StringWriter(); getClient().getSerializer(format).write(writer, getClient().getDeserializer(format). - toProperty(getClass().getResourceAsStream(filename + "." + getSuffix(format))).getPayload()); + toProperty(getClass().getResourceAsStream(filename + "." + getSuffix(format))).getPayload()); assertSimilar(filename + "." + getSuffix(format), writer.toString()); } @@ -185,12 +184,12 @@ public class JSONTest extends AbstractTest { @Test public void crossjoin() throws Exception { assertNotNull(getClient().getDeserializer(ODataFormat.JSON_FULL_METADATA).toEntitySet( - getClass().getResourceAsStream("crossjoin.json"))); + getClass().getResourceAsStream("crossjoin.json"))); } protected void delta(final String filename, final ODataFormat format) throws Exception { final Delta delta = getClient().getDeserializer(format).toDelta( - getClass().getResourceAsStream(filename + "." + getSuffix(format))).getPayload(); + getClass().getResourceAsStream(filename + "." + getSuffix(format))).getPayload(); assertNotNull(delta); assertNotNull(delta.getDeltaLink()); assertEquals(5, delta.getCount(), 0); diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java index 6ee284c7e..91ab86fa9 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java @@ -82,19 +82,15 @@ public class ContextURL { } else if (contextURLasString.endsWith("/$ref")) { instance.suffix = Suffix.REFERENCE; contextURLasString = contextURLasString.replace("/$ref", StringUtils.EMPTY); - } else if (contextURLasString.endsWith("/$delta")) { instance.suffix = Suffix.DELTA; contextURLasString = contextURLasString.replace("/$delta", StringUtils.EMPTY); - } else if (contextURLasString.endsWith("/$deletedEntity")) { instance.suffix = Suffix.DELTA_DELETED_ENTITY; contextURLasString = contextURLasString.replace("/$deletedEntity", StringUtils.EMPTY); - } else if (contextURLasString.endsWith("/$link")) { instance.suffix = Suffix.DELTA_LINK; contextURLasString = contextURLasString.replace("/$link", StringUtils.EMPTY); - } else if (contextURLasString.endsWith("/$deletedLink")) { instance.suffix = Suffix.DELTA_DELETED_LINK; contextURLasString = contextURLasString.replace("/$deletedLink", StringUtils.EMPTY); @@ -125,8 +121,8 @@ public class ContextURL { } } - final int slashIdx = instance.entitySetOrSingletonOrType.indexOf('/'); - if (slashIdx != -1) { + final int slashIdx = instance.entitySetOrSingletonOrType.lastIndexOf('/'); + if (slashIdx != -1 && instance.entitySetOrSingletonOrType.substring(slashIdx + 1).indexOf('.') != -1) { final String clone = instance.entitySetOrSingletonOrType; instance.entitySetOrSingletonOrType = clone.substring(0, slashIdx); instance.derivedEntity = clone.substring(slashIdx + 1); @@ -226,7 +222,7 @@ public class ContextURL { } public ContextURL build() { - StringBuilder result = new StringBuilder(); + final StringBuilder result = new StringBuilder(); if (contextURL.serviceRoot != null) { result.append(contextURL.serviceRoot); } diff --git a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/data/ContextURLTest.java b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/data/ContextURLTest.java index 6317d668b..abef744f9 100644 --- a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/data/ContextURLTest.java +++ b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/data/ContextURLTest.java @@ -18,6 +18,11 @@ */ package org.apache.olingo.commons.api.data; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import org.apache.olingo.commons.api.data.ContextURL.Suffix; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; @@ -27,11 +32,6 @@ import org.mockito.Mockito; import java.net.URI; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - public class ContextURLTest { @Test @@ -52,6 +52,11 @@ public class ContextURLTest { assertNull(contextURL.getSelectList()); assertEquals("Items", contextURL.getNavOrPropertyPath()); assertFalse(contextURL.isEntity()); + + contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Me/Folders('Inbox')/Messages")); + + assertEquals("Me/Folders", contextURL.getEntitySetOrSingletonOrType()); + assertEquals("Messages", contextURL.getNavOrPropertyPath()); } @Test @@ -96,7 +101,7 @@ public class ContextURLTest { @Test public void collectionOfDerivedEntities() { final ContextURL contextURL = ContextURL.getInstance( - URI.create("http://host/service/$metadata#Customers/Model.VipCustomer")); + URI.create("http://host/service/$metadata#Customers/Model.VipCustomer")); assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType()); assertEquals("Model.VipCustomer", contextURL.getDerivedEntity()); @@ -108,7 +113,7 @@ public class ContextURLTest { @Test public void derivedEntity() { final ContextURL contextURL = ContextURL.getInstance( - URI.create("http://host/service/$metadata#Customers/Model.VipCustomer/$entity")); + URI.create("http://host/service/$metadata#Customers/Model.VipCustomer/$entity")); assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType()); assertEquals("Model.VipCustomer", contextURL.getDerivedEntity()); @@ -120,7 +125,7 @@ public class ContextURLTest { @Test public void collectionOfProjectedEntities() { final ContextURL contextURL = ContextURL.getInstance( - URI.create("http://host/service/$metadata#Customers(Address,Orders)")); + URI.create("http://host/service/$metadata#Customers(Address,Orders)")); assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType()); assertNull(contextURL.getDerivedEntity()); @@ -132,7 +137,7 @@ public class ContextURLTest { @Test public void projectedEntity() { ContextURL contextURL = ContextURL.getInstance( - URI.create("http://host/service/$metadata#Customers(Name,Rating)/$entity")); + URI.create("http://host/service/$metadata#Customers(Name,Rating)/$entity")); assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType()); assertNull(contextURL.getDerivedEntity()); @@ -141,7 +146,7 @@ public class ContextURLTest { assertTrue(contextURL.isEntity()); contextURL = ContextURL.getInstance( - URI.create("http://host/service/$metadata#Customers(Name,Address/Country)")); + URI.create("http://host/service/$metadata#Customers(Name,Address/Country)")); assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType()); assertNull(contextURL.getDerivedEntity()); @@ -153,8 +158,8 @@ public class ContextURLTest { @Test public void collectionOfProjectedExpandedEntities() { final ContextURL contextURL = ContextURL.getInstance( - URI.create("http://host/service/$metadata#Employees/" - + "Sales.Manager(DirectReports,DirectReports+(FirstName,LastName))")); + URI.create("http://host/service/$metadata#Employees/" + + "Sales.Manager(DirectReports,DirectReports+(FirstName,LastName))")); assertEquals("Employees", contextURL.getEntitySetOrSingletonOrType()); assertEquals("Sales.Manager", contextURL.getDerivedEntity()); @@ -166,7 +171,7 @@ public class ContextURLTest { @Test public void propertyValue() { final ContextURL contextURL = ContextURL.getInstance( - URI.create("http://host/service/$metadata#Customers(1)/Addresses")); + URI.create("http://host/service/$metadata#Customers(1)/Addresses")); assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType()); assertNull(contextURL.getDerivedEntity()); @@ -178,7 +183,7 @@ public class ContextURLTest { @Test public void CollectionOfComplexOrPrimitiveTypes() { final ContextURL contextURL = ContextURL.getInstance( - URI.create("http://host/service/$metadata#Collection(Edm.String)")); + URI.create("http://host/service/$metadata#Collection(Edm.String)")); assertEquals("Collection(Edm.String)", contextURL.getEntitySetOrSingletonOrType()); assertNull(contextURL.getDerivedEntity()); @@ -260,8 +265,8 @@ public class ContextURLTest { EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class); Mockito.when(entitySet.getName()).thenReturn("Customers"); ContextURL contextURL = ContextURL.create().serviceRoot(URI.create("http://host/service/")) - .entitySet(entitySet) - .build(); + .entitySet(entitySet) + .build(); assertEquals("http://host/service/$metadata#Customers", contextURL.getURI().toASCIIString()); } @@ -272,9 +277,9 @@ public class ContextURLTest { EdmEntityType derivedType = Mockito.mock(EdmEntityType.class); Mockito.when(derivedType.getFullQualifiedName()).thenReturn(new FullQualifiedName("Model", "VipCustomer")); ContextURL contextURL = ContextURL.create().serviceRoot(URI.create("http://host/service/")) - .entitySet(entitySet) - .derived(derivedType) - .build(); + .entitySet(entitySet) + .derived(derivedType) + .build(); assertEquals("http://host/service/$metadata#Customers/Model.VipCustomer", contextURL.getURI().toASCIIString()); } @@ -292,12 +297,12 @@ public class ContextURLTest { EdmEntityType derivedType = Mockito.mock(EdmEntityType.class); Mockito.when(derivedType.getFullQualifiedName()).thenReturn(new FullQualifiedName("Model", "VipCustomer")); ContextURL contextURL = ContextURL.create().serviceRoot(URI.create("http://host/service/")) - .entitySet(entitySet) - .derived(derivedType) - .suffix(Suffix.ENTITY) - .build(); + .entitySet(entitySet) + .derived(derivedType) + .suffix(Suffix.ENTITY) + .build(); assertEquals("http://host/service/$metadata#Customers/Model.VipCustomer/$entity", - contextURL.getURI().toASCIIString()); + contextURL.getURI().toASCIIString()); } @Test(expected = IllegalArgumentException.class)