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/08 11:04:42 UTC

git commit: [OLINGO-444] - Adding the ablity to add key predicates to Context URL - Fixed the wrong ContextURL with readProperty in TechnicalProcessor class - Added unit tests for ContextURL, and integration tests for PropertyProcessor's readProperty & r

Repository: olingo-odata4
Updated Branches:
  refs/heads/master 541d76652 -> bc0129490


[OLINGO-444] - Adding the ablity to add key predicates to Context URL - Fixed the wrong ContextURL with readProperty in TechnicalProcessor class - Added unit tests for ContextURL, and integration tests for PropertyProcessor's readProperty & readPropertyValue methods

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/bc012949
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/bc012949
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/bc012949

Branch: refs/heads/master
Commit: bc0129490be7ba29ec7f6ba5dbd77b91d6778086
Parents: 541d766
Author: Ramesh Reddy <ra...@jboss.org>
Authored: Tue Oct 7 09:52:46 2014 -0500
Committer: Michael Bolz <mi...@sap.com>
Committed: Wed Oct 8 11:02:09 2014 +0200

----------------------------------------------------------------------
 .../olingo/fit/tecsvc/client/BasicITCase.java   | 107 +++++++++++++++++++
 .../olingo/commons/api/data/ContextURL.java     |  53 ++++++++-
 .../serializer/utils/ContextURLBuilder.java     |  12 ++-
 .../serializer/utils/ContextURLBuilderTest.java |  81 ++++++++++++++
 .../olingo/server/tecsvc/data/DataProvider.java |   2 +-
 .../tecsvc/processor/TechnicalProcessor.java    |  53 ++++++---
 .../json/ODataJsonSerializerTest.java           |   4 +-
 7 files changed, 295 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bc012949/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
index f7097a3..46a6b96 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
@@ -36,6 +36,7 @@ import org.apache.olingo.client.api.communication.ODataClientErrorException;
 import org.apache.olingo.client.api.communication.request.retrieve.EdmMetadataRequest;
 import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest;
 import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
+import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest;
 import org.apache.olingo.client.api.communication.request.retrieve.ODataServiceDocumentRequest;
 import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
 import org.apache.olingo.client.api.v4.ODataClient;
@@ -177,6 +178,112 @@ public class BasicITCase extends AbstractBaseTestITCase {
         + "}";
     assertEquals(expectedResult, IOUtils.toString(response.getRawResponse(), "UTF-8"));
   }
+  
+  @Test
+  public void readSimpleProperty() throws Exception {
+    ODataPropertyRequest<ODataProperty> request = getClient().getRetrieveRequestFactory()
+        .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI)            
+            .appendEntitySetSegment("ESTwoPrim")
+            .appendKeySegment(32766)
+            .appendPropertySegment("PropertyString")
+            .build());
+    
+    assertNotNull(request);
+
+    ODataRetrieveResponse<ODataProperty> response = request.execute();
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+    assertThat(response.getContentType(), containsString(ContentType.APPLICATION_JSON.toContentTypeString()));
+
+    final ODataProperty property = response.getBody();
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertEquals("Test String1", property.getPrimitiveValue().toValue());
+  }
+  
+  @Test
+  public void readSimplePropertyContextURL() throws Exception {
+    ODataPropertyRequest<ODataProperty> request = getClient().getRetrieveRequestFactory()
+        .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI)            
+            .appendEntitySetSegment("ESTwoPrim")
+            .appendKeySegment(32766)
+            .appendPropertySegment("PropertyString")
+            .build());    
+    ODataRetrieveResponse<ODataProperty> response = request.execute();
+    String expectedResult = 
+        "{\"@odata.context\":\"$metadata#ESTwoPrim(32766)/PropertyString\"," +
+        "\"value\":\"Test String1\"}";
+    assertEquals(expectedResult, IOUtils.toString(response.getRawResponse(), "UTF-8"));    
+  }  
+  
+  @Test
+  public void readComplexProperty() throws Exception {
+    ODataPropertyRequest<ODataProperty> request = getClient().getRetrieveRequestFactory()
+        .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI)            
+            .appendEntitySetSegment("ESMixPrimCollComp")
+            .appendKeySegment(7)
+            .appendPropertySegment("PropertyComp")
+            .build());    
+    ODataRetrieveResponse<ODataProperty> response = request.execute();
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+    assertThat(response.getContentType(), containsString(ContentType.APPLICATION_JSON.toContentTypeString()));
+
+    final ODataProperty property = response.getBody();
+    assertNotNull(property);
+    assertNotNull(property.getComplexValue());
+    assertEquals("TEST B", property.getComplexValue().get("PropertyString").getPrimitiveValue().toValue());   
+  }  
+  
+  @Test
+  public void readComplexPropertyContextURL() throws Exception {
+    ODataPropertyRequest<ODataProperty> request = getClient().getRetrieveRequestFactory()
+        .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI)            
+            .appendEntitySetSegment("ESMixPrimCollComp")
+            .appendKeySegment(7)
+            .appendPropertySegment("PropertyComp")
+            .build());    
+    ODataRetrieveResponse<ODataProperty> response = request.execute();
+    String expectedResult = 
+        "{\"@odata.context\":\"$metadata#ESMixPrimCollComp(7)/PropertyComp\"," +
+        "\"PropertyInt16\":222,\"PropertyString\":\"TEST B\"}";
+    assertEquals(expectedResult, IOUtils.toString(response.getRawResponse(), "UTF-8"));    
+  }  
+  
+  @Test(expected=ODataClientErrorException.class)
+  public void readUnknownProperty() throws Exception {
+    ODataPropertyRequest<ODataProperty> request = getClient().getRetrieveRequestFactory()
+        .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI)            
+            .appendEntitySetSegment("ESTwoPrim")
+            .appendKeySegment(32766)
+            .appendPropertySegment("Unknown")
+            .build());    
+    ODataRetrieveResponse<ODataProperty> response = request.execute();
+    assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), response.getStatusCode());
+  }   
+  
+  @Test
+  public void readNoContentProperty() throws Exception {
+    ODataPropertyRequest<ODataProperty> request = getClient().getRetrieveRequestFactory()
+        .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI)            
+            .appendEntitySetSegment("ESTwoPrim")
+            .appendKeySegment(-32766)
+            .appendPropertySegment("PropertyString")
+            .build());    
+    ODataRetrieveResponse<ODataProperty> response = request.execute();
+    assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), response.getStatusCode());
+  }   
+  
+  @Test
+  public void readPropertyValue() throws Exception {
+    ODataPropertyRequest<ODataProperty> request = getClient().getRetrieveRequestFactory()
+        .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI)            
+            .appendEntitySetSegment("ESTwoPrim")
+            .appendKeySegment(32766)
+            .appendPropertySegment("PropertyString")
+            .appendValueSegment()
+            .build());    
+    ODataRetrieveResponse<ODataProperty> response = request.execute();
+    assertEquals("Test String1", IOUtils.toString(response.getRawResponse(), "UTF-8"));
+  }   
 
   @Override
   protected CommonODataClient<?> getClient() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bc012949/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
index 7b750de..476da10 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
@@ -19,9 +19,11 @@
 package org.apache.olingo.commons.api.data;
 
 import java.net.URI;
+import java.util.Map;
 
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmType;
 
 /**
  * High-level representation of a context URL, built from the string value returned by a service; provides access to the
@@ -35,11 +37,17 @@ public class ContextURL {
 
   private String entitySetOrSingletonOrType;
 
+  private boolean isCollection = false;
+
   private String derivedEntity;
 
   private String selectList;
 
   private String navOrPropertyPath;
+  
+  private String keyPath;
+
+  private Suffix suffix;
 
   public enum Suffix {
 
@@ -57,7 +65,6 @@ public class ContextURL {
     }
   }
 
-  private Suffix suffix;
 
   private ContextURL() {
   }
@@ -70,6 +77,10 @@ public class ContextURL {
     return entitySetOrSingletonOrType;
   }
 
+  public boolean isCollection() {
+    return isCollection;
+  }
+
   public String getDerivedEntity() {
     return derivedEntity;
   }
@@ -81,6 +92,10 @@ public class ContextURL {
   public String getNavOrPropertyPath() {
     return navOrPropertyPath;
   }
+  
+  public String getKeyPath() {
+    return keyPath;
+  }  
 
   public Suffix getSuffix() {
     return suffix;
@@ -127,11 +142,47 @@ public class ContextURL {
       contextURL.entitySetOrSingletonOrType = entitySet.getName();
       return this;
     }
+    
+    public Builder keySegment(Object value) {
+      if (value != null) {
+        contextURL.keyPath = String.valueOf(value);
+      }
+      return this;
+    }  
+    
+    public Builder keySegment(Map<String, Object> values) {
+      if (values != null && !values.isEmpty()) {
+        
+        if (values.size() == 1) {
+          return keySegment(values.values().iterator().next());
+        }
+        
+        StringBuilder sb = new StringBuilder();
+        for (String key:values.keySet()) {
+          if (sb.length() > 0) {
+            sb.append(",");
+          }
+          sb.append(key).append("=").append(values.get(key));
+        }
+        contextURL.keyPath = sb.toString();
+      }
+      return this;
+    }      
 
     public Builder entitySetOrSingletonOrType(final String entitySetOrSingletonOrType) {
       contextURL.entitySetOrSingletonOrType = entitySetOrSingletonOrType;
       return this;
     }
+    
+    public Builder propertyType(final EdmType type) {
+      contextURL.entitySetOrSingletonOrType = type.getFullQualifiedName().toString();
+      return this;
+    }
+
+    public Builder asCollection() {
+      contextURL.isCollection = true;
+      return this;
+    }
 
     public Builder derived(final EdmEntityType derivedType) {
       contextURL.derivedEntity = derivedType.getFullQualifiedName().getFullQualifiedNameAsString();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bc012949/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 86b29c6..9bfac40 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
@@ -38,7 +38,14 @@ public final class ContextURLBuilder {
     }
     result.append(Constants.METADATA);
     if (contextURL.getEntitySetOrSingletonOrType() != null) {
-      result.append('#').append(Encoder.encode(contextURL.getEntitySetOrSingletonOrType()));
+      result.append('#');
+      if(contextURL.isCollection()) {
+        result.append("Collection(")
+                .append(Encoder.encode(contextURL.getEntitySetOrSingletonOrType()))
+                .append(")");
+      } else {
+        result.append(Encoder.encode(contextURL.getEntitySetOrSingletonOrType()));
+      }
     }
     if (contextURL.getDerivedEntity() != null) {
       if (contextURL.getEntitySetOrSingletonOrType() == null) {
@@ -46,6 +53,9 @@ public final class ContextURLBuilder {
       }
       result.append('/').append(Encoder.encode(contextURL.getDerivedEntity()));
     }
+    if (contextURL.getKeyPath() != null) {
+      result.append('(').append(contextURL.getKeyPath()).append(')');
+    }
     if (contextURL.getSelectList() != null) {
       result.append('(').append(contextURL.getSelectList()).append(')');
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bc012949/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
index bc136f4..a8b5e71 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
@@ -19,13 +19,28 @@
 package org.apache.olingo.server.core.serializer.utils;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TreeMap;
+
 import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.ContextURL.Suffix;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
+import org.apache.olingo.server.api.edm.provider.ComplexType;
+import org.apache.olingo.server.api.edm.provider.EdmProvider;
+import org.apache.olingo.server.api.edm.provider.NavigationProperty;
+import org.apache.olingo.server.api.edm.provider.Property;
+import org.apache.olingo.server.core.edm.provider.EdmComplexTypeImpl;
+import org.apache.olingo.server.core.edm.provider.EdmProviderImpl;
 import org.junit.Test;
 import org.mockito.Mockito;
 
@@ -89,6 +104,72 @@ public class ContextURLBuilderTest {
     assertEquals("http://host/service/$metadata#Customers/Model.VipCustomer/$entity",
         ContextURLBuilder.create(contextURL).toASCIIString());
   }
+  
+  @Test
+  public void buildPropertyValue() {
+    EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
+    Mockito.when(entitySet.getName()).thenReturn("Customers");
+    ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
+        .entitySet(entitySet)
+        .keySegment(1)
+        .navOrPropertyPath("Name")
+        .build();
+    assertEquals("http://host/service/$metadata#Customers(1)/Name",
+        ContextURLBuilder.create(contextURL).toASCIIString());
+    TreeMap<String, Object> keys = new TreeMap<String, Object>();
+    keys.put("one", 1);
+    keys.put("two", "'two'");
+    contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
+        .entitySet(entitySet)
+        .keySegment(keys)
+        .navOrPropertyPath("Name")
+        .build();
+    assertEquals("http://host/service/$metadata#Customers(one=1,two='two')/Name",
+        ContextURLBuilder.create(contextURL).toASCIIString());
+  }  
+  
+  @Test
+  public void buildPrimitiveType() {
+    EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
+    Mockito.when(entitySet.getName()).thenReturn("Customers");
+    ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
+        .propertyType(EdmString.getInstance())
+        .build();
+    assertEquals("http://host/service/$metadata#Edm.String",
+        ContextURLBuilder.create(contextURL).toASCIIString());
+    
+    contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
+        .propertyType(EdmString.getInstance()).asCollection()
+        .build();
+    assertEquals("http://host/service/$metadata#Collection(Edm.String)",
+        ContextURLBuilder.create(contextURL).toString());
+  }  
+  
+  @Test
+  public void buildComplexType() throws Exception {
+    EdmProvider provider = mock(EdmProvider.class);
+    EdmProviderImpl edm = new EdmProviderImpl(provider);
+
+    FullQualifiedName baseName = new FullQualifiedName("namespace", "BaseTypeName");
+    ComplexType baseComplexType = new ComplexType();
+    List<Property> baseProperties = new ArrayList<Property>();
+    baseProperties.add(new Property().setName("prop1").setType(EdmPrimitiveTypeKind.String.getFullQualifiedName()));
+    List<NavigationProperty> baseNavigationProperties = new ArrayList<NavigationProperty>();
+    baseNavigationProperties.add(new NavigationProperty().setName("nav1"));
+    baseComplexType.setName("BaseTypeName").setAbstract(false).setOpenType(false).setProperties(baseProperties)
+        .setNavigationProperties(baseNavigationProperties);
+    when(provider.getComplexType(baseName)).thenReturn(baseComplexType);
+
+    EdmComplexType baseType = EdmComplexTypeImpl.getInstance(edm, baseName, baseComplexType);    
+    
+    EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
+    Mockito.when(entitySet.getName()).thenReturn("Customers");
+    ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
+        .propertyType(baseType)
+        .build();
+    assertEquals("http://host/service/$metadata#namespace.BaseTypeName",
+        ContextURLBuilder.create(contextURL).toASCIIString());    
+  }  
 
   @Test(expected = IllegalArgumentException.class)
   public void buildSuffixWithoutEntitySet() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bc012949/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 f4120db..e8deff3 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
@@ -131,7 +131,7 @@ public class DataProvider {
 
     entitySet.getEntities().add(new EntityImpl()
         .addProperty(createPrimitive("PropertyInt16", -32766))
-        .addProperty(createPrimitive("PropertyString", "Test String3")));
+        .addProperty(createPrimitive("PropertyString", null)));
 
     entitySet.getEntities().add(new EntityImpl()
         .addProperty(createPrimitive("PropertyInt16", Short.MAX_VALUE))

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bc012949/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 17ae201..63a59c3 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
@@ -18,13 +18,21 @@
  */
 package org.apache.olingo.server.tecsvc.processor;
 
+import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TreeMap;
+
 import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.ContextURL.Suffix;
 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.EdmEntityType;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
 import org.apache.olingo.commons.api.edm.EdmProperty;
@@ -37,14 +45,15 @@ import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
-import org.apache.olingo.server.api.processor.EntitySetProcessor;
 import org.apache.olingo.server.api.processor.EntityProcessor;
+import org.apache.olingo.server.api.processor.EntitySetProcessor;
 import org.apache.olingo.server.api.processor.PropertyProcessor;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.uri.UriInfo;
 import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriParameter;
 import org.apache.olingo.server.api.uri.UriResource;
 import org.apache.olingo.server.api.uri.UriResourceEntitySet;
 import org.apache.olingo.server.api.uri.UriResourceKind;
@@ -53,11 +62,6 @@ import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
 
-import java.io.ByteArrayInputStream;
-import java.io.UnsupportedEncodingException;
-import java.util.List;
-import java.util.Locale;
-
 /**
  * Technical Processor which provides currently implemented processor functionality.
  */
@@ -212,14 +216,38 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
         .navOrPropertyPath(propertyPath)
         .build();
   }
-
+  
+  private Map<String, Object> getKeys(EdmEntityType entityType,
+      List<UriParameter> parameters) throws ODataApplicationException {
+    TreeMap<String, Object> keys = new TreeMap<String, Object>();
+    for (UriParameter param: parameters) {
+      final EdmProperty property = (EdmProperty) entityType.getProperty(param.getName());
+      final EdmPrimitiveType type = (EdmPrimitiveType) property.getType();
+      try {
+        Object keyValue = type.valueOfString(param.getText(),
+            property.isNullable(), property.getMaxLength(), property.getPrecision(), property.getScale(),
+            property.isUnicode(), type.getDefaultType());
+        if (keyValue instanceof String) {
+          keyValue = "'"+keyValue+"'";
+        }
+        keys.put(param.getName(), keyValue);
+      } catch (EdmPrimitiveTypeException e) {
+        throw new ODataApplicationException("Invalid key found", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+                Locale.ROOT, e);
+      }
+    }
+    return keys;
+  }
+  
   @Override
   public void readProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
       final ContentType contentType) throws ODataApplicationException, SerializerException {
     validateOptions(uriInfo.asUriInfoResource());
 
     final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource());
+    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0);
     final Entity entity = readEntityInternal(uriInfo.asUriInfoResource(), edmEntitySet);
+
     if (entity == null) {
       throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
     } else {
@@ -236,10 +264,11 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
           final ODataFormat format = ODataFormat.fromContentType(contentType);
           ODataSerializer serializer = odata.createSerializer(format);
           response.setContent(serializer.entityProperty(edmProperty, property,
-              ODataSerializerOptions.with()
-                  .contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
-                      getContextUrl(serializer, edmEntitySet, true, null, null, edmProperty.getName()))
-                  .build()));
+              ODataSerializerOptions.with().contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
+                    ContextURL.with().entitySet(edmEntitySet)
+                            .keySegment(getKeys(edmEntitySet.getEntityType(), resourceEntitySet.getKeyPredicates()))
+                            .navOrPropertyPath(edmProperty.getName())
+                            .build()).build()));
           response.setStatusCode(HttpStatusCode.OK.getStatusCode());
           response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString());
         }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bc012949/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 7835b7a..36e3887 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
@@ -302,7 +302,7 @@ public class ODataJsonSerializerTest {
     final String expectedResult = "{\"value\":["
         + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"},"
         + "{\"PropertyInt16\":-365,\"PropertyString\":\"Test String2\"},"
-        + "{\"PropertyInt16\":-32766,\"PropertyString\":\"Test String3\"},"
+        + "{\"PropertyInt16\":-32766,\"PropertyString\":null},"
         + "{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"}]}";
     Assert.assertEquals(expectedResult, resultString);
   }
@@ -566,7 +566,7 @@ public class ODataJsonSerializerTest {
             + "{\"PropertyInt32\":0,\"NavPropertyETTwoPrimOne\":null,"
             + "\"NavPropertyETTwoPrimMany\":["
             + "{\"PropertyInt16\":32766,\"PropertyString\":\"Test String1\"},"
-            + "{\"PropertyInt16\":-32766,\"PropertyString\":\"Test String3\"},"
+            + "{\"PropertyInt16\":-32766,\"PropertyString\":null},"
             + "{\"PropertyInt16\":32767,\"PropertyString\":\"Test String4\"}]}]}",
         resultString);
   }