You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2014/10/02 08:41:25 UTC

git commit: OLINGO-444, OLINGO-445: Adding support for addressing a individual property (primitive, complex) and aslo ability to retrive the bare value using

Repository: olingo-odata4
Updated Branches:
  refs/heads/Olingo-444_445 [created] afebbbbb6


OLINGO-444, OLINGO-445: Adding support for addressing a individual property (primitive, complex) and aslo ability to retrive the bare value using

Signed-off-by: Michael Bolz <mi...@sap.com>


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

Branch: refs/heads/Olingo-444_445
Commit: afebbbbb679a9ee985180717106a7ace8f54b051
Parents: 11bee5d
Author: Ramesh Reddy <ra...@jboss.org>
Authored: Fri Sep 26 13:24:57 2014 -0500
Committer: Michael Bolz <mi...@sap.com>
Committed: Thu Oct 2 08:40:17 2014 +0200

----------------------------------------------------------------------
 .../server/api/processor/EntityProcessor.java   |  14 ++
 .../api/processor/EntitySetProcessor.java       |   2 +-
 .../server/api/serializer/ODataSerializer.java  |  12 ++
 .../apache/olingo/server/core/ODataHandler.java |  26 ++-
 .../core/serializer/ODataXmlSerializerImpl.java |  10 +
 .../serializer/json/ODataJsonSerializer.java    | 122 +++++++++---
 .../serializer/utils/ContextURLBuilder.java     |  11 +-
 .../tecsvc/processor/TechnicalProcessor.java    |  71 ++++++-
 .../olingo/server/core/ODataHandlerTest.java    |  75 ++++++-
 .../json/ODataJsonSerializerTest.java           | 195 ++++++++++++++-----
 10 files changed, 441 insertions(+), 97 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/afebbbbb/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntityProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntityProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntityProcessor.java
index a277fa9..daccae4 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntityProcessor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntityProcessor.java
@@ -36,4 +36,18 @@ public interface EntityProcessor extends Processor {
    *  @param requestedContentType - requested content type after content negotiation
    */
   void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType format);
+
+  /**
+   * Reads primitive property from entity.
+   * If the property is single-valued and has the null value, the service responds with 204 No Content.
+   * If the property is not available, for example due to permissions, the service responds with 404 Not Found
+   * @param request - OData request object containing raw HTTP information
+   * @param response - OData response object for collecting response data
+   * @param uriInfo - information of a parsed OData URI
+   * @param format - requested content type after content negotiation
+   * @param value - true if only value of property requested through $value,
+   *                 false when individual property read with metadata
+   */  
+  void readEntityProperty(ODataRequest request, ODataResponse response,
+      UriInfo uriInfo, ContentType format, boolean value);
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/afebbbbb/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntitySetProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntitySetProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntitySetProcessor.java
index e23823c..eb36ea4 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntitySetProcessor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntitySetProcessor.java
@@ -30,7 +30,7 @@ public interface EntitySetProcessor extends Processor {
 
   /**
    *  Reads entities data from persistence and puts serialized content and status into the response.
-   *  
+   *
    *  @param request - OData request object containing raw HTTP information
    *  @param response - OData response object for collecting response data
    *  @param uriInfo - information of a parsed OData URI

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/afebbbbb/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 8d11ee4..4fe93ec 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
@@ -22,8 +22,10 @@ import java.io.InputStream;
 
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
+import org.apache.olingo.commons.api.data.Property;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
@@ -55,6 +57,16 @@ public interface ODataSerializer {
    */
   InputStream entity(EdmEntitySet edmEntitySet, Entity entity, ODataSerializerOptions options)
       throws ODataSerializerException;
+  
+  /**
+   * Writes entity data into an InputStream.
+   * @param edmProperty property definition
+   * @param property property value
+   * @param value when true send bare value of property, false metadata is also included
+   * @param options options for the serializer
+   */
+  InputStream entityProperty(EdmProperty edmProperty, Property property,
+      boolean value, ODataSerializerOptions options) throws ODataSerializerException;
 
   /**
    * Writes entity-set data into an InputStream.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/afebbbbb/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
index fed47a7..7a5831f 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
@@ -44,6 +44,7 @@ import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriResource;
 import org.apache.olingo.server.api.uri.UriResourceNavigation;
 import org.apache.olingo.server.api.uri.UriResourcePartTyped;
+import org.apache.olingo.server.api.uri.UriResourceProperty;
 import org.apache.olingo.server.core.uri.parser.Parser;
 import org.apache.olingo.server.core.uri.parser.UriParserException;
 import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
@@ -230,7 +231,30 @@ public class ODataHandler {
     case count:
       if (request.getMethod().equals(HttpMethod.GET)) {
         EntitySetProcessor cp = selectProcessor(EntitySetProcessor.class);
-      	cp.countEntitySet(request, response, uriInfo);
+        cp.countEntitySet(request, response, uriInfo);
+      } else {
+        throw new ODataHandlerException("not implemented",
+            ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+      }
+      break;
+    case primitiveProperty:
+    case complexProperty:
+      if (request.getMethod().equals(HttpMethod.GET)) {
+        EntityProcessor ep = selectProcessor(EntityProcessor.class);
+
+        requestedContentType =
+            ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request, ep, EntityProcessor.class);
+
+        ep.readEntityProperty(request, response, uriInfo, requestedContentType, false);
+      } else {
+        throw new ODataHandlerException("not implemented",
+            ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+      }
+      break;
+    case value:
+      if (request.getMethod().equals(HttpMethod.GET)) {
+        EntityProcessor ep = selectProcessor(EntityProcessor.class);
+        ep.readEntityProperty(request, response, uriInfo, requestedContentType, true);
       } else {
         throw new ODataHandlerException("not implemented",
             ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/afebbbbb/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 580833a..9588619 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
@@ -26,8 +26,10 @@ import javax.xml.stream.XMLStreamWriter;
 
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
+import org.apache.olingo.commons.api.data.Property;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.ODataSerializerException;
@@ -106,4 +108,12 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
       final ExpandOption expand, final SelectOption select) throws ODataSerializerException {
     return ContextURLHelper.buildSelectList(edmEntitySet.getEntityType(), expand, select);
   }
+
+  @Override
+  public 	InputStream entityProperty(EdmProperty edmProperty, Property property,
+    boolean value, ODataSerializerOptions options)
+      throws ODataSerializerException{
+    throw new ODataSerializerException("error serialization not implemented for XML format",
+      ODataSerializerException.MessageKeys.NOT_IMPLEMENTED);
+	}
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/afebbbbb/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 1d5e549..46cc6ff 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
@@ -133,15 +133,13 @@ public class ODataJsonSerializer implements ODataSerializer {
     try {
       JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
       json.writeStartObject();
-      if (format != ODataFormat.JSON_NO_METADATA) {
-        if (options == null || options.getContextURL() == null) {
-          throw new ODataSerializerException("ContextURL null!",
-              ODataSerializerException.MessageKeys.NO_CONTEXT_URL);
-        } else {
-          json.writeStringField(Constants.JSON_CONTEXT,
-              ContextURLBuilder.create(options.getContextURL()).toASCIIString());
-        }
+
+      final ContextURL contextURL = checkContextURL(options);
+      if (contextURL != null) {
+        json.writeStringField(Constants.JSON_CONTEXT,
+            ContextURLBuilder.create(contextURL).toASCIIString());
       }
+
       if (options != null && options.getCount() != null && options.getCount().getValue()
           && entitySet.getCount() != null) {
         json.writeNumberField(Constants.JSON_COUNT, entitySet.getCount());
@@ -163,11 +161,7 @@ public class ODataJsonSerializer implements ODataSerializer {
   @Override
   public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity,
       final ODataSerializerOptions options) throws ODataSerializerException {
-    final ContextURL contextURL = options == null ? null : options.getContextURL();
-    if (format != ODataFormat.JSON_NO_METADATA && contextURL == null) {
-      throw new ODataSerializerException("ContextURL null!",
-          ODataSerializerException.MessageKeys.NO_CONTEXT_URL);
-    }
+    final ContextURL contextURL = checkContextURL(options);
     CircleStreamBuffer buffer = new CircleStreamBuffer();
     try {
       JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
@@ -181,6 +175,19 @@ public class ODataJsonSerializer implements ODataSerializer {
     return buffer.getInputStream();
   }
 
+  private ContextURL checkContextURL(final ODataSerializerOptions options)
+      throws ODataSerializerException {
+    ContextURL contextURL = options == null ? null : options.getContextURL();
+    if (format != ODataFormat.JSON_NO_METADATA && contextURL == null) {
+      throw new ODataSerializerException("ContextURL null!",
+          ODataSerializerException.MessageKeys.NO_CONTEXT_URL);
+    }
+    if (format == ODataFormat.JSON_NO_METADATA) {
+      contextURL = null;
+    }
+    return contextURL;
+  }
+
   protected void writeEntitySet(final EdmEntityType entityType, final EntitySet entitySet,
       final ExpandOption expand, final SelectOption select, final JsonGenerator json)
       throws IOException, ODataSerializerException {
@@ -288,24 +295,30 @@ public class ODataJsonSerializer implements ODataSerializer {
         json.writeNull();
       }
     } else {
-      try {
-        if (edmProperty.isCollection()) {
-          writeCollection(edmProperty, property, selectedPaths, json);
-        } else if (edmProperty.isPrimitive()) {
-          writePrimitive(edmProperty, property, json);
-        } else if (property.isLinkedComplex()) {
-          writeComplexValue(edmProperty, property.asLinkedComplex().getValue(), selectedPaths, json);
-        } else if (property.isComplex()) {
-          writeComplexValue(edmProperty, property.asComplex(), selectedPaths, json);
-        } else {
-          throw new ODataSerializerException("Property type not yet supported!",
-              ODataSerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, edmProperty.getName());
-        }
-      } catch (final EdmPrimitiveTypeException e) {
-        throw new ODataSerializerException("Wrong value for property!", e,
-            ODataSerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
-            edmProperty.getName(), property.getValue().toString());
+      writePropertyValue(edmProperty, property, selectedPaths, json);
+    }
+  }
+
+  private void writePropertyValue(final EdmProperty edmProperty,
+      final Property property, final Set<List<String>> selectedPaths,
+      final JsonGenerator json) throws IOException, ODataSerializerException {
+    try {
+      if (edmProperty.isCollection()) {
+        writeCollection(edmProperty, property, selectedPaths, json);
+      } else if (edmProperty.isPrimitive()) {
+        writePrimitive(edmProperty, property, json);
+      } else if (property.isLinkedComplex()) {
+        writeComplexValue(edmProperty, property.asLinkedComplex().getValue(), selectedPaths, json);
+      } else if (property.isComplex()) {
+        writeComplexValue(edmProperty, property.asComplex(), selectedPaths, json);
+      } else {
+        throw new ODataSerializerException("Property type not yet supported!",
+            ODataSerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, edmProperty.getName());
       }
+    } catch (final EdmPrimitiveTypeException e) {
+      throw new ODataSerializerException("Wrong value for property!", e,
+          ODataSerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
+          edmProperty.getName(), property.getValue().toString());
     }
   }
 
@@ -378,8 +391,15 @@ public class ODataJsonSerializer implements ODataSerializer {
   protected void writeComplexValue(final EdmProperty edmProperty, final List<Property> properties,
       final Set<List<String>> selectedPaths, JsonGenerator json)
       throws IOException, EdmPrimitiveTypeException, ODataSerializerException {
-    final EdmComplexType type = (EdmComplexType) edmProperty.getType();
     json.writeStartObject();
+    writeProperyValues(edmProperty, properties, selectedPaths, json);
+    json.writeEndObject();
+  }
+
+  private void writeProperyValues(final EdmProperty edmProperty,
+      final List<Property> properties, final Set<List<String>> selectedPaths,
+      JsonGenerator json) throws IOException, ODataSerializerException {
+    final EdmComplexType type = (EdmComplexType) edmProperty.getType();
     for (final String propertyName : type.getPropertyNames()) {
       final Property property = findProperty(propertyName, properties);
       if (selectedPaths == null || ExpandSelectHelper.isSelected(selectedPaths, propertyName)) {
@@ -388,7 +408,6 @@ public class ODataJsonSerializer implements ODataSerializer {
             json);
       }
     }
-    json.writeEndObject();
   }
 
   private Property findProperty(final String propertyName, final List<Property> properties) {
@@ -405,4 +424,43 @@ public class ODataJsonSerializer implements ODataSerializer {
       final ExpandOption expand, final SelectOption select) throws ODataSerializerException {
     return ContextURLHelper.buildSelectList(edmEntitySet.getEntityType(), expand, select);
   }
+
+  @Override
+  public InputStream entityProperty(EdmProperty edmProperty,
+      Property property, boolean value, ODataSerializerOptions options)
+      throws ODataSerializerException {
+    final ContextURL contextURL = checkContextURL(options);
+    CircleStreamBuffer buffer = new CircleStreamBuffer();
+    try {
+      JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
+      if (value) {
+        // this is always primitive
+        writePropertyValue(edmProperty, property, null, json);
+      } else {
+        json.writeStartObject();
+        if (format != ODataFormat.JSON_NO_METADATA) {
+          if (contextURL != null) {
+            json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
+          }
+        }
+        if (property.isPrimitive() && property.isNull()) {
+          throw new ODataSerializerException("Property value can not be null",
+              ODataSerializerException.MessageKeys.NULL_INPUT);
+        } else if (property.isComplex() && !property.isNull()) {
+          writeProperyValues(edmProperty, property.asComplex(), null, json);
+        } else if (property.isLinkedComplex() && !property.isNull()) {
+          writeProperyValues(edmProperty, property.asLinkedComplex().getValue(), null, json);
+        } else {
+          json.writeFieldName(Constants.VALUE);
+          writePropertyValue(edmProperty, property, null, json);
+        }
+        json.writeEndObject();
+      }
+      json.close();
+    } catch (final IOException e) {
+      throw new ODataSerializerException("An I/O exception occurred.", e,
+          ODataSerializerException.MessageKeys.IO_EXCEPTION);
+    }
+    return buffer.getInputStream();
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/afebbbbb/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java
index a9c1315..86b29c6 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java
@@ -19,13 +19,19 @@
 package org.apache.olingo.server.core.serializer.utils;
 
 import java.net.URI;
+
 import org.apache.olingo.commons.api.Constants;
 import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.core.Encoder;
 
+/**
+ * Builder to build a context URL (as defined in the <a
+ * href="http://docs.oasis-open.org/odata/odata/v4.0/os/part1-protocol/odata-v4.0-os-part1-protocol.html#_Toc372793655">
+ * protocol specification</a>).
+ */
 public final class ContextURLBuilder {
 
-  public static final URI create(final ContextURL contextURL) {
+  public static URI create(final ContextURL contextURL) {
     StringBuilder result = new StringBuilder();
     if (contextURL.getServiceRoot() != null) {
       result.append(contextURL.getServiceRoot());
@@ -43,6 +49,9 @@ public final class ContextURLBuilder {
     if (contextURL.getSelectList() != null) {
       result.append('(').append(contextURL.getSelectList()).append(')');
     }
+    if (contextURL.getNavOrPropertyPath() != null) {
+      result.append('/').append(contextURL.getNavOrPropertyPath());
+    }
     if (contextURL.isReference()) {
       if (contextURL.getEntitySetOrSingletonOrType() != null) {
         throw new IllegalArgumentException("ContextURL: $ref with Entity Set");

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/afebbbbb/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 c8de547..274b988 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
@@ -22,8 +22,10 @@ import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
 import org.apache.olingo.commons.api.data.ContextURL.Suffix;
+import org.apache.olingo.commons.api.data.Property;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.format.ODataFormat;
 import org.apache.olingo.commons.api.http.HttpHeader;
@@ -41,6 +43,7 @@ import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoResource;
 import org.apache.olingo.server.api.uri.UriResource;
 import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceProperty;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
@@ -50,6 +53,9 @@ import java.io.ByteArrayInputStream;
 import java.util.List;
 import java.util.Locale;
 
+/**
+ * Technical Processor which provides current implemented processor functionality.
+ */
 public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor {
 
   private OData odata;
@@ -84,7 +90,7 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor {
         response.setContent(serializer.entitySet(edmEntitySet, entitySet,
             ODataSerializerOptions.with()
                 .contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
-                    getContextUrl(serializer, edmEntitySet, false, expand, select))
+                    getContextUrl(serializer, edmEntitySet, false, expand, select, null))
                 .count(uriInfo.getCountOption())
                 .expand(expand).select(select)
                 .build()));
@@ -120,7 +126,7 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor {
         response.setContent(serializer.entity(edmEntitySet, entity,
             ODataSerializerOptions.with()
                 .contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
-                    getContextUrl(serializer, edmEntitySet, true, expand, select))
+                    getContextUrl(serializer, edmEntitySet, true, expand, select, null))
                 .count(uriInfo.getCountOption())
                 .expand(expand).select(select)
                 .build()));
@@ -142,9 +148,9 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor {
       EntitySet entitySet = null;
       final UriInfoResource uriResource = uriInfo.asUriInfoResource();
       final List<UriResource> resourceParts = uriResource.getUriResourceParts();
-      if(isCount(resourceParts)) {
+      if (isCount(resourceParts)) {
         int pos = resourceParts.size() - 2;
-        if(pos >= 0) {
+        if (pos >= 0) {
           final UriResourceEntitySet ur =
               (UriResourceEntitySet) uriResource.getUriResourceParts().get(pos);
           entitySet = readEntitySetInternal(ur.getEntitySet(), true);
@@ -165,7 +171,7 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor {
   }
 
   private boolean isCount(List<UriResource> resourceParts) {
-    if(resourceParts.isEmpty()) {
+    if (resourceParts.isEmpty()) {
       return false;
     }
     UriResource part = resourceParts.get(resourceParts.size() - 1);
@@ -180,7 +186,7 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor {
       boolean withCount) throws DataProvider.DataProviderException {
     EntitySet entitySet = dataProvider.readAll(edmEntitySet);
     // TODO: set count (correctly) and next link
-    if(withCount && entitySet.getCount() == null) {
+    if (withCount && entitySet.getCount() == null) {
       entitySet.setCount(entitySet.getEntities().size());
     }
     //
@@ -225,9 +231,58 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor {
 
   private ContextURL getContextUrl(final ODataSerializer serializer,
       final EdmEntitySet entitySet, final boolean isSingleEntity,
-      final ExpandOption expand, final SelectOption select) throws ODataSerializerException {
+      final ExpandOption expand, final SelectOption select, final String navOrPropertyPath)
+      throws ODataSerializerException {
+
     return ContextURL.with().entitySet(entitySet)
         .selectList(serializer.buildContextURLSelectList(entitySet, expand, select))
-        .suffix(isSingleEntity ? Suffix.ENTITY : null).build();
+        .suffix(isSingleEntity ? Suffix.ENTITY : null)
+        .navOrPropertyPath(navOrPropertyPath)
+        .build();
+  }
+
+  @Override
+  public void readEntityProperty(ODataRequest request,
+      ODataResponse response, UriInfo uriInfo, ContentType contentType, boolean value) {
+
+    if (!validateOptions(uriInfo.asUriInfoResource())) {
+      response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode());
+      return;
+    }
+    try {
+      final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource());
+      final Entity entity = readEntityInternal(uriInfo.asUriInfoResource(), edmEntitySet);
+      if (entity == null) {
+        response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
+      } else {
+        UriResourceProperty uriProperty = (UriResourceProperty) uriInfo
+            .getUriResourceParts().get(uriInfo.getUriResourceParts().size() - 1);
+        EdmProperty edmProperty = uriProperty.getProperty();
+        Property property = entity.getProperty(edmProperty.getName());
+        if (property == null) {
+          response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode());
+        } else {
+          if (property.getValue() == null) {
+            response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
+          } else {
+            final ODataFormat format = ODataFormat.fromContentType(contentType);
+            ODataSerializer serializer = odata.createSerializer(format);
+            response.setContent(serializer.entityProperty(edmProperty, property, value,
+                ODataSerializerOptions.with()
+                    .contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
+                        getContextUrl(serializer, edmEntitySet, true, null, null, edmProperty.getName()))
+                    .build()));
+            response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+            response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString());
+          }
+        }
+      }
+    } catch (final DataProvider.DataProviderException e) {
+      response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
+    } catch (final ODataSerializerException e) {
+      response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
+    } catch (final ODataApplicationException e) {
+      response.setStatusCode(e.getStatusCode());
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/afebbbbb/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
index b30ec60..50113a0 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
 import org.apache.commons.io.IOUtils;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.http.HttpContentType;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpMethod;
@@ -39,6 +40,7 @@ import org.apache.olingo.server.api.processor.EntitySetProcessor;
 import org.apache.olingo.server.api.processor.MetadataProcessor;
 import org.apache.olingo.server.api.processor.ServiceDocumentProcessor;
 import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.processor.EntityProcessor;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
 import org.junit.Before;
 import org.junit.Test;
@@ -215,7 +217,7 @@ public class ODataHandlerTest {
     assertNotNull(response);
     assertEquals(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode(), response.getStatusCode());
   }
-  
+
   @Test
   public void testContentNegotiationNotSupported2() {
     ODataRequest request = new ODataRequest();
@@ -252,14 +254,13 @@ public class ODataHandlerTest {
     handler.register(processor);
 
     ODataResponse response = handler.process(request);
-
     assertNotNull(response);
     Mockito.verify(processor).countEntitySet(
         Mockito.eq(request),
         Mockito.any(ODataResponse.class),
         Mockito.any(UriInfo.class));
-  }  
-  
+  }
+
   @Test
   public void testCountWithNavigation() throws Exception {
     ODataRequest request = new ODataRequest();
@@ -271,11 +272,73 @@ public class ODataHandlerTest {
     handler.register(processor);
 
     ODataResponse response = handler.process(request);
-
     assertNotNull(response);
     Mockito.verify(processor).countEntitySet(
         Mockito.eq(request),
         Mockito.any(ODataResponse.class),
         Mockito.any(UriInfo.class));
-  }  
+  }
+
+  @Test
+  public void testAddressPrimitiveProperty() throws Exception {
+    ODataRequest request = new ODataRequest();
+
+    request.setMethod(HttpMethod.GET);
+    request.setRawODataPath("ESAllPrim/PropertyInt16");
+
+    EntityProcessor processor = mock(EntityProcessor.class);
+    handler.register(processor);
+
+    ODataResponse response = handler.process(request);
+    assertNotNull(response);
+
+    Mockito.verify(processor).readEntityProperty(
+        Mockito.any(ODataRequest.class),
+        Mockito.any(ODataResponse.class),
+        Mockito.any(UriInfo.class),
+        Mockito.any(ContentType.class),
+        Mockito.eq(false));
+  }
+
+  @Test
+  public void testAddressPrimitivePropertyValue() throws Exception {
+    ODataRequest request = new ODataRequest();
+
+    request.setMethod(HttpMethod.GET);
+    request.setRawODataPath("ESAllPrim/PropertyInt16/$value");
+
+    EntityProcessor processor = mock(EntityProcessor.class);
+    handler.register(processor);
+
+    ODataResponse response = handler.process(request);
+    assertNotNull(response);
+
+    Mockito.verify(processor).readEntityProperty(
+        Mockito.any(ODataRequest.class),
+        Mockito.any(ODataResponse.class),
+        Mockito.any(UriInfo.class),
+        Mockito.any(ContentType.class),
+        Mockito.eq(true));
+  }
+
+  @Test
+  public void testAddressComplexProperty() throws Exception {
+    ODataRequest request = new ODataRequest();
+
+    request.setMethod(HttpMethod.GET);
+    request.setRawODataPath("ESMixPrimCollComp/PropertyComp");
+
+    EntityProcessor processor = mock(EntityProcessor.class);
+    handler.register(processor);
+
+    ODataResponse response = handler.process(request);
+    assertNotNull(response);
+
+    Mockito.verify(processor).readEntityProperty(
+        Mockito.any(ODataRequest.class),
+        Mockito.any(ODataResponse.class),
+        Mockito.any(UriInfo.class),
+        Mockito.any(ContentType.class),
+        Mockito.eq(false));
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/afebbbbb/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 83e2173..0650480 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
@@ -29,10 +29,13 @@ import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
 import org.apache.olingo.commons.api.data.ValueType;
 import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmElement;
 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.FullQualifiedName;
 import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.core.data.PropertyImpl;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.ODataSerializerException;
@@ -42,6 +45,7 @@ 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.SelectItem;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
+import org.apache.olingo.server.core.edm.provider.EdmPropertyImpl;
 import org.apache.olingo.server.core.serializer.ExpandSelectMock;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
@@ -134,9 +138,9 @@ public class ODataJsonSerializerTest {
       Assert.fail("Expected exception not thrown!");
     } catch (final ODataSerializerException e) {
       Assert.assertEquals(ODataSerializerException.MessageKeys.WRONG_PROPERTY_VALUE, e.getMessageKey());
-       final String message = e.getLocalizedMessage();
-       Assert.assertThat(message, CoreMatchers.containsString("PropertyInt16"));
-       Assert.assertThat(message, CoreMatchers.containsString("false"));
+      final String message = e.getLocalizedMessage();
+      Assert.assertThat(message, CoreMatchers.containsString("PropertyInt16"));
+      Assert.assertThat(message, CoreMatchers.containsString("false"));
     }
   }
 
@@ -391,10 +395,10 @@ public class ODataJsonSerializerTest {
                 .build());
     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\"}}}]}",
+            + "\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp/PropertyString)\","
+            + "\"value\":["
+            + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyString\":\"String 1\"}}},"
+            + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyString\":\"String 2\"}}}]}",
         resultString);
   }
 
@@ -414,10 +418,10 @@ public class ODataJsonSerializerTest {
                 .select(select)
                 .build()));
     Assert.assertEquals("{"
-        + "\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp)\","
-        + "\"value\":["
-        + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyInt16\":123,\"PropertyString\":\"String 1\"}}},"
-        + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyInt16\":987,\"PropertyString\":\"String 2\"}}}]}",
+            + "\"@odata.context\":\"$metadata#ESCompComp(PropertyComp/PropertyComp)\","
+            + "\"value\":["
+            + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyInt16\":123,\"PropertyString\":\"String 1\"}}},"
+            + "{\"PropertyComp\":{\"PropertyComp\":{\"PropertyInt16\":987,\"PropertyString\":\"String 2\"}}}]}",
         resultString);
   }
 
@@ -434,24 +438,24 @@ public class ODataJsonSerializerTest {
             .build());
     final String resultString = IOUtils.toString(result);
     Assert.assertEquals("{\"@odata.context\":\"$metadata#ESTwoPrim/$entity\","
-        + "\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\","
-        + "\"NavPropertyETAllPrimOne\":{"
-        + "\"PropertyInt16\":32767,"
-        + "\"PropertyString\":\"First Resource - positive values\","
-        + "\"PropertyBoolean\":true,"
-        + "\"PropertyByte\":255,"
-        + "\"PropertySByte\":127,"
-        + "\"PropertyInt32\":2147483647,"
-        + "\"PropertyInt64\":9223372036854775807,"
-        + "\"PropertySingle\":1.79E20,"
-        + "\"PropertyDouble\":-1.79E19,"
-        + "\"PropertyDecimal\":34,"
-        + "\"PropertyBinary\":\"ASNFZ4mrze8=\","
-        + "\"PropertyDate\":\"2012-12-03\","
-        + "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\","
-        + "\"PropertyDuration\":\"PT6S\","
-        + "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\","
-        + "\"PropertyTimeOfDay\":\"03:26:05\"}}",
+            + "\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\","
+            + "\"NavPropertyETAllPrimOne\":{"
+            + "\"PropertyInt16\":32767,"
+            + "\"PropertyString\":\"First Resource - positive values\","
+            + "\"PropertyBoolean\":true,"
+            + "\"PropertyByte\":255,"
+            + "\"PropertySByte\":127,"
+            + "\"PropertyInt32\":2147483647,"
+            + "\"PropertyInt64\":9223372036854775807,"
+            + "\"PropertySingle\":1.79E20,"
+            + "\"PropertyDouble\":-1.79E19,"
+            + "\"PropertyDecimal\":34,"
+            + "\"PropertyBinary\":\"ASNFZ4mrze8=\","
+            + "\"PropertyDate\":\"2012-12-03\","
+            + "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\","
+            + "\"PropertyDuration\":\"PT6S\","
+            + "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\","
+            + "\"PropertyTimeOfDay\":\"03:26:05\"}}",
         resultString);
   }
 
@@ -473,9 +477,9 @@ public class ODataJsonSerializerTest {
                 .expand(expand)
                 .build()));
     Assert.assertEquals("{"
-        + "\"@odata.context\":\"$metadata#ESTwoPrim(NavPropertyETAllPrimOne(PropertyDate))/$entity\","
-        + "\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\","
-        + "\"NavPropertyETAllPrimOne\":{\"PropertyDate\":\"2012-12-03\"}}",
+            + "\"@odata.context\":\"$metadata#ESTwoPrim(NavPropertyETAllPrimOne(PropertyDate))/$entity\","
+            + "\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\","
+            + "\"NavPropertyETAllPrimOne\":{\"PropertyDate\":\"2012-12-03\"}}",
         resultString);
   }
 
@@ -500,10 +504,10 @@ public class ODataJsonSerializerTest {
                 .select(select)
                 .build()));
     Assert.assertEquals("{"
-        + "\"@odata.context\":\"$metadata#ESAllPrim(PropertySByte)/$entity\","
-        + "\"PropertySByte\":127,"
-        + "\"NavPropertyETTwoPrimOne\":{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"},"
-        + "\"NavPropertyETTwoPrimMany\":[{\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\"}]}",
+            + "\"@odata.context\":\"$metadata#ESAllPrim(PropertySByte)/$entity\","
+            + "\"PropertySByte\":127,"
+            + "\"NavPropertyETTwoPrimOne\":{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"},"
+            + "\"NavPropertyETTwoPrimMany\":[{\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\"}]}",
         resultString);
   }
 
@@ -526,9 +530,9 @@ public class ODataJsonSerializerTest {
                 .select(select)
                 .build()));
     Assert.assertEquals("{"
-        + "\"@odata.context\":\"$metadata#ESAllPrim(PropertyTimeOfDay)/$entity\","
-        + "\"PropertyTimeOfDay\":\"23:49:14\","
-        + "\"NavPropertyETTwoPrimOne\":null,\"NavPropertyETTwoPrimMany\":[]}",
+            + "\"@odata.context\":\"$metadata#ESAllPrim(PropertyTimeOfDay)/$entity\","
+            + "\"PropertyTimeOfDay\":\"23:49:14\","
+            + "\"NavPropertyETTwoPrimOne\":null,\"NavPropertyETTwoPrimMany\":[]}",
         resultString);
   }
 
@@ -555,15 +559,110 @@ public class ODataJsonSerializerTest {
                 .expand(expand)
                 .build()));
     Assert.assertEquals("{"
-        + "\"@odata.context\":\"$metadata#ESTwoPrim(NavPropertyETAllPrimMany(PropertyInt32))/$entity\","
-        + "\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\","
-        + "\"NavPropertyETAllPrimMany\":["
-        + "{\"PropertyInt32\":-2147483648,\"NavPropertyETTwoPrimOne\":null,\"NavPropertyETTwoPrimMany\":[]},"
-        + "{\"PropertyInt32\":0,\"NavPropertyETTwoPrimOne\":null,"
-        + "\"NavPropertyETTwoPrimMany\":["
-        + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"},"
-        + "{\"PropertyInt16\":-32766,\"PropertyString\":\"Test String3\"},"
-        + "{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"}]}]}",
+            + "\"@odata.context\":\"$metadata#ESTwoPrim(NavPropertyETAllPrimMany(PropertyInt32))/$entity\","
+            + "\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\","
+            + "\"NavPropertyETAllPrimMany\":["
+            + "{\"PropertyInt32\":-2147483648,\"NavPropertyETTwoPrimOne\":null,\"NavPropertyETTwoPrimMany\":[]},"
+            + "{\"PropertyInt32\":0,\"NavPropertyETTwoPrimOne\":null,"
+            + "\"NavPropertyETTwoPrimMany\":["
+            + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"},"
+            + "{\"PropertyInt16\":-32766,\"PropertyString\":\"Test String3\"},"
+            + "{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"}]}]}",
+        resultString);
+  }
+
+  @Test
+  public void individualPrimitiveProperty() throws Exception {
+    final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
+    final EntitySet entitySet = data.readAll(edmEntitySet);
+
+    EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyString");
+    Entity entity = entitySet.getEntities().get(0);
+
+    InputStream result = serializer
+        .entityProperty((EdmProperty) edmElement, entity.getProperty("PropertyString"), false,
+            ODataSerializerOptions.with()
+                .contextURL(ContextURL.with().entitySetOrSingletonOrType("Edm.String")
+                    .build())
+                .build());
+    final String resultString = IOUtils.toString(result);
+    Assert.assertEquals("{"
+            + "\"@odata.context\":\"$metadata#Edm.String\","
+            + "\"value\":\"First Resource - positive values\"}",
+        resultString);
+  }
+
+  @Test(expected = ODataSerializerException.class)
+  public void individualPrimitivePropertyNull() throws Exception {
+    PropertyImpl property = new PropertyImpl("Edm.String", "PropertyString", ValueType.PRIMITIVE, null);
+    final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
+    EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyString");
+    InputStream result = serializer
+        .entityProperty((EdmProperty) edmElement, property, false,
+            ODataSerializerOptions.with()
+                .contextURL(ContextURL.with().entitySetOrSingletonOrType("Edm.String")
+                    .build())
+                .build());
+  }
+
+  @Test
+  public void individualPrimitivePropertyArray() throws Exception {
+    final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
+    final EntitySet entitySet = data.readAll(edmEntitySet);
+
+    EdmElement edmElement = edmEntitySet.getEntityType().getProperty("CollPropertyString");
+    Entity entity = entitySet.getEntities().get(0);
+
+    InputStream result = serializer
+        .entityProperty((EdmProperty) edmElement, entity.getProperty("CollPropertyString"), false,
+            ODataSerializerOptions.with()
+                .contextURL(ContextURL.with().entitySetOrSingletonOrType("Collection(Edm.String)")
+                    .build())
+                .build());
+    final String resultString = IOUtils.toString(result);
+    Assert.assertEquals("{"
+            + "\"@odata.context\":\"$metadata#Collection%28Edm.String%29\","
+            + "\"value\":[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"]}",
+        resultString);
+  }
+
+  @Test
+  public void individualPrimitivePropertyValue() throws Exception {
+    final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
+    final EntitySet entitySet = data.readAll(edmEntitySet);
+
+    EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyString");
+    Entity entity = entitySet.getEntities().get(0);
+
+    InputStream result = serializer
+        .entityProperty((EdmProperty) edmElement, entity.getProperty("PropertyString"), true,
+            ODataSerializerOptions.with()
+                .contextURL(ContextURL.with().entitySetOrSingletonOrType("ESAllPrim(1)")
+                    .navOrPropertyPath("PropertyString")
+                    .build())
+                .build());
+    final String resultString = IOUtils.toString(result);
+    Assert.assertEquals("\"First Resource - positive values\"", resultString);
+  }
+
+  @Test
+  public void individualComplexProperty() throws Exception {
+    final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp");
+    final EntitySet entitySet = data.readAll(edmEntitySet);
+
+    EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyComp");
+    Entity entity = entitySet.getEntities().get(0);
+
+    InputStream result = serializer
+        .entityProperty((EdmProperty) edmElement, entity.getProperty("PropertyComp"), false,
+            ODataSerializerOptions.with()
+                .contextURL(ContextURL.with().entitySetOrSingletonOrType("ESMixPrimCollComp.PropertyComp")
+                    .build())
+                .build());
+    final String resultString = IOUtils.toString(result);
+    Assert.assertEquals("{"
+            + "\"@odata.context\":\"$metadata#ESMixPrimCollComp.PropertyComp\","
+            + "\"PropertyInt16\":111,\"PropertyString\":\"TEST A\"}",
         resultString);
   }
 }