Repository: olingo-odata4
Updated Branches:
  refs/heads/master b1db030cb -> 038a4821a


OLINGO-1009 Changing serialization to allow for $levels

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

Branch: refs/heads/master
Commit: 68969d547da67939bca5a57b3b1dd158e452560c
Parents: b1db030
Author: shawkins <[email protected]>
Authored: Wed Sep 7 09:39:25 2016 -0400
Committer: shawkins <[email protected]>
Committed: Wed Sep 7 09:39:25 2016 -0400

----------------------------------------------------------------------
 .../serializer/json/ODataJsonSerializer.java    |  86 ++++++++++----
 .../serializer/utils/ExpandSelectHelper.java    |  14 ++-
 .../core/serializer/xml/ODataXmlSerializer.java | 116 +++++++++++++------
 .../json/ODataJsonSerializerTest.java           |  48 ++++++++
 4 files changed, 201 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/68969d54/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
index 8c60373..513df38 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
@@ -64,6 +64,7 @@ import org.apache.olingo.server.api.uri.UriHelper;
 import org.apache.olingo.server.api.uri.queryoption.CountOption;
 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.LevelsExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.core.ODataWritableContent;
 import org.apache.olingo.server.core.serializer.AbstractODataSerializer;
@@ -73,6 +74,7 @@ import 
org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
 import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
 import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper;
 import org.apache.olingo.server.core.uri.UriHelperImpl;
+import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
 
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonGenerator;
@@ -164,10 +166,10 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
       writeOperations(entitySet.getOperations(), json);
       json.writeFieldName(Constants.VALUE);
       if (options == null) {
-        writeEntitySet(metadata, entityType, entitySet, null, null, false, 
json);
+        writeEntitySet(metadata, entityType, entitySet, null, null, null, 
false, json);
       } else {
         writeEntitySet(metadata, entityType, entitySet,
-            options.getExpand(), options.getSelect(), 
options.getWriteOnlyReferences(), json);
+            options.getExpand(), null, options.getSelect(), 
options.getWriteOnlyReferences(), json);
       }
       writeNextLink(entitySet, json);
 
@@ -210,10 +212,10 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
       }
       json.writeFieldName(Constants.VALUE);
       if (options == null) {
-        writeEntitySet(metadata, entityType, entitySet, null, null, false, 
json);
+        writeEntitySet(metadata, entityType, entitySet, null, null, null, 
false, json);
       } else {
         writeEntitySet(metadata, entityType, entitySet,
-            options.getExpand(), options.getSelect(), 
options.getWriteOnlyReferences(), json);
+            options.getExpand(), null, options.getSelect(), 
options.getWriteOnlyReferences(), json);
       }
       // next link not supported by default for streaming results
 //      writeNextLink(entitySet, json);
@@ -238,6 +240,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
       JsonGenerator json = new JsonFactory().createGenerator(outputStream);
       writeEntity(metadata, entityType, entity, contextURL,
           options == null ? null : options.getExpand(),
+          null,
           options == null ? null : options.getSelect(),
           options == null ? false : options.getWriteOnlyReferences(),
           json);
@@ -264,7 +267,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
   }
 
   protected void writeEntitySet(final ServiceMetadata metadata, final 
EdmEntityType entityType,
-      final AbstractEntityCollection entitySet, final ExpandOption expand, 
final SelectOption select,
+      final AbstractEntityCollection entitySet, final ExpandOption expand, 
Integer toDepth, final SelectOption select,
       final boolean onlyReference, final JsonGenerator json) throws 
IOException,
       SerializerException {
     json.writeStartArray();
@@ -274,7 +277,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
         json.writeStringField(Constants.JSON_ID, getEntityId(entity));
         json.writeEndObject();
       } else {
-        writeEntity(metadata, entityType, entity, null, expand, select, false, 
json);
+        writeEntity(metadata, entityType, entity, null, expand, toDepth, 
select, false, json);
       }
     }
     json.writeEndArray();
@@ -308,8 +311,8 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
   }
 
   public void writeEntity(final ServiceMetadata metadata, final EdmEntityType 
entityType, final Entity entity,
-      final ContextURL contextURL, final ExpandOption expand, final 
SelectOption select, final boolean onlyReference,
-      final JsonGenerator json)
+      final ContextURL contextURL, final ExpandOption expand, Integer toDepth, 
+      final SelectOption select, final boolean onlyReference, final 
JsonGenerator json)
       throws IOException, SerializerException {
     json.writeStartObject();
     if (!isODataMetadataNone) {
@@ -357,7 +360,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
       }
       
       writeProperties(metadata, resolvedType, entity.getProperties(), select, 
json);
-      writeNavigationProperties(metadata, resolvedType, entity, expand, json);
+      writeNavigationProperties(metadata, resolvedType, entity, expand, 
toDepth, json);
       writeOperations(entity.getOperations(), json);
       json.writeEndObject();
     }
@@ -442,24 +445,57 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
   }
 
   protected void writeNavigationProperties(final ServiceMetadata metadata,
-      final EdmStructuredType type, final Linked linked, final ExpandOption 
expand,
+      final EdmStructuredType type, final Linked linked, final ExpandOption 
expand, final Integer toDepth,
       final JsonGenerator json) throws SerializerException, IOException {
-    if (ExpandSelectHelper.hasExpand(expand)) {
-      final boolean expandAll = ExpandSelectHelper.isExpandAll(expand);
-      final Set<String> expanded = expandAll ? new HashSet<String>() :
-          ExpandSelectHelper.getExpandedPropertyNames(expand.getExpandItems());
+    if ((toDepth != null && toDepth > 1) || (toDepth == null && 
ExpandSelectHelper.hasExpand(expand))) {
+      final ExpandItem expandAll = ExpandSelectHelper.getExpandAll(expand);
       for (final String propertyName : type.getNavigationPropertyNames()) {
-        if (expandAll || expanded.contains(propertyName)) {
+        final ExpandItem innerOptions = 
ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
+        if (toDepth != null) {
           final EdmNavigationProperty property = 
type.getNavigationProperty(propertyName);
           final Link navigationLink = 
linked.getNavigationLink(property.getName());
-          final ExpandItem innerOptions = expandAll ? null :
-              ExpandSelectHelper.getExpandItem(expand.getExpandItems(), 
propertyName);
-          if (innerOptions != null && innerOptions.getLevelsOption() != null) {
-            throw new SerializerException("Expand option $levels is not 
supported.",
-                SerializerException.MessageKeys.NOT_IMPLEMENTED);
+          writeExpandedNavigationProperty(metadata, property, navigationLink,
+                expand, toDepth-1,
+                innerOptions == null ? null : innerOptions.getSelectOption(),
+                innerOptions == null ? null : innerOptions.getCountOption(),
+                innerOptions == null ? false : innerOptions.hasCountPath(),
+                innerOptions == null ? false : innerOptions.isRef(),
+                json);
+          continue;
+        }
+        Integer levels = null;
+        if (expandAll != null || innerOptions != null) {
+          final EdmNavigationProperty property = 
type.getNavigationProperty(propertyName);
+          final Link navigationLink = 
linked.getNavigationLink(property.getName());
+          ExpandOption childExpand = null;
+          LevelsExpandOption levelsOption = null;
+          if (innerOptions != null) {
+            levelsOption = innerOptions.getLevelsOption();
+            if (levelsOption == null) {
+              childExpand = innerOptions.getExpandOption();
+            } else {
+              ExpandOptionImpl expandOptionImpl = new ExpandOptionImpl();
+              expandOptionImpl.addExpandItem(innerOptions);
+              childExpand = expandOptionImpl;
+            }
+          } else if (expandAll != null) {
+            levels = 1;
+            levelsOption = expandAll.getLevelsOption();
+            ExpandOptionImpl expandOptionImpl = new ExpandOptionImpl();
+            expandOptionImpl.addExpandItem(expandAll);
+            childExpand = expandOptionImpl;
+          }
+
+          if (levelsOption != null) {
+            if (levelsOption.isMax()) {
+              levels = Integer.MAX_VALUE;
+            } else {
+              levels = levelsOption.getValue();
+            }
           }
+          
           writeExpandedNavigationProperty(metadata, property, navigationLink,
-              innerOptions == null ? null : innerOptions.getExpandOption(),
+              childExpand, levels,
               innerOptions == null ? null : innerOptions.getSelectOption(),
               innerOptions == null ? null : innerOptions.getCountOption(),
               innerOptions == null ? false : innerOptions.hasCountPath(),
@@ -484,7 +520,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
   protected void writeExpandedNavigationProperty(
       final ServiceMetadata metadata, final EdmNavigationProperty property,
       final Link navigationLink, final ExpandOption innerExpand,
-      final SelectOption innerSelect, final CountOption innerCount,
+      Integer toDepth, final SelectOption innerSelect, final CountOption 
innerCount,
       final boolean writeOnlyCount, final boolean writeOnlyRef,
       final JsonGenerator json) throws IOException, SerializerException {
 
@@ -508,7 +544,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
             writeInlineCount(property.getName(), 
navigationLink.getInlineEntitySet().getCount(), json);
           }
           json.writeFieldName(property.getName());
-          writeEntitySet(metadata, property.getType(), 
navigationLink.getInlineEntitySet(), innerExpand,
+          writeEntitySet(metadata, property.getType(), 
navigationLink.getInlineEntitySet(), innerExpand, toDepth,
               innerSelect, writeOnlyRef, json);
         }
       }
@@ -518,7 +554,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
         json.writeNull();
       } else {
         writeEntity(metadata, property.getType(), 
navigationLink.getInlineEntity(), null,
-            innerExpand, innerSelect, writeOnlyRef, json);
+            innerExpand, toDepth, innerSelect, writeOnlyRef, json);
       }
     }
   }
@@ -847,7 +883,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
       writeProperties(metadata, type, values, options == null ? null : 
options.getSelect(), json);
       if (!property.isNull() && property.isComplex()) {
         writeNavigationProperties(metadata, type, property.asComplex(),
-            options == null ? null : options.getExpand(), json);
+            options == null ? null : options.getExpand(), null, json);
       }
       json.writeEndObject();
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/68969d54/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
index 13e158f..4424b61 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
@@ -121,7 +121,16 @@ public abstract class ExpandSelectHelper {
     }
     return false;
   }
-
+  
+  public static ExpandItem getExpandAll(final ExpandOption expand) {
+      for (final ExpandItem item : expand.getExpandItems()) {
+        if (item.isStar()) {
+          return item;
+        }
+      }
+      return null;
+    }
+  
   public static Set<String> getExpandedPropertyNames(final List<ExpandItem> 
expandItems)
       throws SerializerException {
     Set<String> expanded = new HashSet<String>();
@@ -137,6 +146,9 @@ public abstract class ExpandSelectHelper {
 
   public static ExpandItem getExpandItem(final List<ExpandItem> expandItems, 
final String propertyName) {
     for (final ExpandItem item : expandItems) {
+      if (item.isStar()) {
+          continue;
+      }
       final UriResource resource = 
item.getResourcePath().getUriResourceParts().get(0);
       if (resource instanceof UriResourceNavigation
           && propertyName.equals(((UriResourceNavigation) 
resource).getProperty().getName())) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/68969d54/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
index 47489c9..d6de50f 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
@@ -70,6 +70,7 @@ import 
org.apache.olingo.server.api.serializer.SerializerStreamResult;
 import org.apache.olingo.server.api.uri.queryoption.CountOption;
 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.LevelsExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.core.ODataWritableContent;
 import org.apache.olingo.server.core.serializer.AbstractODataSerializer;
@@ -77,6 +78,7 @@ import 
org.apache.olingo.server.core.serializer.SerializerResultImpl;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
 import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
 import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper;
+import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
 
 public class ODataXmlSerializer extends AbstractODataSerializer {
 
@@ -257,10 +259,11 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
 
       boolean writeOnlyRef = (options != null && 
options.getWriteOnlyReferences());
       if (options == null) {
-        writeEntitySet(metadata, entityType, entitySet, null, null, null, 
writer, writeOnlyRef);
+        writeEntitySet(metadata, entityType, entitySet, null, null, null, 
null, writer, writeOnlyRef);
       } else {
         writeEntitySet(metadata, entityType, entitySet,
-            options.getExpand(), options.getSelect(), 
options.xml10InvalidCharReplacement(), writer, writeOnlyRef);
+            options.getExpand(), null, 
+            options.getSelect(), options.xml10InvalidCharReplacement(), 
writer, writeOnlyRef);
       }
 
       writer.writeEndElement();
@@ -314,10 +317,11 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
 
       boolean writeOnlyRef = (options != null && 
options.getWriteOnlyReferences());
       if (options == null) {
-        writeEntitySet(metadata, entityType, entitySet, null, null, null, 
writer, writeOnlyRef);
+        writeEntitySet(metadata, entityType, entitySet, null, null, null, 
null, writer, writeOnlyRef);
       } else {
         writeEntitySet(metadata, entityType, entitySet,
-            options.getExpand(), options.getSelect(), 
options.xml10InvalidCharReplacement(), writer, writeOnlyRef);
+            options.getExpand(), null, 
+            options.getSelect(), options.xml10InvalidCharReplacement(), 
writer, writeOnlyRef);
       }
 
       writer.writeEndElement();
@@ -356,6 +360,7 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
       writer.writeStartDocument(DEFAULT_CHARSET, "1.0");
       writeEntity(metadata, entityType, entity, contextURL,
           options == null ? null : options.getExpand(),
+          null,
           options == null ? null : options.getSelect(),
           options == null ? null : options.xml10InvalidCharReplacement(),
           writer, true, false);
@@ -397,17 +402,18 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
   }
 
   protected void writeEntitySet(final ServiceMetadata metadata, final 
EdmEntityType entityType,
-      final AbstractEntityCollection entitySet, final ExpandOption expand, 
final SelectOption select,
+      final AbstractEntityCollection entitySet, final ExpandOption expand, 
+      final Integer toDepth, final SelectOption select,
       final String xml10InvalidCharReplacement,final XMLStreamWriter writer, 
final boolean writeOnlyRef) 
           throws XMLStreamException, SerializerException {
     for (final Entity entity : entitySet) {
-      writeEntity(metadata, entityType, entity, null, expand, select, 
+      writeEntity(metadata, entityType, entity, null, expand, toDepth, select, 
           xml10InvalidCharReplacement, writer, false, writeOnlyRef);
     }
   }
 
   protected void writeEntity(final ServiceMetadata metadata, final 
EdmEntityType entityType,
-      final Entity entity, final ContextURL contextURL, final ExpandOption 
expand,
+      final Entity entity, final ContextURL contextURL, final ExpandOption 
expand, final Integer toDepth,
       final SelectOption select, final String xml10InvalidCharReplacement,
       final XMLStreamWriter writer, final boolean top, final boolean 
writeOnlyRef)
       throws XMLStreamException, SerializerException {
@@ -466,7 +472,7 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
     }
 
     EdmEntityType resolvedType = resolveEntityType(metadata, entityType, 
entity.getType());
-    writeNavigationProperties(metadata, resolvedType, entity, expand, 
xml10InvalidCharReplacement, writer);
+    writeNavigationProperties(metadata, resolvedType, entity, expand, toDepth, 
xml10InvalidCharReplacement, writer);
 
     writer.writeStartElement(ATOM, Constants.ATOM_ELEM_CATEGORY, NS_ATOM);
     writer.writeAttribute(Constants.ATOM_ATTR_SCHEME, Constants.NS_SCHEME);
@@ -591,36 +597,71 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
   }
 
   protected void writeNavigationProperties(final ServiceMetadata metadata,
-      final EdmStructuredType type, final Linked linked, final ExpandOption 
expand,
+      final EdmStructuredType type, final Linked linked, final ExpandOption 
expand, final Integer toDepth,
       final String xml10InvalidCharReplacement, final XMLStreamWriter writer) 
           throws SerializerException, XMLStreamException {
-    if (ExpandSelectHelper.hasExpand(expand)) {
-      final boolean expandAll = ExpandSelectHelper.isExpandAll(expand);
-      final Set<String> expanded = expandAll ? new HashSet<String>() :
-          ExpandSelectHelper.getExpandedPropertyNames(expand.getExpandItems());
+    if ((toDepth != null && toDepth > 1) || (toDepth == null && 
ExpandSelectHelper.hasExpand(expand))) {
+      final ExpandItem expandAll = ExpandSelectHelper.getExpandAll(expand);
       for (final String propertyName : type.getNavigationPropertyNames()) {
-        final EdmNavigationProperty property = 
type.getNavigationProperty(propertyName);
-        final Link navigationLink = getOrCreateLink(linked, propertyName);
-        if (expandAll || expanded.contains(propertyName)) {
-          final ExpandItem innerOptions = expandAll ? null :
-              ExpandSelectHelper.getExpandItem(expand.getExpandItems(), 
propertyName);
-          if (innerOptions != null && innerOptions.getLevelsOption() != null) {
-            throw new SerializerException("Expand option $levels is not 
supported.",
-                SerializerException.MessageKeys.NOT_IMPLEMENTED);
-          }
-          if (navigationLink != null) {
-            writeLink(writer, navigationLink, false);
-            writer.writeStartElement(METADATA, Constants.ATOM_ELEM_INLINE, 
NS_METADATA);
-            writeExpandedNavigationProperty(metadata, property, navigationLink,
-                innerOptions == null ? null : innerOptions.getExpandOption(),
-                innerOptions == null ? null : innerOptions.getSelectOption(),
-                innerOptions == null ? null : innerOptions.getCountOption(),
-                innerOptions == null ? false : innerOptions.hasCountPath(),
-                innerOptions == null ? false : innerOptions.isRef(),           
                         
-                xml10InvalidCharReplacement, writer);
-            writer.writeEndElement();
-            writer.writeEndElement();
+        final ExpandItem innerOptions = 
ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
+        if (toDepth != null) {
+          final EdmNavigationProperty property = 
type.getNavigationProperty(propertyName);
+          final Link navigationLink = getOrCreateLink(linked, propertyName);
+          writeLink(writer, navigationLink, false);
+          writer.writeStartElement(METADATA, Constants.ATOM_ELEM_INLINE, 
NS_METADATA);
+          writeExpandedNavigationProperty(metadata, property, navigationLink,
+              expand, toDepth - 1,
+              innerOptions == null ? null : innerOptions.getSelectOption(),
+              innerOptions == null ? null : innerOptions.getCountOption(),
+              innerOptions == null ? false : innerOptions.hasCountPath(),
+              innerOptions == null ? false : innerOptions.isRef(),             
                       
+              xml10InvalidCharReplacement, writer);
+          writer.writeEndElement();
+          writer.writeEndElement();
+          continue;
+        }
+        Integer levels = null;
+        if (expandAll != null || innerOptions != null) {
+          final EdmNavigationProperty property = 
type.getNavigationProperty(propertyName);
+          final Link navigationLink = getOrCreateLink(linked, propertyName);
+          ExpandOption childExpand = null;
+          LevelsExpandOption levelsOption = null;
+          if (innerOptions != null) {
+            levelsOption = innerOptions.getLevelsOption();
+            if (levelsOption == null) {
+              childExpand = innerOptions.getExpandOption();
+            } else {
+              ExpandOptionImpl expandOptionImpl = new ExpandOptionImpl();
+              expandOptionImpl.addExpandItem(innerOptions);
+              childExpand = expandOptionImpl;
+            }
+          } else if (expandAll != null) {
+            levels = 1;
+            levelsOption = expandAll.getLevelsOption();
+            ExpandOptionImpl expandOptionImpl = new ExpandOptionImpl();
+            expandOptionImpl.addExpandItem(expandAll);
+            childExpand = expandOptionImpl;
+          }  
+
+          if (levelsOption != null) {
+            if (levelsOption.isMax()) {
+              levels = Integer.MAX_VALUE;
+            } else {
+              levels = levelsOption.getValue();
+            }
           }
+          
+          writeLink(writer, navigationLink, false);
+          writer.writeStartElement(METADATA, Constants.ATOM_ELEM_INLINE, 
NS_METADATA);
+          writeExpandedNavigationProperty(metadata, property, navigationLink,
+              childExpand, levels,
+              innerOptions == null ? null : innerOptions.getSelectOption(),
+              innerOptions == null ? null : innerOptions.getCountOption(),
+              innerOptions == null ? false : innerOptions.hasCountPath(),
+              innerOptions == null ? false : innerOptions.isRef(),             
                       
+              xml10InvalidCharReplacement, writer);
+          writer.writeEndElement();
+          writer.writeEndElement();
         } else {
           writeLink(writer, getOrCreateLink(linked, propertyName));
         }
@@ -676,7 +717,8 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
 
   protected void writeExpandedNavigationProperty(final ServiceMetadata 
metadata,
       final EdmNavigationProperty property, final Link navigationLink,
-      final ExpandOption innerExpand, final SelectOption innerSelect, final 
CountOption coutOption, 
+      final ExpandOption innerExpand, final Integer toDepth, 
+      final SelectOption innerSelect, final CountOption coutOption, 
       final boolean writeNavigationCount, final boolean writeOnlyRef,final 
String xml10InvalidCharReplacement,
       final XMLStreamWriter writer) throws XMLStreamException, 
SerializerException {
     if (property.isCollection()) {
@@ -688,7 +730,7 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
           if (coutOption != null && coutOption.getValue()) {
             writeCount(navigationLink.getInlineEntitySet(), writer);
           }
-          writeEntitySet(metadata, property.getType(), 
navigationLink.getInlineEntitySet(), innerExpand,
+          writeEntitySet(metadata, property.getType(), 
navigationLink.getInlineEntitySet(), innerExpand, toDepth,
               innerSelect, xml10InvalidCharReplacement, writer, writeOnlyRef);
         }
         writer.writeEndElement();
@@ -696,7 +738,7 @@ public class ODataXmlSerializer extends 
AbstractODataSerializer {
     } else {
       if (navigationLink != null && navigationLink.getInlineEntity() != null) {
         writeEntity(metadata, property.getType(), 
navigationLink.getInlineEntity(), null,
-            innerExpand, innerSelect, xml10InvalidCharReplacement, writer, 
false, writeOnlyRef);
+            innerExpand, toDepth, innerSelect, xml10InvalidCharReplacement, 
writer, false, writeOnlyRef);
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/68969d54/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
index 2e86298..efd0713 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
@@ -65,6 +65,7 @@ import org.apache.olingo.server.api.uri.UriHelper;
 import org.apache.olingo.server.api.uri.queryoption.CountOption;
 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.LevelsExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectItem;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.core.serializer.ExpandSelectMock;
@@ -1356,6 +1357,53 @@ public class ODataJsonSerializerTest {
         + "{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"}]}]}",
         resultString);
   }
+  
+  @Test
+  public void expandStarTwoLevels() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESTwoPrim");
+    final EdmEntityType entityType = edmEntitySet.getEntityType();
+    final EdmEntitySet innerEntitySet = 
entityContainer.getEntitySet("ESAllPrim");
+    final Entity entity = data.readAll(edmEntitySet).getEntities().get(1);
+    ExpandItem expandItem = Mockito.mock(ExpandItem.class);
+    Mockito.when(expandItem.isStar()).thenReturn(true);
+    LevelsExpandOption levels = Mockito.mock(LevelsExpandOption.class);
+    Mockito.when(levels.getValue()).thenReturn(2);
+    Mockito.when(expandItem.getLevelsOption()).thenReturn(levels);
+    final SelectOption select = 
ExpandSelectMock.mockSelectOption(Collections.singletonList(
+        ExpandSelectMock.mockSelectItem(innerEntitySet, "PropertyInt32")));
+    final ExpandOption expand = 
ExpandSelectMock.mockExpandOption(Collections.singletonList(expandItem));
+    final String resultString = IOUtils.toString(serializer
+        .entity(metadata, entityType, entity,
+            EntitySerializerOptions.with()
+                .contextURL(ContextURL.with().entitySet(edmEntitySet)
+                    .selectList(helper.buildContextURLSelectList(entityType, 
expand, select))
+                    .suffix(Suffix.ENTITY).build())
+                .expand(expand)
+                .build()).getContent());
+    Assert.assertEquals("{\"@odata.context\":\"$metadata#ESTwoPrim/$entity\","
+            + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+            + "\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\","
+            + "\"NavPropertyETAllPrimOne\":null,"
+            + "\"NavPropertyETAllPrimMany\":["
+            + "{\"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\","
+            + 
"\"NavPropertyETTwoPrimOne\":null,\"NavPropertyETTwoPrimMany\":[]},"
+            + 
"{\"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\",\"NavPropertyETTwoPrimOne\":null,"
+            + "\"NavPropertyETTwoPrimMany\":["
+            + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"},"
+            + "{\"PropertyInt16\":-32766,\"PropertyString\":null},"
+            + "{\"PropertyInt16\":32767,\"PropertyString\":\"Test 
String4\"}]}]}",
+        resultString);
+  }
 
   @Test
   public void primitiveProperty() throws Exception {

Reply via email to