Repository: olingo-odata4
Updated Branches:
  refs/heads/OLINGO-422-SelectExpandSupport [created] 1976c3407


[OLINGO-422] Select for server serializer


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

Branch: refs/heads/OLINGO-422-SelectExpandSupport
Commit: 1976c3407d5b6d969a0c3eb8e779f0f4530931b3
Parents: dff439f
Author: Michael Bolz <[email protected]>
Authored: Mon Sep 8 06:34:14 2014 +0200
Committer: Michael Bolz <[email protected]>
Committed: Mon Sep 8 09:04:14 2014 +0200

----------------------------------------------------------------------
 .../server/api/serializer/ODataSerializer.java  |   5 +-
 .../core/serializer/ODataXmlSerializerImpl.java |   7 +-
 .../serializer/json/ODataJsonSerializer.java    | 130 +++++--
 .../olingo/server/tecsvc/data/DataProvider.java | 338 +++++++++++--------
 .../tecsvc/processor/TechnicalProcessor.java    |   4 +-
 .../server/tecsvc/data/DataProviderTest.java    |  13 +-
 .../json/ODataJsonSerializerTest.java           | 149 +++++++-
 7 files changed, 468 insertions(+), 178 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1976c340/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
----------------------------------------------------------------------
diff --git 
a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
 
b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
index 073dfd5..a0d44b9 100644
--- 
a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
+++ 
b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
@@ -26,6 +26,7 @@ import org.apache.olingo.commons.api.data.EntitySet;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.server.api.ODataServerError;
+import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
 
 public interface ODataSerializer {
 
@@ -35,10 +36,10 @@ public interface ODataSerializer {
 
   InputStream metadataDocument(Edm edm) throws ODataSerializerException;
 
-  InputStream entity(EdmEntitySet edmEntitySet, Entity entity, ContextURL 
contextURL)
+  InputStream entity(EdmEntitySet edmEntitySet, Entity entity, ContextURL 
contextURL, ExpandItem options)
       throws ODataSerializerException;
 
-  InputStream entitySet(EdmEntitySet edmEntitySet, EntitySet entitySet, 
ContextURL contextURL)
+  InputStream entitySet(EdmEntitySet edmEntitySet, EntitySet entitySet, 
ContextURL contextURL, ExpandItem options)
       throws ODataSerializerException;
 
   /**

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1976c340/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
index 5aed277..f3043c1 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
@@ -32,6 +32,7 @@ import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.ODataSerializerException;
+import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
 import 
org.apache.olingo.server.core.serializer.xml.MetadataDocumentXmlSerializer;
 import org.slf4j.Logger;
@@ -79,15 +80,15 @@ public class ODataXmlSerializerImpl implements 
ODataSerializer {
   }
 
   @Override
-  public InputStream entity(final EdmEntitySet edmEntitySet, final Entity 
entity, final ContextURL contextURL)
-      throws ODataSerializerException {
+  public InputStream entity(final EdmEntitySet edmEntitySet, final Entity 
entity, final ContextURL contextURL,
+      final ExpandItem options) throws ODataSerializerException {
     throw new ODataSerializerException("Entity serialization not implemented 
for XML format",
         ODataSerializerException.MessageKeys.NOT_IMPLEMENTED);
   }
 
   @Override
   public InputStream entitySet(final EdmEntitySet edmEntitySet, final 
EntitySet entitySet,
-      final ContextURL contextURL) throws ODataSerializerException {
+      final ContextURL contextURL, final ExpandItem options) throws 
ODataSerializerException {
     throw new ODataSerializerException("Entityset serialization not 
implemented for XML format",
         ODataSerializerException.MessageKeys.NOT_IMPLEMENTED);
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1976c340/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 6982678..665c258 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
@@ -20,7 +20,10 @@ package org.apache.olingo.server.core.serializer.json;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.olingo.commons.api.Constants;
 import org.apache.olingo.commons.api.data.ContextURL;
@@ -41,6 +44,10 @@ import 
org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.ODataSerializerException;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceProperty;
+import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.uri.queryoption.SelectItem;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
 import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
 import org.slf4j.Logger;
@@ -119,7 +126,7 @@ public class ODataJsonSerializer implements ODataSerializer 
{
 
   @Override
   public InputStream entitySet(final EdmEntitySet edmEntitySet, final 
EntitySet entitySet,
-      final ContextURL contextURL) throws ODataSerializerException {
+      final ContextURL contextURL, final ExpandItem options) throws 
ODataSerializerException {
     CircleStreamBuffer buffer = new CircleStreamBuffer();
     try {
       JsonGenerator json = new 
JsonFactory().createGenerator(buffer.getOutputStream());
@@ -138,7 +145,7 @@ public class ODataJsonSerializer implements ODataSerializer 
{
       json.writeFieldName(Constants.VALUE);
       json.writeStartArray();
       for (Entity entity : entitySet.getEntities()) {
-        writeEntity(edmEntitySet, entity, null, json);
+        writeEntity(edmEntitySet, entity, null, options, json);
       }
       json.writeEndArray();
       if (entitySet.getNext() != null) {
@@ -153,8 +160,8 @@ public class ODataJsonSerializer implements ODataSerializer 
{
   }
 
   @Override
-  public InputStream entity(final EdmEntitySet edmEntitySet, final Entity 
entity, final ContextURL contextURL)
-      throws ODataSerializerException {
+  public InputStream entity(final EdmEntitySet edmEntitySet, final Entity 
entity, final ContextURL contextURL,
+      final ExpandItem options) throws ODataSerializerException {
     if (format != ODataFormat.JSON_NO_METADATA && contextURL == null) {
       throw new ODataSerializerException("ContextURL null!",
           ODataSerializerException.MessageKeys.NO_CONTEXT_URL);
@@ -162,7 +169,7 @@ public class ODataJsonSerializer implements ODataSerializer 
{
     CircleStreamBuffer buffer = new CircleStreamBuffer();
     try {
       JsonGenerator json = new 
JsonFactory().createGenerator(buffer.getOutputStream());
-      writeEntity(edmEntitySet, entity, contextURL, json);
+      writeEntity(edmEntitySet, entity, contextURL, options, json);
       json.close();
     } catch (final IOException e) {
       throw new ODataSerializerException("An I/O exception occurred.", e,
@@ -172,7 +179,7 @@ public class ODataJsonSerializer implements ODataSerializer 
{
   }
 
   protected void writeEntity(final EdmEntitySet entitySet, final Entity 
entity, final ContextURL contextURL,
-      final JsonGenerator json) throws IOException, ODataSerializerException {
+      final ExpandItem options, final JsonGenerator json) throws IOException, 
ODataSerializerException {
     final EdmEntityType entityType = entitySet.getEntityType();
     json.writeStartObject();
     if (format != ODataFormat.JSON_NO_METADATA) {
@@ -191,16 +198,71 @@ public class ODataJsonSerializer implements 
ODataSerializer {
         }
       }
     }
+    final boolean all = isAll(options);
+    final Set<String> selected = all ? null : 
getSelectedPropertyNames(options.getSelectOption().getSelectItems());
     for (final String propertyName : entityType.getPropertyNames()) {
-      final EdmProperty edmProperty = (EdmProperty) 
entityType.getProperty(propertyName);
-      final Property property = entity.getProperty(propertyName);
-      writeProperty(edmProperty, property, json);
+      if (all || selected.contains(propertyName)) {
+        final EdmProperty edmProperty = (EdmProperty) 
entityType.getProperty(propertyName);
+        final Property property = entity.getProperty(propertyName);
+        final Set<List<String>> selectedPaths = all || 
edmProperty.isPrimitive() ? null :
+            getSelectedPaths(options.getSelectOption().getSelectItems(), 
propertyName);
+        writeProperty(edmProperty, property, selectedPaths, json);
+      }
     }
     json.writeEndObject();
   }
 
-  protected void writeProperty(final EdmProperty edmProperty, final Property 
property, final JsonGenerator json)
-      throws IOException, ODataSerializerException {
+  private boolean isAll(final ExpandItem options) {
+    if (options == null || options.getSelectOption() == null
+        || options.getSelectOption().getSelectItems() == null
+        || options.getSelectOption().getSelectItems().isEmpty()) {
+      return true;
+    } else {
+      for (final SelectItem item : options.getSelectOption().getSelectItems()) 
{
+        if (item.isStar()) {
+          return true;
+        }
+      }
+      return false;
+    }
+  }
+
+  private Set<String> getSelectedPropertyNames(final List<SelectItem> 
selectItems) {
+    Set<String> selected = new HashSet<String>();
+    for (final SelectItem item : selectItems) {
+      final UriResource resource = 
item.getResourcePath().getUriResourceParts().get(0);
+      if (resource instanceof UriResourceProperty) {
+        selected.add(((UriResourceProperty) resource).getProperty().getName());
+      }
+    }
+    return selected;
+  }
+
+  private Set<List<String>> getSelectedPaths(final List<SelectItem> 
selectItems, final String propertyName) {
+    Set<List<String>> selectedPaths = new HashSet<List<String>>();
+    for (final SelectItem item : selectItems) {
+      final List<UriResource> parts = 
item.getResourcePath().getUriResourceParts();
+      final UriResource resource = parts.get(0);
+      if (resource instanceof UriResourceProperty
+          && propertyName.equals(((UriResourceProperty) 
resource).getProperty().getName())) {
+        if (parts.size() > 1) {
+          List<String> path = new ArrayList<String>();
+          for (final UriResource part : parts.subList(1, parts.size())) {
+            if (part instanceof UriResourceProperty) {
+              path.add(((UriResourceProperty) part).getProperty().getName());
+            }
+          }
+          selectedPaths.add(path);
+        } else {
+          return null;
+        }
+      }
+    }
+    return selectedPaths.isEmpty() ? null : selectedPaths;
+  }
+
+  protected void writeProperty(final EdmProperty edmProperty, final Property 
property,
+      final Set<List<String>> selectedPaths, final JsonGenerator json) throws 
IOException, ODataSerializerException {
     json.writeFieldName(edmProperty.getName());
     if (property == null || property.isNull()) {
       if (edmProperty.isNullable() == Boolean.FALSE) {
@@ -212,13 +274,13 @@ public class ODataJsonSerializer implements 
ODataSerializer {
     } else {
       try {
         if (edmProperty.isCollection()) {
-          writeCollection(edmProperty, property, json);
+          writeCollection(edmProperty, property, selectedPaths, json);
         } else if (edmProperty.isPrimitive()) {
           writePrimitive(edmProperty, property, json);
         } else if (property.isLinkedComplex()) {
-          writeComplexValue(edmProperty, 
property.asLinkedComplex().getValue(), json);
+          writeComplexValue(edmProperty, 
property.asLinkedComplex().getValue(), selectedPaths, json);
         } else if (property.isComplex()) {
-          writeComplexValue(edmProperty, property.asComplex(), json);
+          writeComplexValue(edmProperty, property.asComplex(), selectedPaths, 
json);
         } else {
           throw new ODataSerializerException("Property type not yet 
supported!",
               ODataSerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, 
edmProperty.getName());
@@ -231,7 +293,8 @@ public class ODataJsonSerializer implements ODataSerializer 
{
     }
   }
 
-  private void writeCollection(EdmProperty edmProperty, Property property, 
JsonGenerator json)
+  private void writeCollection(final EdmProperty edmProperty, final Property 
property,
+      final Set<List<String>> selectedPaths, JsonGenerator json)
       throws IOException, EdmPrimitiveTypeException, ODataSerializerException {
     json.writeStartArray();
     for (Object value : property.asCollection()) {
@@ -246,10 +309,10 @@ public class ODataJsonSerializer implements 
ODataSerializer {
         json.writeString(value.toString());
         break;
       case COLLECTION_LINKED_COMPLEX:
-        writeComplexValue(edmProperty, ((LinkedComplexValue) 
value).getValue(), json);
+        writeComplexValue(edmProperty, ((LinkedComplexValue) 
value).getValue(), selectedPaths, json);
         break;
       case COLLECTION_COMPLEX:
-        writeComplexValue(edmProperty, property.asComplex(), json);
+        writeComplexValue(edmProperty, property.asComplex(), selectedPaths, 
json);
         break;
       default:
         throw new ODataSerializerException("Property type not yet supported!",
@@ -298,12 +361,17 @@ public class ODataJsonSerializer implements 
ODataSerializer {
   }
 
   private void writeComplexValue(final EdmProperty edmProperty, final 
List<Property> properties,
-      JsonGenerator json) throws IOException, EdmPrimitiveTypeException, 
ODataSerializerException {
+      final Set<List<String>> selectedPaths, JsonGenerator json)
+      throws IOException, EdmPrimitiveTypeException, ODataSerializerException {
     final EdmComplexType type = (EdmComplexType) edmProperty.getType();
     json.writeStartObject();
     for (final String propertyName : type.getPropertyNames()) {
       final Property property = findProperty(propertyName, properties);
-      writeProperty((EdmProperty) type.getProperty(propertyName), property, 
json);
+      if (selectedPaths == null || isSelected(selectedPaths, propertyName)) {
+        writeProperty((EdmProperty) type.getProperty(propertyName), property,
+            selectedPaths == null ? null : 
getReducedSelectedPaths(selectedPaths, propertyName),
+            json);
+      }
     }
     json.writeEndObject();
   }
@@ -316,4 +384,28 @@ public class ODataJsonSerializer implements 
ODataSerializer {
     }
     return null;
   }
+
+  private boolean isSelected(final Set<List<String>> selectedPaths, final 
String propertyName) {
+    for (final List<String> path : selectedPaths) {
+      if (propertyName.equals(path.get(0))) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private Set<List<String>> getReducedSelectedPaths(final Set<List<String>> 
selectedPaths,
+      final String propertyName) {
+    Set<List<String>> reducedPaths = new HashSet<List<String>>();
+    for (final List<String> path : selectedPaths) {
+      if (path.size() > 1) {
+        if (propertyName.equals(path.get(0))) {
+          reducedPaths.add(path.subList(1, path.size()));
+        }
+      } else {
+        return null;
+      }
+    }
+    return reducedPaths.isEmpty() ? null : reducedPaths;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1976c340/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
index f6c9f3a..c1b55c4 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java
@@ -31,6 +31,7 @@ import java.util.UUID;
 import org.apache.olingo.commons.api.ODataException;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
+import org.apache.olingo.commons.api.data.Link;
 import org.apache.olingo.commons.api.data.LinkedComplexValue;
 import org.apache.olingo.commons.api.data.Property;
 import org.apache.olingo.commons.api.data.ValueType;
@@ -41,6 +42,7 @@ import 
org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
 import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.core.data.EntityImpl;
 import org.apache.olingo.commons.core.data.EntitySetImpl;
+import org.apache.olingo.commons.core.data.LinkImpl;
 import org.apache.olingo.commons.core.data.LinkedComplexValueImpl;
 import org.apache.olingo.commons.core.data.PropertyImpl;
 import org.apache.olingo.server.api.uri.UriParameter;
@@ -59,7 +61,11 @@ public class DataProvider {
     data.put("ESCollAllPrim", createESCollAllPrim());
     data.put("ESMixPrimCollComp", createESMixPrimCollComp());
     data.put("ESAllKey", createESAllKey());
+    data.put("ESCompComp", createESCompComp());
     data.put("ESMedia", createESMedia());
+
+    linkESTwoPrim();
+    linkESAllPrim();
   }
 
   public EntitySet readAll(final EdmEntitySet edmEntitySet) throws 
DataProviderException {
@@ -112,25 +118,21 @@ public class DataProvider {
   private EntitySet createESTwoPrim() {
     EntitySet entitySet = new EntitySetImpl();
 
-    Entity entity = new EntityImpl();
-    entity.addProperty(createPrimitive("PropertyInt16", 32766));
-    entity.addProperty(createPrimitive("PropertyString", "Test String1"));
-    entitySet.getEntities().add(entity);
+    entitySet.getEntities().add(new EntityImpl()
+        .addProperty(createPrimitive("PropertyInt16", 32766))
+        .addProperty(createPrimitive("PropertyString", "Test String1")));
 
-    entity = new EntityImpl();
-    entity.addProperty(createPrimitive("PropertyInt16", -365));
-    entity.addProperty(createPrimitive("PropertyString", "Test String2"));
-    entitySet.getEntities().add(entity);
+    entitySet.getEntities().add(new EntityImpl()
+        .addProperty(createPrimitive("PropertyInt16", -365))
+        .addProperty(createPrimitive("PropertyString", "Test String2")));
 
-    entity = new EntityImpl();
-    entity.addProperty(createPrimitive("PropertyInt16", -32766));
-    entity.addProperty(createPrimitive("PropertyString", "Test String3"));
-    entitySet.getEntities().add(entity);
+    entitySet.getEntities().add(new EntityImpl()
+        .addProperty(createPrimitive("PropertyInt16", -32766))
+        .addProperty(createPrimitive("PropertyString", "Test String3")));
 
-    entity = new EntityImpl();
-    entity.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE));
-    entity.addProperty(createPrimitive("PropertyString", "Test String4"));
-    entitySet.getEntities().add(entity);
+    entitySet.getEntities().add(new EntityImpl()
+        .addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE))
+        .addProperty(createPrimitive("PropertyString", "Test String4")));
 
     return entitySet;
   }
@@ -138,64 +140,61 @@ public class DataProvider {
   private EntitySet createESAllPrim() {
     EntitySet entitySet = new EntitySetImpl();
 
-    Entity entity = new EntityImpl();
-    entity.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE));
-    entity.addProperty(createPrimitive("PropertyString", "First Resource - 
positive values"));
-    entity.addProperty(createPrimitive("PropertyBoolean", true));
-    entity.addProperty(createPrimitive("PropertyByte", 255));
-    entity.addProperty(createPrimitive("PropertySByte", Byte.MAX_VALUE));
-    entity.addProperty(createPrimitive("PropertyInt32", Integer.MAX_VALUE));
-    entity.addProperty(createPrimitive("PropertyInt64", Long.MAX_VALUE));
-    entity.addProperty(createPrimitive("PropertySingle", 1.79000000E+20));
-    entity.addProperty(createPrimitive("PropertyDouble", 
-1.7900000000000000E+19));
-    entity.addProperty(createPrimitive("PropertyDecimal", 34));
-    entity.addProperty(createPrimitive("PropertyBinary",
-        new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 
0xCD, (byte) 0xEF }));
-    entity.addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 
3, 0, 0, 0)));
-    entity.addProperty(createPrimitive("PropertyDateTimeOffset", 
getDateTime(2012, 12, 3, 7, 16, 23)));
-    entity.addProperty(createPrimitive("PropertyDuration", 6));
-    entity.addProperty(createPrimitive("PropertyGuid", GUID));
-    entity.addProperty(createPrimitive("PropertyTimeOfDay", getTime(3, 26, 
5)));
-    entitySet.getEntities().add(entity);
-
-    entity = new EntityImpl();
-    entity.addProperty(createPrimitive("PropertyInt16", Short.MIN_VALUE));
-    entity.addProperty(createPrimitive("PropertyString", "Second Resource - 
negative values"));
-    entity.addProperty(createPrimitive("PropertyBoolean", false));
-    entity.addProperty(createPrimitive("PropertyByte", 0));
-    entity.addProperty(createPrimitive("PropertySByte", Byte.MIN_VALUE));
-    entity.addProperty(createPrimitive("PropertyInt32", Integer.MIN_VALUE));
-    entity.addProperty(createPrimitive("PropertyInt64", Long.MIN_VALUE));
-    entity.addProperty(createPrimitive("PropertySingle", -1.79000000E+08));
-    entity.addProperty(createPrimitive("PropertyDouble", 
-1.7900000000000000E+05));
-    entity.addProperty(createPrimitive("PropertyDecimal", -34));
-    entity.addProperty(createPrimitive("PropertyBinary",
-        new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 
0xCD, (byte) 0xEF }));
-    entity.addProperty(createPrimitive("PropertyDate", getDateTime(2015, 11, 
5, 0, 0, 0)));
-    entity.addProperty(createPrimitive("PropertyDateTimeOffset", 
getDateTime(2005, 12, 3, 7, 17, 8)));
-    entity.addProperty(createPrimitive("PropertyDuration", 9));
-    entity.addProperty(createPrimitive("PropertyGuid", 
UUID.fromString("76543201-23ab-cdef-0123-456789dddfff")));
-    entity.addProperty(createPrimitive("PropertyTimeOfDay", getTime(23, 49, 
14)));
-    entitySet.getEntities().add(entity);
-
-    entity = new EntityImpl();
-    entity.addProperty(createPrimitive("PropertyInt16", 0));
-    entity.addProperty(createPrimitive("PropertyString", ""));
-    entity.addProperty(createPrimitive("PropertyBoolean", false));
-    entity.addProperty(createPrimitive("PropertyByte", 0));
-    entity.addProperty(createPrimitive("PropertySByte", 0));
-    entity.addProperty(createPrimitive("PropertyInt32", 0));
-    entity.addProperty(createPrimitive("PropertyInt64", 0));
-    entity.addProperty(createPrimitive("PropertySingle", 0));
-    entity.addProperty(createPrimitive("PropertyDouble", 0));
-    entity.addProperty(createPrimitive("PropertyDecimal", 0));
-    entity.addProperty(createPrimitive("PropertyBinary", new byte[] {}));
-    entity.addProperty(createPrimitive("PropertyDate", getDateTime(1970, 1, 1, 
0, 0, 0)));
-    entity.addProperty(createPrimitive("PropertyDateTimeOffset", 
getDateTime(2005, 12, 3, 0, 0, 0)));
-    entity.addProperty(createPrimitive("PropertyDuration", 0));
-    entity.addProperty(createPrimitive("PropertyGuid", 
UUID.fromString("76543201-23ab-cdef-0123-456789cccddd")));
-    entity.addProperty(createPrimitive("PropertyTimeOfDay", getTime(0, 1, 1)));
-    entitySet.getEntities().add(entity);
+    entitySet.getEntities().add(new EntityImpl()
+        .addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE))
+        .addProperty(createPrimitive("PropertyString", "First Resource - 
positive values"))
+        .addProperty(createPrimitive("PropertyBoolean", true))
+        .addProperty(createPrimitive("PropertyByte", 255))
+        .addProperty(createPrimitive("PropertySByte", Byte.MAX_VALUE))
+        .addProperty(createPrimitive("PropertyInt32", Integer.MAX_VALUE))
+        .addProperty(createPrimitive("PropertyInt64", Long.MAX_VALUE))
+        .addProperty(createPrimitive("PropertySingle", 1.79000000E+20))
+        .addProperty(createPrimitive("PropertyDouble", 
-1.7900000000000000E+19))
+        .addProperty(createPrimitive("PropertyDecimal", 34))
+        .addProperty(createPrimitive("PropertyBinary",
+            new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, 
(byte) 0xCD, (byte) 0xEF }))
+        .addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 3, 
0, 0, 0)))
+        .addProperty(createPrimitive("PropertyDateTimeOffset", 
getDateTime(2012, 12, 3, 7, 16, 23)))
+        .addProperty(createPrimitive("PropertyDuration", 6))
+        .addProperty(createPrimitive("PropertyGuid", GUID))
+        .addProperty(createPrimitive("PropertyTimeOfDay", getTime(3, 26, 5))));
+
+    entitySet.getEntities().add(new EntityImpl()
+        .addProperty(createPrimitive("PropertyInt16", Short.MIN_VALUE))
+        .addProperty(createPrimitive("PropertyString", "Second Resource - 
negative values"))
+        .addProperty(createPrimitive("PropertyBoolean", false))
+        .addProperty(createPrimitive("PropertyByte", 0))
+        .addProperty(createPrimitive("PropertySByte", Byte.MIN_VALUE))
+        .addProperty(createPrimitive("PropertyInt32", Integer.MIN_VALUE))
+        .addProperty(createPrimitive("PropertyInt64", Long.MIN_VALUE))
+        .addProperty(createPrimitive("PropertySingle", -1.79000000E+08))
+        .addProperty(createPrimitive("PropertyDouble", 
-1.7900000000000000E+05))
+        .addProperty(createPrimitive("PropertyDecimal", -34))
+        .addProperty(createPrimitive("PropertyBinary",
+            new byte[] { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, 
(byte) 0xCD, (byte) 0xEF }))
+        .addProperty(createPrimitive("PropertyDate", getDateTime(2015, 11, 5, 
0, 0, 0)))
+        .addProperty(createPrimitive("PropertyDateTimeOffset", 
getDateTime(2005, 12, 3, 7, 17, 8)))
+        .addProperty(createPrimitive("PropertyDuration", 9))
+        .addProperty(createPrimitive("PropertyGuid", 
UUID.fromString("76543201-23ab-cdef-0123-456789dddfff")))
+        .addProperty(createPrimitive("PropertyTimeOfDay", getTime(23, 49, 
14))));
+
+    entitySet.getEntities().add(new EntityImpl()
+        .addProperty(createPrimitive("PropertyInt16", 0))
+        .addProperty(createPrimitive("PropertyString", ""))
+        .addProperty(createPrimitive("PropertyBoolean", false))
+        .addProperty(createPrimitive("PropertyByte", 0))
+        .addProperty(createPrimitive("PropertySByte", 0))
+        .addProperty(createPrimitive("PropertyInt32", 0))
+        .addProperty(createPrimitive("PropertyInt64", 0))
+        .addProperty(createPrimitive("PropertySingle", 0))
+        .addProperty(createPrimitive("PropertyDouble", 0))
+        .addProperty(createPrimitive("PropertyDecimal", 0))
+        .addProperty(createPrimitive("PropertyBinary", new byte[] {}))
+        .addProperty(createPrimitive("PropertyDate", getDateTime(1970, 1, 1, 
0, 0, 0)))
+        .addProperty(createPrimitive("PropertyDateTimeOffset", 
getDateTime(2005, 12, 3, 0, 0, 0)))
+        .addProperty(createPrimitive("PropertyDuration", 0))
+        .addProperty(createPrimitive("PropertyGuid", 
UUID.fromString("76543201-23ab-cdef-0123-456789cccddd")))
+        .addProperty(createPrimitive("PropertyTimeOfDay", getTime(0, 1, 1))));
 
     return entitySet;
   }
@@ -281,46 +280,49 @@ public class DataProvider {
   private EntitySet createESCollAllPrim() {
     EntitySet entitySet = new EntitySetImpl();
 
+    entitySet.getEntities().add(new EntityImpl()
+        .addProperty(createPrimitive("PropertyInt16", 1))
+        .addProperty(createCollection("CollPropertyString",
+            "[email protected]", "[email protected]", 
"[email protected]"))
+        .addProperty(createCollection("CollPropertyBoolean", true, false, 
true))
+        .addProperty(createCollection("CollPropertyByte", 50, 200, 249))
+        .addProperty(createCollection("CollPropertySByte", -120, 120, 126))
+        .addProperty(createCollection("CollPropertyInt16", 1000, 2000, 30112))
+        .addProperty(createCollection("CollPropertyInt32", 23232323, 11223355, 
10000001))
+        .addProperty(createCollection("CollPropertyInt64", 929292929292L, 
333333333333L, 444444444444L))
+        .addProperty(createCollection("CollPropertySingle", 1.79000000E+03, 
2.66000000E+04, 3.21000000E+03))
+        .addProperty(createCollection("CollPropertyDouble",
+            -1.7900000000000000E+04, -2.7800000000000000E+07, 
3.2100000000000000E+03))
+        .addProperty(createCollection("CollPropertyDecimal", 12, -2, 1234))
+        .addProperty(createCollection("CollPropertyBinary",
+            new byte[] { (byte) 0xAB, (byte) 0xCD, (byte) 0xEF },
+            new byte[] { 0x01, 0x23, 0x45 },
+            new byte[] { 0x54, 0x67, (byte) 0x89 }))
+        .addProperty(createCollection("CollPropertyDate",
+            getDateTime(1958, 12, 3, 0, 0, 0),
+            getDateTime(1999, 8, 5, 0, 0, 0),
+            getDateTime(2013, 6, 25, 0, 0, 0)))
+        .addProperty(createCollection("CollPropertyDateTimeOffset",
+            getDateTime(2015, 8, 12, 3, 8, 34),
+            getDateTime(1970, 3, 28, 12, 11, 10),
+            getDateTime(1948, 2, 17, 9, 9, 9)))
+        .addProperty(createCollection("CollPropertyDuration", 13, 19680, 3600))
+        .addProperty(createCollection("CollPropertyGuid",
+            UUID.fromString("ffffff67-89ab-cdef-0123-456789aaaaaa"),
+            UUID.fromString("eeeeee67-89ab-cdef-0123-456789bbbbbb"),
+            UUID.fromString("cccccc67-89ab-cdef-0123-456789cccccc")))
+        .addProperty(createCollection("CollPropertyTimeOfDay",
+            getTime(4, 14, 13), getTime(23, 59, 59), getTime(1, 12, 33))));
+
     Entity entity = new EntityImpl();
-    entity.addProperty(createPrimitive("PropertyInt16", 1));
-    entity.addProperty(createCollection("CollPropertyString",
-        "[email protected]", "[email protected]", 
"[email protected]"));
-    entity.addProperty(createCollection("CollPropertyBoolean", true, false, 
true));
-    entity.addProperty(createCollection("CollPropertyByte", 50, 200, 249));
-    entity.addProperty(createCollection("CollPropertySByte", -120, 120, 126));
-    entity.addProperty(createCollection("CollPropertyInt16", 1000, 2000, 
30112));
-    entity.addProperty(createCollection("CollPropertyInt32", 23232323, 
11223355, 10000001));
-    entity.addProperty(createCollection("CollPropertyInt64", 929292929292L, 
333333333333L, 444444444444L));
-    entity.addProperty(createCollection("CollPropertySingle", 1.79000000E+03, 
2.66000000E+04, 3.21000000E+03));
-    entity.addProperty(createCollection("CollPropertyDouble",
-        -1.7900000000000000E+04, -2.7800000000000000E+07, 
3.2100000000000000E+03));
-    entity.addProperty(createCollection("CollPropertyDecimal", 12, -2, 1234));
-    entity.addProperty(createCollection("CollPropertyBinary",
-        new byte[] { (byte) 0xAB, (byte) 0xCD, (byte) 0xEF },
-        new byte[] { 0x01, 0x23, 0x45 },
-        new byte[] { 0x54, 0x67, (byte) 0x89 }));
-    entity.addProperty(createCollection("CollPropertyDate",
-        getDateTime(1958, 12, 3, 0, 0, 0), getDateTime(1999, 8, 5, 0, 0, 0), 
getDateTime(2013, 6, 25, 0, 0, 0)));
-    entity.addProperty(createCollection("CollPropertyDateTimeOffset",
-        getDateTime(2015, 8, 12, 3, 8, 34), getDateTime(1970, 3, 28, 12, 11, 
10), getDateTime(1948, 2, 17, 9, 9, 9)));
-    entity.addProperty(createCollection("CollPropertyDuration", 13, 19680, 
3600));
-    entity.addProperty(createCollection("CollPropertyGuid",
-        UUID.fromString("ffffff67-89ab-cdef-0123-456789aaaaaa"),
-        UUID.fromString("eeeeee67-89ab-cdef-0123-456789bbbbbb"),
-        UUID.fromString("cccccc67-89ab-cdef-0123-456789cccccc")));
-    entity.addProperty(createCollection("CollPropertyTimeOfDay",
-        getTime(4, 14, 13), getTime(23, 59, 59), getTime(1, 12, 33)));
+    
entity.getProperties().addAll(entitySet.getEntities().get(0).getProperties());
+    entity.getProperties().set(0, createPrimitive("PropertyInt16", 2));
     entitySet.getEntities().add(entity);
 
-    Entity entity2 = new EntityImpl();
-    entity2.getProperties().addAll(entity.getProperties());
-    entity2.getProperties().set(0, createPrimitive("PropertyInt16", 2));
-    entitySet.getEntities().add(entity2);
-
-    entity2 = new EntityImpl();
-    entity2.getProperties().addAll(entity.getProperties());
-    entity2.getProperties().set(0, createPrimitive("PropertyInt16", 3));
-    entitySet.getEntities().add(entity2);
+    entity = new EntityImpl();
+    
entity.getProperties().addAll(entitySet.getEntities().get(0).getProperties());
+    entity.getProperties().set(0, createPrimitive("PropertyInt16", 3));
+    entitySet.getEntities().add(entity);
 
     return entitySet;
   }
@@ -383,36 +385,62 @@ public class DataProvider {
   private EntitySet createESAllKey() {
     EntitySet entitySet = new EntitySetImpl();
 
+    entitySet.getEntities().add(new EntityImpl()
+        .addProperty(createPrimitive("PropertyString", "First"))
+        .addProperty(createPrimitive("PropertyBoolean", true))
+        .addProperty(createPrimitive("PropertyByte", 255))
+        .addProperty(createPrimitive("PropertySByte", Byte.MAX_VALUE))
+        .addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE))
+        .addProperty(createPrimitive("PropertyInt32", Integer.MAX_VALUE))
+        .addProperty(createPrimitive("PropertyInt64", Long.MAX_VALUE))
+        .addProperty(createPrimitive("PropertyDecimal", 34))
+        .addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 3, 
0, 0, 0)))
+        .addProperty(createPrimitive("PropertyDateTimeOffset", 
getDateTime(2012, 12, 3, 7, 16, 23)))
+        .addProperty(createPrimitive("PropertyDuration", 6))
+        .addProperty(createPrimitive("PropertyGuid", GUID))
+        .addProperty(createPrimitive("PropertyTimeOfDay", getTime(2, 48, 
21))));
+
+    entitySet.getEntities().add(new EntityImpl()
+        .addProperty(createPrimitive("PropertyString", "Second"))
+        .addProperty(createPrimitive("PropertyBoolean", true))
+        .addProperty(createPrimitive("PropertyByte", 254))
+        .addProperty(createPrimitive("PropertySByte", 124))
+        .addProperty(createPrimitive("PropertyInt16", 32764))
+        .addProperty(createPrimitive("PropertyInt32", 2147483644))
+        .addProperty(createPrimitive("PropertyInt64", 9223372036854775804L))
+        .addProperty(createPrimitive("PropertyDecimal", 34))
+        .addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 3, 
0, 0, 0)))
+        .addProperty(createPrimitive("PropertyDateTimeOffset", 
getDateTime(2012, 12, 3, 7, 16, 23)))
+        .addProperty(createPrimitive("PropertyDuration", 6))
+        .addProperty(createPrimitive("PropertyGuid", GUID))
+        .addProperty(createPrimitive("PropertyTimeOfDay", getTime(2, 48, 
21))));
+
+    return entitySet;
+  }
+
+  private EntitySet createESCompComp() {
+    EntitySet entitySet = new EntitySetImpl();
+
     Entity entity = new EntityImpl();
-    entity.addProperty(createPrimitive("PropertyString", "First"));
-    entity.addProperty(createPrimitive("PropertyBoolean", true));
-    entity.addProperty(createPrimitive("PropertyByte", 255));
-    entity.addProperty(createPrimitive("PropertySByte", Byte.MAX_VALUE));
-    entity.addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE));
-    entity.addProperty(createPrimitive("PropertyInt32", Integer.MAX_VALUE));
-    entity.addProperty(createPrimitive("PropertyInt64", Long.MAX_VALUE));
-    entity.addProperty(createPrimitive("PropertyDecimal", 34));
-    entity.addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 
3, 0, 0, 0)));
-    entity.addProperty(createPrimitive("PropertyDateTimeOffset", 
getDateTime(2012, 12, 3, 7, 16, 23)));
-    entity.addProperty(createPrimitive("PropertyDuration", 6));
-    entity.addProperty(createPrimitive("PropertyGuid", GUID));
-    entity.addProperty(createPrimitive("PropertyTimeOfDay", getTime(2, 48, 
21)));
+    entity.addProperty(createPrimitive("PropertyInt16", 1));
+    LinkedComplexValue complexValueInner = new LinkedComplexValueImpl();
+    complexValueInner.getValue().add(createPrimitive("PropertyInt16", 123));
+    complexValueInner.getValue().add(createPrimitive("PropertyString", "String 
1"));
+    LinkedComplexValue complexValueOuter = new LinkedComplexValueImpl();
+    complexValueOuter.getValue().add(
+        new PropertyImpl(null, "PropertyComp", ValueType.LINKED_COMPLEX, 
complexValueInner));
+    entity.addProperty(new PropertyImpl(null, "PropertyComp", 
ValueType.LINKED_COMPLEX, complexValueOuter));
     entitySet.getEntities().add(entity);
 
     entity = new EntityImpl();
-    entity.addProperty(createPrimitive("PropertyString", "Second"));
-    entity.addProperty(createPrimitive("PropertyBoolean", true));
-    entity.addProperty(createPrimitive("PropertyByte", 254));
-    entity.addProperty(createPrimitive("PropertySByte", 124));
-    entity.addProperty(createPrimitive("PropertyInt16", 32764));
-    entity.addProperty(createPrimitive("PropertyInt32", 2147483644));
-    entity.addProperty(createPrimitive("PropertyInt64", 9223372036854775804L));
-    entity.addProperty(createPrimitive("PropertyDecimal", 34));
-    entity.addProperty(createPrimitive("PropertyDate", getDateTime(2012, 12, 
3, 0, 0, 0)));
-    entity.addProperty(createPrimitive("PropertyDateTimeOffset", 
getDateTime(2012, 12, 3, 7, 16, 23)));
-    entity.addProperty(createPrimitive("PropertyDuration", 6));
-    entity.addProperty(createPrimitive("PropertyGuid", GUID));
-    entity.addProperty(createPrimitive("PropertyTimeOfDay", getTime(2, 48, 
21)));
+    entity.addProperty(createPrimitive("PropertyInt16", 2));
+    complexValueInner = new LinkedComplexValueImpl();
+    complexValueInner.getValue().add(createPrimitive("PropertyInt16", 987));
+    complexValueInner.getValue().add(createPrimitive("PropertyString", "String 
2"));
+    complexValueOuter = new LinkedComplexValueImpl();
+    complexValueOuter.getValue().add(
+        new PropertyImpl(null, "PropertyComp", ValueType.LINKED_COMPLEX, 
complexValueInner));
+    entity.addProperty(new PropertyImpl(null, "PropertyComp", 
ValueType.LINKED_COMPLEX, complexValueOuter));
     entitySet.getEntities().add(entity);
 
     return entitySet;
@@ -444,6 +472,26 @@ public class DataProvider {
     return entitySet;
   }
 
+  private void linkESTwoPrim() {
+    EntitySet entitySet = data.get("ESTwoPrim");
+    final List<Entity> targetEntities = data.get("ESAllPrim").getEntities();
+
+    setLinks(entitySet.getEntities().get(1), "NavPropertyETAllPrimMany", 
targetEntities.subList(1, 3));
+
+    setLink(entitySet.getEntities().get(3), "NavPropertyETAllPrimOne", 
targetEntities.get(0));
+  }
+
+  private void linkESAllPrim() {
+    EntitySet entitySet = data.get("ESAllPrim");
+    final List<Entity> targetEntities = data.get("ESTwoPrim").getEntities();
+
+    setLinks(entitySet.getEntities().get(0), "NavPropertyETTwoPrimMany", 
targetEntities.subList(1, 2));
+    setLink(entitySet.getEntities().get(0), "NavPropertyETTwoPrimOne", 
targetEntities.get(3));
+
+    setLinks(entitySet.getEntities().get(2), "NavPropertyETTwoPrimMany",
+        Arrays.asList(targetEntities.get(0), targetEntities.get(2), 
targetEntities.get(3)));
+  }
+
   private Property createPrimitive(final String name, final Object value) {
     return new PropertyImpl(null, name, ValueType.PRIMITIVE, value);
   }
@@ -475,4 +523,20 @@ public class DataProvider {
     timestamp.setNanos(nanosecond);
     return timestamp;
   }
+
+  private void setLink(Entity entity, final String navigationPropertyName, 
final Entity target) {
+    Link link = new LinkImpl();
+    link.setTitle(navigationPropertyName);
+    link.setInlineEntity(target);
+    entity.getNavigationLinks().add(link);
+  }
+
+  private void setLinks(Entity entity, final String navigationPropertyName, 
final List<Entity> targets) {
+    Link link = new LinkImpl();
+    link.setTitle(navigationPropertyName);
+    EntitySet target = new EntitySetImpl();
+    target.getEntities().addAll(targets);
+    link.setInlineEntitySet(target);
+    entity.getNavigationLinks().add(link);
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1976c340/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index 49a10eb..3917fae 100644
--- 
a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ 
b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@ -73,7 +73,7 @@ public class TechnicalProcessor implements 
EntityCollectionProcessor, EntityProc
         response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
       } else {
         ODataSerializer serializer = 
odata.createSerializer(ODataFormat.fromContentType(requestedContentType));
-        response.setContent(serializer.entitySet(edmEntitySet, entitySet, 
getContextUrl(edmEntitySet, false)));
+        response.setContent(serializer.entitySet(edmEntitySet, entitySet, 
getContextUrl(edmEntitySet, false), null));
         response.setStatusCode(HttpStatusCode.OK.getStatusCode());
         response.setHeader(HttpHeader.CONTENT_TYPE, 
requestedContentType.toContentTypeString());
       }
@@ -100,7 +100,7 @@ public class TechnicalProcessor implements 
EntityCollectionProcessor, EntityProc
         response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
       } else {
         ODataSerializer serializer = 
odata.createSerializer(ODataFormat.fromContentType(requestedContentType));
-        response.setContent(serializer.entity(edmEntitySet, entity, 
getContextUrl(edmEntitySet, true)));
+        response.setContent(serializer.entity(edmEntitySet, entity, 
getContextUrl(edmEntitySet, true), null));
         response.setStatusCode(HttpStatusCode.OK.getStatusCode());
         response.setHeader(HttpHeader.CONTENT_TYPE, 
requestedContentType.toContentTypeString());
       }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1976c340/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java
 
b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java
index 581ec1d..e8be8ad 100644
--- 
a/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java
+++ 
b/lib/server-tecsvc/src/test/java/org/apache/olingo/server/tecsvc/data/DataProviderTest.java
@@ -68,11 +68,20 @@ public class DataProviderTest {
 
   @Test
   public void esAllPrim() throws Exception {
-    EntitySet outSet = new DataProvider().readAll(esAllPrim);
+    final DataProvider data = new DataProvider();
+    EntitySet outSet = data.readAll(esAllPrim);
 
     Assert.assertEquals(3, outSet.getEntities().size());
+
     Entity first = outSet.getEntities().get(0);
     Assert.assertEquals(16, first.getProperties().size());
+    Assert.assertEquals(2, first.getNavigationLinks().size());
+    final EntitySet target = 
first.getNavigationLink("NavPropertyETTwoPrimMany").getInlineEntitySet();
+    Assert.assertNotNull(target);
+    Assert.assertEquals(1, target.getEntities().size());
+    
Assert.assertEquals(data.readAll(entityContainer.getEntitySet("ESTwoPrim")).getEntities().get(1),
+        target.getEntities().get(0));
+
     Assert.assertEquals(16, 
outSet.getEntities().get(1).getProperties().size());
     Assert.assertEquals(16, 
outSet.getEntities().get(2).getProperties().size());
   }
@@ -120,7 +129,7 @@ public class DataProviderTest {
     Assert.assertEquals(2, linkedComplexValue.getValue().size());
     Property lcProp = linkedComplexValue.getValue().get(0);
     Assert.assertFalse(lcProp.isCollection());
-    Assert.assertEquals(Integer.valueOf("123"), lcProp.getValue());
+    Assert.assertEquals(123, lcProp.getValue());
     //
     Assert.assertEquals(4, outSet.getEntities().get(1).getProperties().size());
     Assert.assertEquals(4, outSet.getEntities().get(2).getProperties().size());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1976c340/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 8e6d3ad..e33e1dd 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
@@ -20,7 +20,9 @@ package org.apache.olingo.server.core.serializer.json;
 
 import java.io.InputStream;
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.olingo.commons.api.data.ContextURL;
@@ -31,16 +33,25 @@ import org.apache.olingo.commons.api.data.ValueType;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntityContainer;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.format.ODataFormat;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.ODataSerializerException;
+import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceProperty;
+import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.uri.queryoption.SelectItem;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
 import org.hamcrest.CoreMatchers;
 import org.junit.Assert;
 import org.junit.Test;
+import org.mockito.Mockito;
 
 public class ODataJsonSerializerTest {
 
@@ -55,7 +66,8 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESAllPrim");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet, entity,
-        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build());
+        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
+        null);
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
@@ -85,7 +97,7 @@ public class ODataJsonSerializerTest {
     Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     
entity.getProperties().retainAll(Arrays.asList(entity.getProperties().get(0)));
     final String resultString = 
IOUtils.toString(serializer.entity(edmEntitySet, entity,
-        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()));
+        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
 null));
     final String expectedResult = 
"{\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
         + "\"PropertyInt16\":32767,"
         + "\"PropertyString\":null,\"PropertyBoolean\":null,"
@@ -104,7 +116,7 @@ public class ODataJsonSerializerTest {
     Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     entity.getProperties().clear();
     serializer.entity(edmEntitySet, entity,
-        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build());
+        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
 null);
   }
 
   @Test
@@ -114,7 +126,7 @@ public class ODataJsonSerializerTest {
     entity.getProperties().get(0).setValue(ValueType.PRIMITIVE, false);
     try {
       serializer.entity(edmEntitySet, entity,
-          
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build());
+          
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
 null);
       Assert.fail("Expected exception not thrown!");
     } catch (final ODataSerializerException e) {
       
Assert.assertEquals(ODataSerializerException.MessageKeys.WRONG_PROPERTY_VALUE, 
e.getMessageKey());
@@ -131,7 +143,7 @@ public class ODataJsonSerializerTest {
     entitySet.setCount(entitySet.getEntities().size());
     entitySet.setNext(URI.create("/next"));
     InputStream result = serializer.entitySet(edmEntitySet, entitySet,
-        ContextURL.Builder.create().entitySet(edmEntitySet).build());
+        ContextURL.Builder.create().entitySet(edmEntitySet).build(), null);
     final String resultString = IOUtils.toString(result);
 
     Assert.assertThat(resultString, CoreMatchers.startsWith("{"
@@ -154,7 +166,7 @@ public class ODataJsonSerializerTest {
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet, entity,
         
ContextURL.Builder.create().serviceRoot(URI.create("http://host/service/";))
-            .entitySet(edmEntitySet).suffix(Suffix.ENTITY).build());
+            .entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(), null);
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + 
"\"@odata.context\":\"http://host/service/$metadata#ESCollAllPrim/$entity\",";
@@ -187,7 +199,7 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESCompAllPrim");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet, entity,
-        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build());
+        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
 null);
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"$metadata#ESCompAllPrim/$entity\","
@@ -218,7 +230,7 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESMixPrimCollComp");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = serializer.entity(edmEntitySet, entity,
-        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build());
+        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
 null);
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{"
         + "\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\","
@@ -239,7 +251,7 @@ public class ODataJsonSerializerTest {
     Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     
entity.getProperties().retainAll(Arrays.asList(entity.getProperties().get(0)));
     final String resultString = 
IOUtils.toString(serializer.entity(edmEntitySet, entity,
-        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()));
+        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
 null));
     final String expectedResult = 
"{\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\","
         + "\"PropertyInt16\":32767,"
         + 
"\"CollPropertyString\":null,\"PropertyComp\":null,\"CollPropertyComp\":null}";
@@ -251,7 +263,7 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESTwoPrim");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA)
-        .entity(edmEntitySet, entity, null);
+        .entity(edmEntitySet, entity, null, null);
     final String resultString = IOUtils.toString(result);
     final String expectedResult = 
"{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}";
     Assert.assertEquals(expectedResult, resultString);
@@ -262,7 +274,7 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESTwoPrim");
     final EntitySet entitySet = data.readAll(edmEntitySet);
     InputStream result = new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA)
-        .entitySet(edmEntitySet, entitySet, 
ContextURL.Builder.create().entitySet(edmEntitySet).build());
+        .entitySet(edmEntitySet, entitySet, 
ContextURL.Builder.create().entitySet(edmEntitySet).build(), null);
     final String resultString = IOUtils.toString(result);
     final String expectedResult = "{\"value\":["
         + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"},"
@@ -278,7 +290,7 @@ public class ODataJsonSerializerTest {
     Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     entity.setMediaETag("theMediaETag");
     final String resultString = 
IOUtils.toString(serializer.entity(edmEntitySet, entity,
-        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build()));
+        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
 null));
     final String expectedResult = 
"{\"@odata.context\":\"$metadata#ESMedia/$entity\","
         + 
"\"@odata.mediaEtag\":\"theMediaETag\",\"@odata.mediaContentType\":\"image/png\","
         + "\"PropertyInt16\":1}";
@@ -290,7 +302,7 @@ public class ODataJsonSerializerTest {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMedia");
     final EntitySet entitySet = data.readAll(edmEntitySet);
     final String resultString = 
IOUtils.toString(serializer.entitySet(edmEntitySet, entitySet,
-        ContextURL.Builder.create().entitySet(edmEntitySet).build()));
+        ContextURL.Builder.create().entitySet(edmEntitySet).build(), null));
     final String expectedResult = 
"{\"@odata.context\":\"$metadata#ESMedia\",\"value\":["
         + "{\"@odata.mediaContentType\":\"image/png\",\"PropertyInt16\":1},"
         + "{\"@odata.mediaContentType\":\"image/bmp\",\"PropertyInt16\":2},"
@@ -298,4 +310,115 @@ public class ODataJsonSerializerTest {
         + "{\"@odata.mediaContentType\":\"foo\",\"PropertyInt16\":4}]}";
     Assert.assertEquals(expectedResult, resultString);
   }
+
+  @Test
+  public void select() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESAllPrim");
+    final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    final SelectItem selectItem1 = mockSelectItem(edmEntitySet, 
"PropertyDate");
+    final SelectItem selectItem2 = mockSelectItem(edmEntitySet, 
"PropertyBoolean");
+    final SelectOption select = mockSelectOption(Arrays.asList(selectItem1, 
selectItem2, selectItem2));
+    ExpandItem options = Mockito.mock(ExpandItem.class);
+    Mockito.when(options.getSelectOption()).thenReturn(select);
+    InputStream result =
+        new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer
+            .entity(edmEntitySet, entity,
+                null, // 
ContextURL.Builder.create().entitySet(edmEntitySet).selectList("PropertyBoolean,PropertyDate")
+                      //     .suffix(Suffix.ENTITY).build(),
+                options);
+    final String resultString = IOUtils.toString(result);
+    final String expectedResult = "{"
+        // + 
"\"@odata.context\":\"$metadata#ESAllPrim(PropertyBoolean,PropertyDate)/$entity\","
+        + "\"PropertyBoolean\":true,\"PropertyDate\":\"2012-12-03\"}";
+    Assert.assertEquals(expectedResult, resultString);
+  }
+
+  @Test
+  public void selectAll() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESTwoPrim");
+    final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    final SelectItem selectItem1 = mockSelectItem(edmEntitySet, 
"PropertyString");
+    SelectItem selectItem2 = Mockito.mock(SelectItem.class);
+    Mockito.when(selectItem2.isStar()).thenReturn(true);
+    final SelectOption select = mockSelectOption(Arrays.asList(selectItem1, 
selectItem2));
+    ExpandItem options = Mockito.mock(ExpandItem.class);
+    Mockito.when(options.getSelectOption()).thenReturn(select);
+    InputStream result = serializer.entity(edmEntitySet, entity,
+        
ContextURL.Builder.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build(),
+        options);
+    final String resultString = IOUtils.toString(result);
+    final String expectedResult = 
"{\"@odata.context\":\"$metadata#ESTwoPrim/$entity\","
+        + "\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"}";
+    Assert.assertEquals(expectedResult, resultString);
+  }
+
+  @Test
+  public void selectComplex() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESCompComp");
+    final EntitySet entitySet = data.readAll(edmEntitySet);
+    final SelectOption select = mockSelectOption(Arrays.asList(
+        mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp", 
"PropertyString")));
+    ExpandItem options = Mockito.mock(ExpandItem.class);
+    Mockito.when(options.getSelectOption()).thenReturn(select);
+    InputStream result =
+        new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer
+            .entitySet(edmEntitySet, entitySet,
+                null, // ContextURL.Builder.create().entitySet(edmEntitySet)
+                      //     
.selectList("PropertyComp/PropertyComp/PropertyString").build(),
+                options);
+    final String resultString = IOUtils.toString(result);
+    Assert.assertEquals("{"
+        // + 
"\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp/PropertyString)\","
+        + "\"value\":["
+        + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyString\":\"String 
1\"}}},"
+        + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyString\":\"String 
2\"}}}]}",
+        resultString);
+  }
+
+  @Test
+  public void selectComplexTwice() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESCompComp");
+    final EntitySet entitySet = data.readAll(edmEntitySet);
+    final SelectOption select = mockSelectOption(Arrays.asList(
+        mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp", 
"PropertyString"),
+        mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp")));
+    ExpandItem options = Mockito.mock(ExpandItem.class);
+    Mockito.when(options.getSelectOption()).thenReturn(select);
+    InputStream result =
+        new ODataJsonSerializer(ODataFormat.JSON_NO_METADATA) // serializer
+            .entitySet(edmEntitySet, entitySet,
+                null, // ContextURL.Builder.create().entitySet(edmEntitySet)
+                      //     .selectList("PropertyComp/PropertyComp").build(),
+                options);
+    final String resultString = IOUtils.toString(result);
+    Assert.assertEquals("{"
+    //    + 
"\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp)\","
+        + "\"value\":["
+        + 
"{\"PropertyComp\":{\"PropertyComp\":{\"PropertyInt16\":123,\"PropertyString\":\"String
 1\"}}},"
+        + 
"{\"PropertyComp\":{\"PropertyComp\":{\"PropertyInt16\":987,\"PropertyString\":\"String
 2\"}}}]}",
+        resultString);
+  }
+
+  private SelectItem mockSelectItem(final EdmEntitySet edmEntitySet, final 
String... names) {
+    EdmStructuredType type = edmEntitySet.getEntityType();
+    List<UriResource> elements = new ArrayList<UriResource>();
+    for (final String name : Arrays.asList(names)) {
+      UriResourceProperty element = Mockito.mock(UriResourceProperty.class);
+      final EdmProperty property = (EdmProperty) type.getProperty(name);
+      Mockito.when(element.getProperty()).thenReturn(property);
+      elements.add(element);
+      type = property.isPrimitive() ? null : (EdmStructuredType) 
property.getType();
+    }
+    UriInfoResource resource = Mockito.mock(UriInfoResource.class);
+    Mockito.when(resource.getUriResourceParts()).thenReturn(elements);
+    SelectItem selectItem = Mockito.mock(SelectItem.class);
+    Mockito.when(selectItem.getResourcePath()).thenReturn(resource);
+    return selectItem;
+  }
+
+  private SelectOption mockSelectOption(final List<SelectItem> selectItems) {
+    SelectOption select = Mockito.mock(SelectOption.class);
+    Mockito.when(select.getSelectItems()).thenReturn(selectItems);
+    return select;
+  }
 }

Reply via email to