Repository: olingo-odata4
Updated Branches:
  refs/heads/master 22a21a28e -> 44d6f5a17


[OLINGO-988] Prevent duplicate ExpandItems in ExpandTreeBuilder


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

Branch: refs/heads/master
Commit: 44d6f5a1714809d89162ec52a8f3846aa19419c2
Parents: 22a21a2
Author: Christian Amend <[email protected]>
Authored: Tue Jul 26 10:27:25 2016 +0200
Committer: Christian Amend <[email protected]>
Committed: Tue Jul 26 10:27:25 2016 +0200

----------------------------------------------------------------------
 .../deserializer/helper/ExpandTreeBuilder.java  |  4 +
 .../helper/ExpandTreeBuilderImpl.java           | 53 ++++++------
 .../json/ODataJsonDeserializer.java             | 91 +++++++++-----------
 .../json/ODataDeserializerDeepInsertTest.java   | 58 +++++++++++++
 .../json/ODataJsonDeserializerEntityTest.java   |  7 ++
 .../test/resources/UnbalancedESAllPrimFeed.json | 23 +++++
 .../resources/UnbalancedESAllPrimFeed2.json     | 24 ++++++
 7 files changed, 185 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/44d6f5a1/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java
index 882213c..afa8d70 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilder.java
@@ -19,13 +19,17 @@
 package org.apache.olingo.server.core.deserializer.helper;
 
 import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.core.uri.UriInfoImpl;
 import org.apache.olingo.server.core.uri.UriResourceNavigationPropertyImpl;
 import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl;
 
 public abstract class ExpandTreeBuilder {
+  
   public abstract ExpandTreeBuilder expand(EdmNavigationProperty 
edmNavigationProperty);
 
+  public abstract ExpandOption build();
+  
   protected ExpandItemImpl buildExpandItem(final EdmNavigationProperty 
edmNavigationProperty) {
     return new ExpandItemImpl()
         .setResourcePath(new UriInfoImpl()

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/44d6f5a1/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilderImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilderImpl.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilderImpl.java
index b0287ff..4232f98 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilderImpl.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/helper/ExpandTreeBuilderImpl.java
@@ -18,6 +18,9 @@
  */
 package org.apache.olingo.server.core.deserializer.helper;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl;
@@ -25,43 +28,41 @@ import 
org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
 
 public class ExpandTreeBuilderImpl extends ExpandTreeBuilder {
 
+  private final Map<String, ExpandTreeBuilder> childBuilderCache = new 
HashMap<String, ExpandTreeBuilder>();
+  private final ExpandItemImpl parentItem;
   private ExpandOptionImpl expandOption = null;
 
+  private ExpandTreeBuilderImpl(final ExpandItemImpl parentItem) {
+    this.parentItem = parentItem;
+  }
+  
+  
   @Override
   public ExpandTreeBuilder expand(final EdmNavigationProperty 
edmNavigationProperty) {
-    ExpandItemImpl expandItem = buildExpandItem(edmNavigationProperty);
-
     if (expandOption == null) {
       expandOption = new ExpandOptionImpl();
+      if(parentItem != null && parentItem.getExpandOption() == null){
+        parentItem.setSystemQueryOption(expandOption);
+      }
     }
-    expandOption.addExpandItem(expandItem);
-
-    return new ExpandTreeBuilderInner(expandItem);
+    
+    ExpandTreeBuilder builder = 
childBuilderCache.get(edmNavigationProperty.getName());
+    if(builder == null){
+      ExpandItemImpl expandItem = buildExpandItem(edmNavigationProperty);
+      expandOption.addExpandItem(expandItem);
+      builder = new ExpandTreeBuilderImpl(expandItem);
+      childBuilderCache.put(edmNavigationProperty.getName(), builder);
+    }
+    
+    return builder;
   }
 
+  @Override
   public ExpandOption build() {
     return expandOption;
   }
-
-  private class ExpandTreeBuilderInner extends ExpandTreeBuilder {
-    private ExpandItemImpl parent;
-
-    public ExpandTreeBuilderInner(final ExpandItemImpl expandItem) {
-      parent = expandItem;
-    }
-
-    @Override
-    public ExpandTreeBuilder expand(final EdmNavigationProperty 
edmNavigationProperty) {
-      if (parent.getExpandOption() == null) {
-        final ExpandOptionImpl expandOption = new ExpandOptionImpl();
-        parent.setSystemQueryOption(expandOption);
-      }
-
-      final ExpandItemImpl expandItem = buildExpandItem(edmNavigationProperty);
-      ((ExpandOptionImpl) parent.getExpandOption()).addExpandItem(expandItem);
-
-      return new ExpandTreeBuilderInner(expandItem);
-    }
-
+  
+  public static ExpandTreeBuilder create(){
+    return new ExpandTreeBuilderImpl(null);
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/44d6f5a1/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
index de1fa39..3398dc7 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
@@ -134,7 +134,7 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
           throw new DeserializerException("Nested Arrays and primitive values 
are not allowed for an entity value.",
               DeserializerException.MessageKeys.INVALID_ENTITY);
         }
-        EdmEntityType derivedEdmEntityType = 
(EdmEntityType)getDerivedType(edmEntityType, arrayElement);
+        EdmEntityType derivedEdmEntityType = (EdmEntityType) 
getDerivedType(edmEntityType, arrayElement);
         entities.add(consumeEntityNode(derivedEdmEntityType, (ObjectNode) 
arrayElement, expandBuilder));
       }
       return entities;
@@ -149,9 +149,9 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
       throws DeserializerException {
     try {
       final ObjectNode tree = parseJsonTree(stream);
-      final ExpandTreeBuilderImpl expandBuilder = new ExpandTreeBuilderImpl();
+      final ExpandTreeBuilder expandBuilder = ExpandTreeBuilderImpl.create();
 
-      EdmEntityType derivedEdmEntityType = 
(EdmEntityType)getDerivedType(edmEntityType, tree);
+      EdmEntityType derivedEdmEntityType = (EdmEntityType) 
getDerivedType(edmEntityType, tree);
 
       return 
DeserializerResultImpl.with().entity(consumeEntityNode(derivedEdmEntityType, 
tree, expandBuilder))
           .expandOption(expandBuilder.build())
@@ -279,8 +279,8 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
   public Parameter parameter(final String content, final EdmParameter 
parameter) throws DeserializerException {
     try {
       JsonParser parser = new JsonFactory(new ObjectMapper()
-      .configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true))
-      .createParser(content);
+          .configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, 
true))
+              .createParser(content);
       JsonNode node = parser.getCodec().readTree(parser);
       if (node == null) {
         throw new DeserializerException("Invalid JSON syntax.",
@@ -384,30 +384,29 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
       final EdmNavigationProperty edmNavigationProperty) throws 
DeserializerException {
     Link link = new Link();
     link.setTitle(navigationPropertyName);
-    final ExpandTreeBuilder childExpandBuilder = (expandBuilder != null) ?
-        expandBuilder.expand(edmNavigationProperty) : null;
-        EdmEntityType derivedEdmEntityType = (EdmEntityType)getDerivedType(
-            edmNavigationProperty.getType(), jsonNode);
-        if (jsonNode.isArray() && edmNavigationProperty.isCollection()) {
-          link.setType(Constants.ENTITY_SET_NAVIGATION_LINK_TYPE);
-          EntityCollection inlineEntitySet = new EntityCollection();
-          inlineEntitySet.getEntities().addAll(
-              consumeEntitySetArray(derivedEdmEntityType, jsonNode, 
childExpandBuilder));
-          link.setInlineEntitySet(inlineEntitySet);
-        } else if (!jsonNode.isArray() && (!jsonNode.isValueNode() || 
jsonNode.isNull())
-            && !edmNavigationProperty.isCollection()) {
-          link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
-          if (!jsonNode.isNull()) {
-            Entity inlineEntity = consumeEntityNode(derivedEdmEntityType, 
(ObjectNode) jsonNode,
-                childExpandBuilder);
-            link.setInlineEntity(inlineEntity);
-          }
-        } else {
-          throw new DeserializerException("Invalid value: " + 
jsonNode.getNodeType()
-              + " for expanded navigation property: " + navigationPropertyName,
-              MessageKeys.INVALID_VALUE_FOR_NAVIGATION_PROPERTY, 
navigationPropertyName);
-        }
-        return link;
+    final ExpandTreeBuilder childExpandBuilder = (expandBuilder != null) ? 
expandBuilder.expand(edmNavigationProperty)
+        : null;
+    EdmEntityType derivedEdmEntityType = (EdmEntityType) getDerivedType(
+        edmNavigationProperty.getType(), jsonNode);
+    if (jsonNode.isArray() && edmNavigationProperty.isCollection()) {
+      link.setType(Constants.ENTITY_SET_NAVIGATION_LINK_TYPE);
+      EntityCollection inlineEntitySet = new EntityCollection();
+      inlineEntitySet.getEntities().addAll(
+          consumeEntitySetArray(derivedEdmEntityType, jsonNode, 
childExpandBuilder));
+      link.setInlineEntitySet(inlineEntitySet);
+    } else if (!jsonNode.isArray() && (!jsonNode.isValueNode() || 
jsonNode.isNull())
+        && !edmNavigationProperty.isCollection()) {
+      link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
+      if (!jsonNode.isNull()) {
+        Entity inlineEntity = consumeEntityNode(derivedEdmEntityType, 
(ObjectNode) jsonNode, childExpandBuilder);
+        link.setInlineEntity(inlineEntity);
+      }
+    } else {
+      throw new DeserializerException("Invalid value: " + 
jsonNode.getNodeType()
+          + " for expanded navigation property: " + navigationPropertyName,
+          MessageKeys.INVALID_VALUE_FOR_NAVIGATION_PROPERTY, 
navigationPropertyName);
+    }
+    return link;
   }
 
   private Link consumeBindingLink(final String key, final JsonNode jsonNode, 
final EdmEntityType edmEntityType)
@@ -477,7 +476,7 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
   private void consumePropertySingleNode(final String name, final EdmType type,
       final boolean isNullable, final Integer maxLength, final Integer 
precision, final Integer scale,
       final boolean isUnicode, final EdmMapping mapping, final JsonNode 
jsonNode, final Property property)
-          throws DeserializerException {
+      throws DeserializerException {
     switch (type.getKind()) {
     case PRIMITIVE:
     case DEFINITION:
@@ -504,7 +503,7 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
 
   private Object readComplexNode(final String name, final EdmType type, final 
boolean isNullable,
       final JsonNode jsonNode)
-          throws DeserializerException {
+      throws DeserializerException {
     // read and add all complex properties
     ComplexValue value = readComplexValue(name, type, isNullable, jsonNode);
 
@@ -520,7 +519,7 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
   private void consumePropertyCollectionNode(final String name, final EdmType 
type,
       final boolean isNullable, final Integer maxLength, final Integer 
precision, final Integer scale,
       final boolean isUnicode, final EdmMapping mapping, final JsonNode 
jsonNode, final Property property)
-          throws DeserializerException {
+      throws DeserializerException {
     if (!jsonNode.isArray()) {
       throw new DeserializerException("Value for property: " + name + " must 
be an array but is not.",
           DeserializerException.MessageKeys.INVALID_JSON_TYPE_FOR_PROPERTY, 
name);
@@ -537,10 +536,8 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
             isNullable, maxLength, precision, scale, isUnicode, mapping, 
arrayElement);
         valueArray.add(value);
       }
-      property.setValue(type.getKind() == EdmTypeKind.ENUM ?
-          ValueType.COLLECTION_ENUM :
-          ValueType.COLLECTION_PRIMITIVE,
-            valueArray);
+      property.setValue(type.getKind() == EdmTypeKind.ENUM ? 
ValueType.COLLECTION_ENUM : ValueType.COLLECTION_PRIMITIVE,
+          valueArray);
       break;
     case COMPLEX:
       while (iterator.hasNext()) {
@@ -631,14 +628,10 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
    */
   private Class<?> getJavaClassForPrimitiveType(final EdmMapping mapping, 
final EdmPrimitiveType type) {
     final EdmPrimitiveType edmPrimitiveType =
-        type.getKind() == EdmTypeKind.ENUM ?
-            ((EdmEnumType) type).getUnderlyingType() :
-            type.getKind() == EdmTypeKind.DEFINITION ?
-                ((EdmTypeDefinition) type).getUnderlyingType() :
-                type;
-                  return mapping == null || mapping.getMappedJavaClass() == 
null ?
-                      edmPrimitiveType.getDefaultType() :
-                        mapping.getMappedJavaClass();
+        type.getKind() == EdmTypeKind.ENUM ? ((EdmEnumType) 
type).getUnderlyingType() : type
+            .getKind() == EdmTypeKind.DEFINITION ? ((EdmTypeDefinition) 
type).getUnderlyingType() : type;
+    return mapping == null || mapping.getMappedJavaClass() == null ? 
edmPrimitiveType.getDefaultType() : mapping
+        .getMappedJavaClass();
   }
 
   /**
@@ -831,7 +824,7 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
       String odataType = odataTypeNode.asText();
       if (!odataType.isEmpty()) {
         odataType = odataType.substring(1);
-        
+
         if 
(odataType.equalsIgnoreCase(edmType.getFullQualifiedName().getFullQualifiedNameAsString()))
 {
           return edmType;
         } else if (this.serviceMetadata == null) {
@@ -839,14 +832,14 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
               "Failed to resolve Odata type " + odataType + " due to metadata 
is not available",
               DeserializerException.MessageKeys.UNKNOWN_CONTENT);
         }
-        
+
         EdmStructuredType currentEdmType = null;
-        if(edmType instanceof EdmEntityType) {
+        if (edmType instanceof EdmEntityType) {
           currentEdmType = serviceMetadata.getEdm()
-              .getEntityType(new FullQualifiedName(odataType));          
+              .getEntityType(new FullQualifiedName(odataType));
         } else {
           currentEdmType = serviceMetadata.getEdm()
-              .getComplexType(new FullQualifiedName(odataType));          
+              .getComplexType(new FullQualifiedName(odataType));
         }
         if (!isAssignable(edmType, currentEdmType)) {
           throw new DeserializerException(

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/44d6f5a1/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerDeepInsertTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerDeepInsertTest.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerDeepInsertTest.java
index 8b87a12..e684c0f 100644
--- 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerDeepInsertTest.java
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerDeepInsertTest.java
@@ -30,12 +30,64 @@ import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.Link;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.deserializer.DeserializerResult;
+import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import 
org.apache.olingo.server.core.deserializer.AbstractODataDeserializerTest;
 import org.junit.Test;
 
 public class ODataDeserializerDeepInsertTest extends 
AbstractODataDeserializerTest {
 
   @Test
+  public void unbalancedESAllPrim() throws Exception {
+    final DeserializerResult result = 
deserializeWithResult("UnbalancedESAllPrimFeed.json");
+    ExpandOption root = result.getExpandTree();
+    assertEquals(1, root.getExpandItems().size());
+
+    ExpandItem etTwoPrimManyLevel = root.getExpandItems().get(0);
+    assertEquals("NavPropertyETTwoPrimMany", 
etTwoPrimManyLevel.getResourcePath().getUriResourceParts().get(0)
+        .getSegmentValue());
+    assertEquals(1, 
etTwoPrimManyLevel.getExpandOption().getExpandItems().size());
+
+    ExpandItem etAllPrimOneLevel = 
etTwoPrimManyLevel.getExpandOption().getExpandItems().get(0);
+    assertEquals("NavPropertyETAllPrimOne", 
etAllPrimOneLevel.getResourcePath().getUriResourceParts().get(0)
+        .getSegmentValue());
+    assertEquals(1, 
etAllPrimOneLevel.getExpandOption().getExpandItems().size());
+
+    ExpandItem etTwoPrimOneLevel = 
etAllPrimOneLevel.getExpandOption().getExpandItems().get(0);
+    assertEquals("NavPropertyETTwoPrimOne", 
etTwoPrimOneLevel.getResourcePath().getUriResourceParts().get(0)
+        .getSegmentValue());
+    assertNull(etTwoPrimOneLevel.getExpandOption());
+  }
+
+  @Test
+  public void unbalancedESAllPrim2() throws Exception {
+    final DeserializerResult result = 
deserializeWithResult("UnbalancedESAllPrimFeed2.json");
+    ExpandOption root = result.getExpandTree();
+    assertEquals(1, root.getExpandItems().size());
+
+    ExpandItem etTwoPrimManyLevel = root.getExpandItems().get(0);
+    assertEquals("NavPropertyETTwoPrimMany", 
etTwoPrimManyLevel.getResourcePath().getUriResourceParts().get(0)
+        .getSegmentValue());
+    assertEquals(1, 
etTwoPrimManyLevel.getExpandOption().getExpandItems().size());
+
+    ExpandItem etAllPrimOneLevel = 
etTwoPrimManyLevel.getExpandOption().getExpandItems().get(0);
+    assertEquals("NavPropertyETAllPrimOne", 
etAllPrimOneLevel.getResourcePath().getUriResourceParts().get(0)
+        .getSegmentValue());
+    assertEquals(2, 
etAllPrimOneLevel.getExpandOption().getExpandItems().size());
+
+    ExpandItem etTwoPrimOneLevel = 
etAllPrimOneLevel.getExpandOption().getExpandItems().get(0);
+    assertEquals("NavPropertyETTwoPrimMany", 
etTwoPrimOneLevel.getResourcePath().getUriResourceParts().get(0)
+        .getSegmentValue());
+    assertNull(etTwoPrimOneLevel.getExpandOption());
+
+    etTwoPrimOneLevel = 
etAllPrimOneLevel.getExpandOption().getExpandItems().get(1);
+    assertEquals("NavPropertyETTwoPrimOne", 
etTwoPrimOneLevel.getResourcePath().getUriResourceParts().get(0)
+        .getSegmentValue());
+    assertNull(etTwoPrimOneLevel.getExpandOption());
+  }
+
+  @Test
   public void esAllPrimExpandedToOne() throws Exception {
     final Entity entity = 
deserialize("EntityESAllPrimExpandedNavPropertyETTwoPrimOne.json");
 
@@ -152,4 +204,10 @@ public class ODataDeserializerDeepInsertTest extends 
AbstractODataDeserializerTe
     return 
ODataJsonDeserializerEntityTest.deserialize(getFileAsStream(resourceName),
         "ETAllPrim", ContentType.JSON);
   }
+
+  private DeserializerResult deserializeWithResult(final String resourceName) 
throws IOException,
+      DeserializerException {
+    return 
ODataJsonDeserializerEntityTest.deserializeWithResult(getFileAsStream(resourceName),
+        "ETAllPrim", ContentType.JSON);
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/44d6f5a1/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
index 02453e6..6b46ffd 100644
--- 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
@@ -49,6 +49,7 @@ import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.deserializer.DeserializerResult;
 import org.apache.olingo.server.api.deserializer.ODataDeserializer;
 import 
org.apache.olingo.server.core.deserializer.AbstractODataDeserializerTest;
 import org.junit.Assert;
@@ -1347,6 +1348,12 @@ public class ODataJsonDeserializerEntityTest extends 
AbstractODataDeserializerTe
         .entity(stream, edm.getEntityType(new FullQualifiedName(NAMESPACE, 
entityTypeName)))
         .getEntity();
   }
+  
+  protected static DeserializerResult deserializeWithResult(final InputStream 
stream, final String entityTypeName,
+      final ContentType contentType) throws DeserializerException {
+    return OData.newInstance().createDeserializer(contentType, metadata)
+        .entity(stream, edm.getEntityType(new FullQualifiedName(NAMESPACE, 
entityTypeName)));
+  }
 
   private static Entity deserialize(final String entityString, final String 
entityTypeName,
       final ContentType contentType) throws DeserializerException {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/44d6f5a1/lib/server-test/src/test/resources/UnbalancedESAllPrimFeed.json
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/resources/UnbalancedESAllPrimFeed.json 
b/lib/server-test/src/test/resources/UnbalancedESAllPrimFeed.json
new file mode 100644
index 0000000..d3fa550
--- /dev/null
+++ b/lib/server-test/src/test/resources/UnbalancedESAllPrimFeed.json
@@ -0,0 +1,23 @@
+{
+  "@odata.context": "$metadata#ESAllPrim\/$entity",
+  "@odata.metadataEtag": "W\/\"4efd6576-89c0-487c-8d6c-584e2acbae16\"",
+  "PropertyInt16": 1,
+  "NavPropertyETTwoPrimMany": [
+    {
+      "PropertyInt16": 2,
+      "NavPropertyETAllPrimOne": {
+        "PropertyInt16": 3
+      }
+    },
+    {
+      "PropertyInt16": 2,
+      "NavPropertyETAllPrimOne": {
+        "PropertyInt16": 3,
+        "NavPropertyETTwoPrimOne": {
+          "PropertyInt16": 32766,
+          "PropertyString": "Innermost Entry"
+        }
+      }
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/44d6f5a1/lib/server-test/src/test/resources/UnbalancedESAllPrimFeed2.json
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/resources/UnbalancedESAllPrimFeed2.json 
b/lib/server-test/src/test/resources/UnbalancedESAllPrimFeed2.json
new file mode 100644
index 0000000..678fd3a
--- /dev/null
+++ b/lib/server-test/src/test/resources/UnbalancedESAllPrimFeed2.json
@@ -0,0 +1,24 @@
+{
+  "@odata.context": "$metadata#ESAllPrim\/$entity",
+  "@odata.metadataEtag": "W\/\"4efd6576-89c0-487c-8d6c-584e2acbae16\"",
+  "PropertyInt16": 1,
+  "NavPropertyETTwoPrimMany": [
+    {
+      "PropertyInt16": 2,
+      "NavPropertyETAllPrimOne": {
+          "PropertyInt16": 3,
+          "NavPropertyETTwoPrimMany": []
+        } 
+    },
+    {
+      "PropertyInt16": 2,
+      "NavPropertyETAllPrimOne": {
+          "PropertyInt16": 3,
+          "NavPropertyETTwoPrimOne": {
+            "PropertyInt16": 32766,
+            "PropertyString": "Innermost Entry"
+            }           
+        }      
+    }
+  ]
+}
\ No newline at end of file

Reply via email to