OLINGO-1383
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
index 6e49f81..006e477 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/EntityCollectionSerializerOptions.java
@@ -35,6 +35,7 @@
private String id;
private ODataContentWriteErrorCallback odataContentWriteErrorCallback;
private String xml10InvalidCharReplacement;
+ private boolean isFullRepresentation = false;
/** Gets the {@link ContextURL}. */
public ContextURL getContextURL() {
@@ -81,6 +82,11 @@
public String xml10InvalidCharReplacement() {
return xml10InvalidCharReplacement;
}
+
+ /** Inline entries will not have @delta if representation is full **/
+ public boolean isFullRepresentation() {
+ return isFullRepresentation;
+ }
/** Initializes the options builder. */
public static Builder with() {
@@ -150,6 +156,12 @@
return this;
}
+ /** sets isFullRepresentation to represent inline entries**/
+ public Builder isFullRepresentation(boolean isFullRepresentation) {
+ options.isFullRepresentation = isFullRepresentation;
+ return this;
+ }
+
/** Builds the OData serializer options. */
public EntityCollectionSerializerOptions build() {
return options;
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
index 3ccf0d3..69603df 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
@@ -278,10 +278,20 @@
public boolean assertHttpMethod(ODataResponse response) throws ODataHandlerException {
// the create/update/delete to navigation property is done through references
// see # 11.4.6
- if (!getNavigations().isEmpty() && !isGET()) {
- return methodNotAllowed(response, httpMethod(),
- "create/update/delete to navigation property is done through references",
- allowedMethods());
+ if (!getNavigations().isEmpty()) {
+ if (isPOST()) {
+ UriResourceNavigation last = getNavigations().getLast();
+ if (!(getEntitySet().getRelatedBindingTarget(last.getProperty().getName())
+ instanceof EdmEntitySet)) {
+ return methodNotAllowed(response, httpMethod(),
+ "navigation updates must be to an entity contained in an entity set",
+ allowedMethods());
+ }
+ } else if (!isGET()) {
+ return methodNotAllowed(response, httpMethod(),
+ "update/delete to navigation property is done through references",
+ allowedMethods());
+ }
}
if ((isGET() || isDELETE()) && getReturnRepresentation() != ReturnRepresentation.NONE) {
@@ -316,13 +326,14 @@
public void execute(ServiceHandler handler, ODataResponse response)
throws ODataLibraryException, ODataApplicationException {
+ ContextURL contextURL = getContextURL(odata);
EntityResponse entityResponse = EntityResponse.getInstance(DataRequest.this,
- getContextURL(odata), false, response);
+ contextURL, false, response);
if (isGET()) {
if (isCollection()) {
handler.read(DataRequest.this,
- EntitySetResponse.getInstance(DataRequest.this, getContextURL(odata), false, response));
+ EntitySetResponse.getInstance(DataRequest.this, contextURL, false, response));
} else {
handler.read(DataRequest.this,entityResponse);
}
@@ -339,24 +350,37 @@
} else if (ifNoneMatch) {
// 11.4.4
entityResponse = EntityResponse.getInstance(DataRequest.this,
- getContextURL(odata), false, response, getReturnRepresentation());
+ contextURL, false, response, getReturnRepresentation());
handler.createEntity(DataRequest.this, getEntityFromClient(), entityResponse);
} else {
handler.upsertEntity(DataRequest.this, getEntityFromClient(), isPATCH(), getETag(),
entityResponse);
}
} else if (isPOST()) {
- entityResponse = EntityResponse.getInstance(DataRequest.this,
- getContextURL(odata), false, response, getReturnRepresentation());
- handler.createEntity(DataRequest.this, getEntityFromClient(),entityResponse);
+ if (!getNavigations().isEmpty()) {
+ entityResponse = EntityResponse.getInstance(DataRequest.this,
+ contextURL, false, response, getReturnRepresentation());
+ UriResourceNavigation last = getNavigations().getLast();
+ EdmEntityType navigationType = last.getProperty().getType();
+ Entity entity = getEntityFromClient(navigationType);
+ handler.createEntity(DataRequest.this, entity,entityResponse);
+ } else {
+ entityResponse = EntityResponse.getInstance(DataRequest.this,
+ contextURL, false, response, getReturnRepresentation());
+ handler.createEntity(DataRequest.this, getEntityFromClient(),entityResponse);
+ }
} else if (isDELETE()) {
handler.deleteEntity(DataRequest.this, getETag(), entityResponse);
}
}
private Entity getEntityFromClient() throws DeserializerException {
+ return getEntityFromClient(getEntitySet().getEntityType());
+ }
+
+ private Entity getEntityFromClient(EdmEntityType entityType) throws DeserializerException {
ODataDeserializer deserializer = odata.createDeserializer(getRequestContentType(), getServiceMetaData());
- return deserializer.entity(getODataRequest().getBody(), getEntitySet().getEntityType()).getEntity();
+ return deserializer.entity(getODataRequest().getBody(), entityType).getEntity();
}
@Override
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java
index 562eac0..cde9b74 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java
@@ -493,7 +493,7 @@
map = new HashMap<String, Object>();
this.peopleLinks.put((String) parentEntity.getProperty(key).getValue(), map);
}
- map.put("Photo", childEntity.getProperty(key).getValue());
+ map.put("Photo", ((Long)childEntity.getProperty("Id").getValue()).intValue());
setLink(parentEntity, navigation, childEntity);
} else if (type.getName().equals("Trip") && navigation.equals("PlanItems")) {
Map<String, Object> map = this.tripLinks.get(parentEntity.getProperty(key).getValue());
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
index 4dbf74e..f594a64 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
@@ -239,7 +239,12 @@
public void createEntity(DataRequest request, Entity entity, EntityResponse response)
throws ODataLibraryException, ODataApplicationException {
EdmEntitySet edmEntitySet = request.getEntitySet();
-
+
+ if (!request.getNavigations().isEmpty()) {
+ UriResourceNavigation lastNavigation = request.getNavigations().getLast();
+ edmEntitySet = (EdmEntitySet)edmEntitySet.getRelatedBindingTarget(lastNavigation.getProperty().getName());
+ }
+
Entity created = this.dataModel.createEntity(edmEntitySet, entity, request.getODataRequest().getRawBaseUri());
try {
@@ -272,6 +277,25 @@
} catch (URISyntaxException e) {
throw new ODataApplicationException(e.getMessage(), 500, Locale.getDefault());
}
+
+ if (!request.getNavigations().isEmpty()) {
+ UriResourceNavigation lastNavigation = request.getNavigations().getLast();
+
+ String parentRequest = request.getODataRequest().getRawRequestUri();
+ parentRequest = parentRequest.substring(0, parentRequest.lastIndexOf('/'));
+
+ DataRequest bindingRequest;
+ try {
+ bindingRequest = request.parseLink(new URI(parentRequest));
+ } catch (URISyntaxException e) {
+ throw new ODataApplicationException(e.getMessage(), 500, Locale.getDefault());
+ }
+
+ Entity reference = this.dataModel.getEntity(bindingRequest.getEntitySet().getName(),
+ bindingRequest.getKeyPredicates());
+
+ this.dataModel.addNavigationLink(lastNavigation.getProperty().getName(), reference, created);
+ }
response.writeCreatedEntity(edmEntitySet, created);
}
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
index 520f3ee..5d2a13d 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
@@ -552,6 +552,46 @@
assertTrue(node.get("value").isArray());
assertEquals("scottketchum", ((ArrayNode)node.get("value")).get(1).get("UserName").asText());
}
+
+ @Ignore("4.01 style binding not supported")
+ @Test
+ public void testCreateEntityWithLinkToRelatedEntitiesIds() throws Exception {
+ String payload = "{\n" +
+ " \"UserName\":\"olingo\",\n" +
+ " \"FirstName\":\"Olingo\",\n" +
+ " \"LastName\":\"Apache\",\n" +
+ " \"Emails\":[\n" +
+ " \"olingo@apache.org\"\n" +
+ " ],\n" +
+ " \"AddressInfo\":[\n" +
+ " {\n" +
+ " \"Address\":\"100 apache Ln.\",\n" +
+ " \"City\":{\n" +
+ " \"CountryRegion\":\"United States\",\n" +
+ " \"Name\":\"Boise\",\n" +
+ " \"Region\":\"ID\"\n" +
+ " }\n" +
+ " }\n" +
+ " ],\n" +
+ " \"Gender\":\"0\",\n" +
+ " \"Concurrency\":635585295719432047,\n" +
+ "\"Friends\":[" +
+ "{\"@id\": \"People('russellwhyte')\"},\n" +
+ "{\"@id\": \"People('scottketchum')\"}\n" +
+ "]"+
+ "}";
+ HttpPost postRequest = new HttpPost(baseURL + "/People");
+ postRequest.setEntity(new StringEntity(payload, ContentType.APPLICATION_JSON));
+ postRequest.setHeader("Prefer", "return=minimal");
+ HttpResponse response = httpSend(postRequest, 204);
+ EntityUtils.consumeQuietly(response.getEntity());
+
+ response = httpGET(baseURL+"/People('olingo')/Friends", 200);
+ JsonNode node = getJSONNode(response);
+ assertEquals(baseURL+"/$metadata#People", node.get("@odata.context").asText());
+ assertTrue(node.get("value").isArray());
+ assertEquals("scottketchum", ((ArrayNode)node.get("value")).get(1).get("UserName").asText());
+ }
@Test
public void testUpdatePrimitiveProperty() throws Exception {
@@ -779,6 +819,80 @@
node = getJSONNode(response);
assertNull("/People('russellwhyte')", ((ArrayNode) node.get("value")).get(2));
}
+
+ @Test
+ public void testAddEntityToNavigationFailsNotEntitySet() throws Exception {
+ // adding to an entity that is not part of an entity set
+ // goes against a few assumptions in downstream code, so
+ // not handling for now
+ String msg = "{\n" +
+ "\"TripId\": 1010,\n" +
+ "\"Description\": \"The trip of a lifetime.\",\n" +
+ "\"Name\": \"Grand Prize\",\n" +
+ "\"Budget\": 100000\n" +
+ "}";
+ String editUrl = baseURL + "/People('vincentcalabrese')/Trips";
+ HttpPost postRequest = new HttpPost(editUrl);
+ postRequest.setEntity(new StringEntity(msg, ContentType.APPLICATION_JSON));
+ postRequest.addHeader("Content-Type", "application/json;odata.metadata=minimal");
+ HttpResponse response = httpSend(postRequest, 405);
+ EntityUtils.consumeQuietly(response.getEntity());
+ }
+
+ @Test
+ public void testAddEntityToNavigation() throws Exception {
+ String msg = "{\n" +
+ "\"Id\": 1010,\n" +
+ "\"Name\": \"Grand Prize\"\n" +
+ "}";
+ String editUrl = baseURL + "/People('vincentcalabrese')/Photo";
+ HttpPost postRequest = new HttpPost(editUrl);
+ postRequest.setEntity(new StringEntity(msg, ContentType.APPLICATION_JSON));
+ postRequest.addHeader("Content-Type", "application/json;odata.metadata=minimal");
+ HttpResponse response = httpSend(postRequest, 201);
+ EntityUtils.consumeQuietly(response.getEntity());
+
+ response = httpGET(baseURL+"/People('vincentcalabrese')/Photo", 200);
+ JsonNode node = getJSONNode(response);
+ assertEquals(baseURL+"/$metadata#Photos/$entity", node.get("@odata.context").asText());
+ assertEquals("Grand Prize", node.get("Name").asText());
+ }
+
+ @Test
+ public void testAddEntityToNavigationSelf() throws Exception {
+ String payload = "{\n" +
+ " \"UserName\":\"olingo\",\n" +
+ " \"FirstName\":\"Olingo\",\n" +
+ " \"LastName\":\"Apache\",\n" +
+ " \"Emails\":[\n" +
+ " \"olingo@apache.org\"\n" +
+ " ],\n" +
+ " \"AddressInfo\":[\n" +
+ " {\n" +
+ " \"Address\":\"100 apache Ln.\",\n" +
+ " \"City\":{\n" +
+ " \"CountryRegion\":\"United States\",\n" +
+ " \"Name\":\"Boise\",\n" +
+ " \"Region\":\"ID\"\n" +
+ " }\n" +
+ " }\n" +
+ " ],\n" +
+ " \"Gender\":\"0\",\n" +
+ " \"Concurrency\":635585295719432047\n" +
+ "}";
+ String editUrl = baseURL + "/People('vincentcalabrese')/Friends";
+ HttpPost postRequest = new HttpPost(editUrl);
+ postRequest.setEntity(new StringEntity(payload, ContentType.APPLICATION_JSON));
+ postRequest.addHeader("Content-Type", "application/json;odata.metadata=minimal");
+ HttpResponse response = httpSend(postRequest, 201);
+ EntityUtils.consumeQuietly(response.getEntity());
+
+ response = httpGET(baseURL+"/People('vincentcalabrese')/Friends", 200);
+ JsonNode node = getJSONNode(response);
+ assertEquals(baseURL+"/$metadata#People", node.get("@odata.context").asText());
+ assertTrue(node.get("value").isArray());
+ assertEquals("olingo", ((ArrayNode)node.get("value")).get(2).get("UserName").asText());
+ }
@Test
public void testDeleteReference() throws Exception {
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
index bbd94e5..7a632b1 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
@@ -267,11 +267,13 @@
static void fillUriInformation(final ODataRequest odRequest,
final HttpServletRequest httpRequest, final int split) {
String rawRequestUri = httpRequest.getRequestURL().toString();
-
+
+ String rawServiceResolutionUri = null;
String rawODataPath;
//Application need to set the request mapping attribute if the request is coming from a spring based application
if(httpRequest.getAttribute(REQUESTMAPPING)!=null){
String requestMapping = httpRequest.getAttribute(REQUESTMAPPING).toString();
+ rawServiceResolutionUri = requestMapping;
int beginIndex = rawRequestUri.indexOf(requestMapping) + requestMapping.length();
rawODataPath = rawRequestUri.substring(beginIndex);
}else if(!"".equals(httpRequest.getServletPath())) {
@@ -286,7 +288,6 @@
rawODataPath = httpRequest.getRequestURI();
}
- String rawServiceResolutionUri = null;
if (split > 0) {
rawServiceResolutionUri = rawODataPath;
for (int i = 0; i < split; i++) {
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/JsonDeltaSerializerWithNavigations.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/JsonDeltaSerializerWithNavigations.java
index ad8635d..bf74efd 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/JsonDeltaSerializerWithNavigations.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/JsonDeltaSerializerWithNavigations.java
@@ -142,7 +142,8 @@
json.writeStartArray();
for (final Entity entity : entitySet.getEntities()) {
writeAddedUpdatedEntity(metadata, entityType, entity, options.getExpand(), options.getSelect(),
- options.getContextURL(), false, options.getContextURL().getEntitySetOrSingletonOrType(), json);
+ options.getContextURL(), false, options.getContextURL().getEntitySetOrSingletonOrType(), json,
+ options.isFullRepresentation());
}
for (final DeletedEntity deletedEntity : entitySet.getDeletedEntities()) {
writeDeletedEntity(deletedEntity, json);
@@ -232,7 +233,7 @@
public void writeAddedUpdatedEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
final Entity entity, final ExpandOption expand, final SelectOption select, final ContextURL url,
- final boolean onlyReference, String name, final JsonGenerator json)
+ final boolean onlyReference, String name, final JsonGenerator json, boolean isFullRepresentation)
throws IOException, SerializerException {
json.writeStartObject();
if (entity.getId() != null && url != null) {
@@ -248,7 +249,7 @@
}
json.writeStringField(Constants.AT + Constants.ATOM_ATTR_ID, getEntityId(entity, entityType, name));
writeProperties(metadata, entityType, entity.getProperties(), select, json);
- writeNavigationProperties(metadata, entityType, entity, expand, name, json);
+ writeNavigationProperties(metadata, entityType, entity, expand, name, json, isFullRepresentation);
json.writeEndObject();
}
@@ -503,7 +504,8 @@
protected void writeNavigationProperties(final ServiceMetadata metadata,
final EdmStructuredType type, final Linked linked, final ExpandOption expand,
- final String name, final JsonGenerator json) throws SerializerException, IOException {
+ final String name, final JsonGenerator json, boolean isFullRepresentation)
+ throws SerializerException, IOException {
if (ExpandSelectHelper.hasExpand(expand)) {
final boolean expandAll = ExpandSelectHelper.getExpandAll(expand) != null;
final Set<String> expanded = expandAll ? new HashSet<String>() : ExpandSelectHelper.getExpandedPropertyNames(
@@ -525,7 +527,15 @@
innerOptions == null ? null : innerOptions.getCountOption(),
innerOptions == null ? false : innerOptions.hasCountPath(),
innerOptions == null ? false : innerOptions.isRef(),
- name, json);
+ name, json, isFullRepresentation);
+ } else {
+ json.writeFieldName(property.getName());
+ if (property.isCollection()) {
+ json.writeStartArray();
+ json.writeEndArray();
+ } else {
+ json.writeNull();
+ }
}
}
}
@@ -534,24 +544,28 @@
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
final AbstractEntityCollection entitySet, final ExpandOption expand, final SelectOption select,
- final boolean onlyReference, String name, final JsonGenerator json) throws IOException,
- SerializerException {
- json.writeStartArray();
- for (final Entity entity : entitySet) {
- if (onlyReference) {
- json.writeStartObject();
- json.writeStringField(Constants.JSON_ID, getEntityId(entity, entityType, null));
- json.writeEndObject();
- } else {
- if (entity instanceof DeletedEntity) {
- writeDeletedEntity(entity, json);
+ final boolean onlyReference, String name, final JsonGenerator json,
+ boolean isFullRepresentation) throws IOException, SerializerException {
+ if (entitySet instanceof AbstractEntityCollection) {
+ AbstractEntityCollection entities = (AbstractEntityCollection)entitySet;
+ json.writeStartArray();
+ for (final Entity entity : entities) {
+ if (onlyReference) {
+ json.writeStartObject();
+ json.writeStringField(Constants.JSON_ID, getEntityId(entity, entityType, null));
+ json.writeEndObject();
} else {
- writeAddedUpdatedEntity(metadata, entityType, entity, expand, select, null, false, name, json);
+ if (entity instanceof DeletedEntity) {
+ writeDeletedEntity(entity, json);
+ } else {
+ writeAddedUpdatedEntity(metadata, entityType, entity, expand, select, null, false,
+ name, json, isFullRepresentation);
+ }
+
}
-
}
+ json.writeEndArray();
}
- json.writeEndArray();
}
protected void writeExpandedNavigationProperty(
@@ -559,23 +573,37 @@
final Link navigationLink, final ExpandOption innerExpand,
final SelectOption innerSelect, final CountOption innerCount,
final boolean writeOnlyCount, final boolean writeOnlyRef, final String name,
- final JsonGenerator json) throws IOException, SerializerException {
+ final JsonGenerator json, boolean isFullRepresentation) throws IOException, SerializerException {
if (property.isCollection()) {
- if (navigationLink != null && navigationLink.getInlineEntitySet() != null) {
- json.writeFieldName(property.getName() + Constants.AT + Constants.DELTAVALUE);
+ if (navigationLink == null || navigationLink.getInlineEntitySet() == null) {
+ json.writeFieldName(property.getName());
+ json.writeStartArray();
+ json.writeEndArray();
+ } else if (navigationLink != null && navigationLink.getInlineEntitySet() != null) {
+ if (isFullRepresentation) {
+ json.writeFieldName(property.getName());
+ } else {
+ json.writeFieldName(property.getName() + Constants.AT + Constants.DELTAVALUE);
+ }
writeEntitySet(metadata, property.getType(), navigationLink.getInlineEntitySet(), innerExpand,
- innerSelect, writeOnlyRef, name, json);
+ innerSelect, writeOnlyRef, name, json, isFullRepresentation);
}
} else {
- json.writeFieldName(property.getName()+ Constants.AT + Constants.DELTAVALUE);
- if (navigationLink != null && navigationLink.getInlineEntity() != null) {
+ if (isFullRepresentation) {
+ json.writeFieldName(property.getName());
+ } else {
+ json.writeFieldName(property.getName()+ Constants.AT + Constants.DELTAVALUE);
+ }
+ if (navigationLink == null || navigationLink.getInlineEntity() == null) {
+ json.writeNull();
+ } else if (navigationLink != null && navigationLink.getInlineEntity() != null) {
if (navigationLink.getInlineEntity() instanceof DeletedEntity) {
writeDeletedEntity(navigationLink.getInlineEntity(), json);
} else {
writeAddedUpdatedEntity(metadata, property.getType(), navigationLink.getInlineEntity(),
- innerExpand, innerSelect, null, writeOnlyRef, name, json);
+ innerExpand, innerSelect, null, writeOnlyRef, name, json, isFullRepresentation);
}
}
}
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java
index 0645423..158cae6 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java
@@ -212,7 +212,7 @@
String rawODataPath = p[4];
String rawQueryPath = "".equals(p[5]) ? null : p[5];
String rawRequestUri = requestUrl + (queryString == null ? "" : "?" + queryString);
- String rawServiceResolutionUri = "".equals(p[3]) ? null : p[3];
+ String rawServiceResolutionUri = ("0".equals(p[6])) ? p[2] : p[3];
when(hr.getAttribute("requestMapping")).thenReturn(p[2]);
ODataHttpHandlerImpl.fillUriInformation(odr, hr, Integer.parseInt(p[6]));
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 c5b62dc..3c188a0 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
@@ -1796,8 +1796,38 @@
setLinks(entityCollection.getEntities().get(0), "NavPropertyETAllPrimMany", targetEntities.get(1),
targetEntities.get(2));
setLink(entityCollection.getEntities().get(3), "NavPropertyETAllPrimOne", targetEntities.get(0));
+ setLinkForDelta(entityCollection.getEntities().get(1), "NavPropertyETAllPrimOne");
+ setLinksForDelta(entityCollection.getEntities().get(2), "NavPropertyETAllPrimMany");
}
+ protected static void setLinkForDelta(final Entity entity, final String navigationPropertyName) {
+ Link link = entity.getNavigationLink(navigationPropertyName);
+ if (link == null) {
+ link = new Link();
+ link.setRel(Constants.NS_NAVIGATION_LINK_REL + navigationPropertyName);
+ link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
+ link.setTitle(navigationPropertyName);
+ link.setHref(null);
+ entity.getNavigationLinks().add(link);
+ }
+ link.setInlineEntity(null);
+ }
+
+ protected static void setLinksForDelta(final Entity entity, final String navigationPropertyName) {
+ Link link = entity.getNavigationLink(navigationPropertyName);
+ if (link == null) {
+ link = new Link();
+ link.setRel(Constants.NS_NAVIGATION_LINK_REL + navigationPropertyName);
+ link.setType(Constants.ENTITY_SET_NAVIGATION_LINK_TYPE);
+ link.setTitle(navigationPropertyName);
+ link.setInlineEntitySet(null);
+ link.setHref(entity.getId().toASCIIString() + "/" + navigationPropertyName);
+ entity.getNavigationLinks().add(link);
+ } else {
+ link.getInlineEntitySet().getEntities().addAll(null);
+ }
+ }
+
private void linkESPeople(final Map<String, EntityCollection> data) {
final EntityCollection entityCollection = data.get("ESPeople");
final List<Entity> targetEntities = data.get("ESPeople").getEntities();
@@ -2096,7 +2126,7 @@
link.setRel(Constants.NS_NAVIGATION_LINK_REL + navigationPropertyName);
link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
link.setTitle(navigationPropertyName);
- link.setHref(target.getId().toASCIIString());
+ link.setHref(target.getId() != null ? target.getId().toASCIIString() : null);
entity.getNavigationLinks().add(link);
}
link.setInlineEntity(target);
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/JsonDeltaSerializerWithNavigationsTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/JsonDeltaSerializerWithNavigationsTest.java
index c09caf9..7bfd202 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/JsonDeltaSerializerWithNavigationsTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/JsonDeltaSerializerWithNavigationsTest.java
@@ -60,6 +60,7 @@
import org.junit.Test;
import org.mockito.Mockito;
+@SuppressWarnings("deprecation")
public class JsonDeltaSerializerWithNavigationsTest {
EdmDeltaSerializer ser;
@@ -541,13 +542,58 @@
+ "\"PropertyDuration\":\"PT0S\",\"PropertyGuid\":"
+ "\"76543201-23ab-cdef-0123-456789cccddd\","
+ "\"PropertyTimeOfDay\":\"00:01:01\"}]},{\"@id\":\"ESDelta(-32768)\","
- + "\"PropertyString\":\"Number:-32768\"}]"
+ + "\"PropertyString\":\"Number:-32768\",\"NavPropertyETAllPrimMany\":[]}]"
+ "}";
Assert.assertNotNull(jsonString);
Assert.assertEquals(expectedResult, jsonString);
}
@Test
+ public void navigationInDeltaEntityInFullRepresentation() throws Exception {
+ final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
+ Delta delta = new Delta();
+ final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+ final Entity entity2 = data.readAll(edmEntitySet).getEntities().get(1);
+ final ExpandOption expand = ExpandSelectMock.mockExpandOption(Collections.singletonList(
+ ExpandSelectMock.mockExpandItem(edmEntitySet, "NavPropertyETAllPrimMany")));
+ List<Entity> addedEntity = new ArrayList<Entity>();
+ Entity changedEntity = new Entity();
+ changedEntity.setId(entity2.getId());
+ changedEntity.addProperty(entity2.getProperty("PropertyString"));
+ addedEntity.add(entity);
+ addedEntity.add(changedEntity);
+ delta.getEntities().addAll(addedEntity);
+ InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
+ EntityCollectionSerializerOptions.with()
+ .contextURL(ContextURL.with().entitySet(edmEntitySet).build()).expand(expand)
+ .isFullRepresentation(true).build()).getContent();
+ String jsonString = IOUtils.toString(stream);
+ final String expectedResult = "{"
+ + "\"@context\":\"$metadata#ESDelta/$delta\",\"value\":"
+ + "[{\"@id\":\"ESDelta(32767)\",\"PropertyInt16\":32767,\"PropertyString\":\"Number:32767\","
+ + "\"NavPropertyETAllPrimMany\":["
+ + "{\"@id\":\"ESAllPrim(-32768)\",\"PropertyInt16\":-32768,"
+ + "\"PropertyString\":\"Second Resource - negative values\","
+ + "\"PropertyBoolean\":false,\"PropertyByte\":0,\"PropertySByte\":-128,\"PropertyInt32\":-2147483648,"
+ + "\"PropertyInt64\":-9223372036854775808,\"PropertySingle\":-1.79E8,\"PropertyDouble\":-179000.0,"
+ + "\"PropertyDecimal\":-34,\"PropertyBinary\":\"ASNFZ4mrze8=\",\"PropertyDate\":\"2015-11-05\","
+ + "\"PropertyDateTimeOffset\":\"2005-12-03T07:17:08Z\",\"PropertyDuration\":\"PT9S\","
+ + "\"PropertyGuid\":\"76543201-23ab-cdef-0123-456789dddfff\",\"PropertyTimeOfDay\":\"23:49:14\"},"
+ + "{\"@id\":\"ESAllPrim(0)\",\"PropertyInt16\":0,\"PropertyString\":\"\","
+ + "\"PropertyBoolean\":false,\"PropertyByte\":0,\"PropertySByte\":0,\"PropertyInt32\":0,"
+ + "\"PropertyInt64\":0,\"PropertySingle\":0.0,\"PropertyDouble\":0.0,"
+ + "\"PropertyDecimal\":0,"
+ + "\"PropertyBinary\":\"\",\"PropertyDate\":\"1970-01-01\","
+ + "\"PropertyDateTimeOffset\":\"2005-12-03T00:00:00Z\","
+ + "\"PropertyDuration\":\"PT0S\",\"PropertyGuid\":"
+ + "\"76543201-23ab-cdef-0123-456789cccddd\","
+ + "\"PropertyTimeOfDay\":\"00:01:01\"}]},{\"@id\":\"ESDelta(-32768)\","
+ + "\"PropertyString\":\"Number:-32768\",\"NavPropertyETAllPrimMany\":[]}]}";
+ Assert.assertNotNull(jsonString);
+ Assert.assertEquals(expectedResult, jsonString);
+ }
+
+ @Test
public void navigationInDeltaEntityWithDeleted() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
Delta delta = new Delta();
@@ -839,7 +885,8 @@
String jsonString = IOUtils.toString(stream);
final String expectedResult = "{"
+ "\"@context\":\"$metadata#ESDelta/$delta\",\"value\":[{\"@id\":\"ESDelta(32767)\","
- + "\"PropertyInt16\":32767,\"PropertyString\":\"Number:32767\"},{\"@id\":\"ESDelta(100)\","
+ + "\"PropertyInt16\":32767,\"PropertyString\":\"Number:32767\",\"NavPropertyETAllPrimOne\":null},"
+ + "{\"@id\":\"ESDelta(100)\","
+ "\"PropertyInt16\":100,\"PropertyString\":\"Number:100\","
+ "\"NavPropertyETAllPrimOne@delta\":"
+ "{\"@id\":\"ESAllPrim(32767)\",\"PropertyInt16\":32767,\"PropertyString\":"
@@ -854,6 +901,45 @@
Assert.assertEquals(expectedResult, jsonString);
}
+ @Test
+ public void navigationEntityInDeltaEntityWithFullRepresentation() throws Exception {
+ final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
+ Delta delta = new Delta();
+ final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+ final Entity entity2 = data.readAll(edmEntitySet).getEntities().get(3);
+ final ExpandOption expand = ExpandSelectMock.mockExpandOption(Collections.singletonList(
+ ExpandSelectMock.mockExpandItem(edmEntitySet, "NavPropertyETAllPrimOne")));
+ List<Entity> addedEntity = new ArrayList<Entity>();
+ Entity changedEntity = new Entity();
+ changedEntity.setId(entity.getId());
+ changedEntity.addProperty(entity.getProperty("PropertyString"));
+ addedEntity.add(entity);
+ addedEntity.add(entity2);
+ delta.getEntities().addAll(addedEntity);
+ InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
+ EntityCollectionSerializerOptions.with()
+ .contextURL(ContextURL.with().entitySet(edmEntitySet).build()).expand(expand)
+ .isFullRepresentation(true)
+ .build()).getContent();
+ String jsonString = IOUtils.toString(stream);
+ final String expectedResult = "{"
+ + "\"@context\":\"$metadata#ESDelta/$delta\",\"value\":[{\"@id\":\"ESDelta(32767)\","
+ + "\"PropertyInt16\":32767,\"PropertyString\":\"Number:32767\",\"NavPropertyETAllPrimOne\":null},"
+ + "{\"@id\":\"ESDelta(100)\","
+ + "\"PropertyInt16\":100,\"PropertyString\":\"Number:100\","
+ + "\"NavPropertyETAllPrimOne\":"
+ + "{\"@id\":\"ESAllPrim(32767)\",\"PropertyInt16\":32767,\"PropertyString\":"
+ + "\"First Resource - positive values\","
+ + "\"PropertyBoolean\":true,\"PropertyByte\":255,\"PropertySByte\":127,\"PropertyInt32\":2147483647,"
+ + "\"PropertyInt64\":9223372036854775807,\"PropertySingle\":1.79E20,\"PropertyDouble\":-1.79E19,"
+ + "\"PropertyDecimal\":34,\"PropertyBinary\":\"ASNFZ4mrze8=\",\"PropertyDate\":\"2012-12-03\","
+ + "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\",\"PropertyDuration\":\"PT6S\",\"PropertyGuid\":"
+ + "\"01234567-89ab-cdef-0123-456789abcdef\",\"PropertyTimeOfDay\":\"03:26:05\"}}]"
+ + "}";
+ Assert.assertNotNull(jsonString);
+ Assert.assertEquals(expectedResult, jsonString);
+ }
+
@Test(expected = SerializerException.class)
public void negativeDeltaEntityTest() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
@@ -1010,4 +1096,91 @@
Assert.assertEquals(expectedResult, jsonString);
}
+ @Test
+ public void emptynavigationToManyInDeltaEntityInFullRepresentation() throws Exception {
+ final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
+ Delta delta = new Delta();
+ final Entity entity = data.readAll(edmEntitySet).getEntities().get(2);
+ final ExpandOption expand = ExpandSelectMock.mockExpandOption(Collections.singletonList(
+ ExpandSelectMock.mockExpandItem(edmEntitySet, "NavPropertyETAllPrimMany")));
+ List<Entity> addedEntity = new ArrayList<Entity>();
+ addedEntity.add(entity);
+ delta.getEntities().addAll(addedEntity);
+ InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
+ EntityCollectionSerializerOptions.with()
+ .contextURL(ContextURL.with().entitySet(edmEntitySet).build()).expand(expand)
+ .isFullRepresentation(true).build()).getContent();
+ String jsonString = IOUtils.toString(stream);
+ final String expectedResult = "{\"@context\":\"$metadata#ESDelta/$delta\","
+ + "\"value\":[{\"@id\":\"ESDelta(0)\",\"PropertyInt16\":0,"
+ + "\"PropertyString\":\"Number:0\",\"NavPropertyETAllPrimMany\":[]}]}";
+ Assert.assertNotNull(jsonString);
+ Assert.assertEquals(expectedResult, jsonString);
+ }
+
+ @Test
+ public void emptynavigationToOneInDeltaEntityInFullRepresentation() throws Exception {
+ final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
+ Delta delta = new Delta();
+ final Entity entity = data.readAll(edmEntitySet).getEntities().get(1);
+ final ExpandOption expand = ExpandSelectMock.mockExpandOption(Collections.singletonList(
+ ExpandSelectMock.mockExpandItem(edmEntitySet, "NavPropertyETAllPrimOne")));
+ List<Entity> addedEntity = new ArrayList<Entity>();
+ addedEntity.add(entity);
+ delta.getEntities().addAll(addedEntity);
+ InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
+ EntityCollectionSerializerOptions.with()
+ .contextURL(ContextURL.with().entitySet(edmEntitySet).build()).expand(expand)
+ .isFullRepresentation(true).build()).getContent();
+ String jsonString = IOUtils.toString(stream);
+ final String expectedResult = "{\"@context\":\"$metadata#ESDelta/$delta\","
+ + "\"value\":[{\"@id\":\"ESDelta(-32768)\",\"PropertyInt16\":-32768,"
+ + "\"PropertyString\":\"Number:-32768\",\"NavPropertyETAllPrimOne\":null}]}";
+ Assert.assertNotNull(jsonString);
+ Assert.assertEquals(expectedResult, jsonString);
+ }
+
+ @Test
+ public void nullnavigationToOneInDeltaEntityInFullRepresentation() throws Exception {
+ final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
+ Delta delta = new Delta();
+ final Entity entity = data.readAll(edmEntitySet).getEntities().get(4);
+ final ExpandOption expand = ExpandSelectMock.mockExpandOption(Collections.singletonList(
+ ExpandSelectMock.mockExpandItem(edmEntitySet, "NavPropertyETAllPrimOne")));
+ List<Entity> addedEntity = new ArrayList<Entity>();
+ addedEntity.add(entity);
+ delta.getEntities().addAll(addedEntity);
+ InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
+ EntityCollectionSerializerOptions.with()
+ .contextURL(ContextURL.with().entitySet(edmEntitySet).build()).expand(expand)
+ .isFullRepresentation(true).build()).getContent();
+ String jsonString = IOUtils.toString(stream);
+ final String expectedResult = "{\"@context\":\"$metadata#ESDelta/$delta\","
+ + "\"value\":[{\"@id\":\"ESDelta(-1)\",\"PropertyInt16\":-1,"
+ + "\"PropertyString\":\"Number:-1\",\"NavPropertyETAllPrimOne\":null}]}";
+ Assert.assertNotNull(jsonString);
+ Assert.assertEquals(expectedResult, jsonString);
+ }
+
+ @Test
+ public void nullnavigationToManyInDeltaEntityInFullRepresentation() throws Exception {
+ final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESDelta");
+ Delta delta = new Delta();
+ final Entity entity = data.readAll(edmEntitySet).getEntities().get(4);
+ final ExpandOption expand = ExpandSelectMock.mockExpandOption(Collections.singletonList(
+ ExpandSelectMock.mockExpandItem(edmEntitySet, "NavPropertyETAllPrimMany")));
+ List<Entity> addedEntity = new ArrayList<Entity>();
+ addedEntity.add(entity);
+ delta.getEntities().addAll(addedEntity);
+ InputStream stream = ser.entityCollection(metadata, edmEntitySet.getEntityType(), delta ,
+ EntityCollectionSerializerOptions.with()
+ .contextURL(ContextURL.with().entitySet(edmEntitySet).build()).expand(expand)
+ .isFullRepresentation(true).build()).getContent();
+ String jsonString = IOUtils.toString(stream);
+ final String expectedResult = "{\"@context\":\"$metadata#ESDelta/$delta\","
+ + "\"value\":[{\"@id\":\"ESDelta(-1)\",\"PropertyInt16\":-1,"
+ + "\"PropertyString\":\"Number:-1\",\"NavPropertyETAllPrimMany\":[]}]}";
+ Assert.assertNotNull(jsonString);
+ Assert.assertEquals(expectedResult, jsonString);
+ }
}