You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2015/01/14 09:29:09 UTC

olingo-odata4 git commit: [OLINGO-530] Entity and EntitySet deserialization

Repository: olingo-odata4
Updated Branches:
  refs/heads/master ab39763f3 -> 2ac6ba18b


[OLINGO-530] Entity and EntitySet deserialization


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

Branch: refs/heads/master
Commit: 2ac6ba18bba09f3154584a16a49439a9eb5fb959
Parents: ab39763
Author: Christian Amend <ch...@apache.org>
Authored: Wed Jan 14 09:20:27 2015 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Wed Jan 14 09:21:08 2015 +0100

----------------------------------------------------------------------
 .../org/apache/olingo/server/api/OData.java     |   4 +
 .../api/deserializer/DeserializerException.java |  13 +-
 .../api/deserializer/ODataDeserializer.java     |  33 ++
 .../apache/olingo/server/core/ODataImpl.java    |  22 +
 .../json/ODataJsonDeserializer.java             | 523 +++++++++++++++++++
 .../json/ODataJsonDeserializerBasicTest.java    |  44 ++
 .../json/AbstractODataDeserializerTest.java     |  42 ++
 .../json/ODataDeserializerDeepInsertTest.java   |  69 +++
 .../json/ODataDeserializerEntitySetTest.java    |  83 +++
 .../json/ODataJsonDeserializerEntityTest.java   | 236 +++++++++
 .../src/test/resources/ESAllPrim.json           |  56 ++
 .../src/test/resources/ESCompCollComp.json      |  35 ++
 ...AllPrimExpandedNavPropertyETTwoPrimMany.json |  24 +
 ...SAllPrimExpandedNavPropertyETTwoPrimOne.json |  23 +
 14 files changed, 1206 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java
index 47dcd8f..eddd0da 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java
@@ -22,7 +22,9 @@ import java.util.List;
 
 import org.apache.olingo.commons.api.ODataRuntimeException;
 import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
 import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer;
+import org.apache.olingo.server.api.deserializer.ODataDeserializer;
 import org.apache.olingo.server.api.edm.provider.EdmProvider;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
@@ -96,4 +98,6 @@ public abstract class OData {
    * It can be used in Processor implementations.
    */
   public abstract UriHelper createUriHelper();
+
+  public abstract ODataDeserializer createDeserializer(ODataFormat format) throws DeserializerException;
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/DeserializerException.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/DeserializerException.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/DeserializerException.java
index 2e4e7bc..2475125 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/DeserializerException.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/DeserializerException.java
@@ -28,7 +28,18 @@ public class DeserializerException extends ODataTranslatedException {
   /** Keys for exception texts in the resource bundle. */
   public static enum MessageKeys implements MessageKey {
     NOT_IMPLEMENTED,
-    IO_EXCEPTION;
+    IO_EXCEPTION,
+    //TODO: create texts for the following message keys:
+    /** parameter: format */ UNSUPPORTED_FORMAT, 
+    JSON_SYNTAX_EXCEPTION, 
+    /** parameter: propertyName */ INVALID_NULL_PROPERTY, 
+    TREE_NOT_EMPTY, 
+    /** parameter: propertyName */ INVALID_VALUE_FOR_PROPERTY, 
+    /** parameter: propertyName */ INVALID_TYPE_FOR_PROPERTY, 
+    VALUE_ARRAY_NOT_PRESENT, 
+    VALUE_TAG_MUST_BE_AN_ARRAY, 
+    INVALID_ENTITY, 
+    /** parameter: navigationPropertyName */INVALID_VALUE_FOR_NAVIGATION_PROPERTY;
 
     @Override
     public String getKey() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java
new file mode 100644
index 0000000..a312221
--- /dev/null
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.api.deserializer;
+
+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.edm.EdmEntityType;
+
+public interface ODataDeserializer {
+
+  Entity entity(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException;
+
+  EntitySet entitySet(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException;
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
index 1a8bfca..1551461 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
@@ -25,7 +25,9 @@ import org.apache.olingo.commons.api.format.ODataFormat;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataHttpHandler;
 import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
 import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer;
+import org.apache.olingo.server.api.deserializer.ODataDeserializer;
 import org.apache.olingo.server.api.edm.provider.EdmProvider;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
@@ -33,6 +35,7 @@ import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.uri.UriHelper;
 import org.apache.olingo.server.core.deserializer.FixedFormatDeserializerImpl;
+import org.apache.olingo.server.core.deserializer.json.ODataJsonDeserializer;
 import org.apache.olingo.server.core.serializer.FixedFormatSerializerImpl;
 import org.apache.olingo.server.core.serializer.json.ODataJsonSerializer;
 import org.apache.olingo.server.core.serializer.xml.ODataXmlSerializerImpl;
@@ -84,4 +87,23 @@ public class ODataImpl extends OData {
   public UriHelper createUriHelper() {
     return new UriHelperImpl();
   }
+
+  @Override
+  public ODataDeserializer createDeserializer(ODataFormat format) throws DeserializerException{
+    ODataDeserializer serializer;
+    switch (format) {
+    case JSON:
+    case JSON_NO_METADATA:
+    case JSON_FULL_METADATA:
+      serializer = new ODataJsonDeserializer();
+      break;
+    case XML:
+      //We do not support xml deserialization right now so this mus lead to an error
+    default:
+      throw new DeserializerException("Unsupported format: " + format,
+          SerializerException.MessageKeys.UNSUPPORTED_FORMAT, format.toString());
+    }
+
+    return serializer;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
new file mode 100644
index 0000000..bca290a
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
@@ -0,0 +1,523 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core.deserializer.json;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.olingo.commons.api.Constants;
+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.Property;
+import org.apache.olingo.commons.api.data.ValueType;
+import org.apache.olingo.commons.api.domain.ODataLinkType;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmEnumType;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+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.PropertyImpl;
+import org.apache.olingo.commons.core.edm.EdmTypeInfo;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.deserializer.ODataDeserializer;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class ODataJsonDeserializer implements ODataDeserializer {
+
+  @Override
+  public EntitySet entitySet(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException {
+    try {
+      JsonParser parser = new JsonFactory(new ObjectMapper()).createParser(stream);
+      final ObjectNode tree = parser.getCodec().readTree(parser);
+
+      return consumeEntitySetNode(edmEntityType, tree);
+    } catch (JsonParseException e) {
+      throw new DeserializerException("An JsonParseException occourred", e,
+          DeserializerException.MessageKeys.JSON_SYNTAX_EXCEPTION);
+    } catch (IOException e) {
+      throw new DeserializerException("An IOException occourred", e, DeserializerException.MessageKeys.IO_EXCEPTION);
+    }
+  }
+
+  private EntitySet consumeEntitySetNode(EdmEntityType edmEntityType, final ObjectNode tree)
+      throws DeserializerException {
+    EntitySetImpl entitySet = new EntitySetImpl();
+    // Consume entitySet annotations
+    consumeODataEntitySetAnnotations(tree, entitySet);
+
+    // Consume entities
+    JsonNode jsonNode = tree.get(Constants.VALUE);
+    if (jsonNode != null) {
+      if (jsonNode.isArray() == false) {
+        throw new DeserializerException("The content of the value tag must be an Array but is not. ",
+            DeserializerException.MessageKeys.VALUE_TAG_MUST_BE_AN_ARRAY);
+      }
+
+      consumeEntitySetArray(entitySet, edmEntityType, jsonNode);
+      tree.remove(Constants.VALUE);
+    } else {
+      throw new DeserializerException("Could not find value array.",
+          DeserializerException.MessageKeys.VALUE_ARRAY_NOT_PRESENT);
+    }
+
+    if (tree.size() != 0) {
+      throw new DeserializerException("Tree should be empty but still has content left.",
+          DeserializerException.MessageKeys.TREE_NOT_EMPTY);
+    }
+    return entitySet;
+  }
+
+  private void consumeEntitySetArray(EntitySetImpl entitySet, EdmEntityType edmEntityType, JsonNode jsonNode)
+      throws DeserializerException {
+    Iterator<JsonNode> arrayIterator = jsonNode.iterator();
+    while (arrayIterator.hasNext()) {
+      JsonNode arrayElement = (JsonNode) arrayIterator.next();
+      if (arrayElement.isContainerNode() && arrayElement.isArray()) {
+        throw new DeserializerException("Nested Arrays and primitive values are not allowed for an entity value.",
+            DeserializerException.MessageKeys.INVALID_ENTITY);
+      }
+
+      entitySet.getEntities().add(consumeEntityNode(edmEntityType, (ObjectNode) arrayElement));
+    }
+  }
+
+  private void consumeODataEntitySetAnnotations(final ObjectNode tree, EntitySetImpl entitySet) {
+    URI contextURL;
+    if (tree.hasNonNull(Constants.JSON_CONTEXT)) {
+      contextURL = URI.create(tree.get(Constants.JSON_CONTEXT).textValue());
+      tree.remove(Constants.JSON_CONTEXT);
+    } else if (tree.hasNonNull(Constants.JSON_METADATA)) {
+      contextURL = URI.create(tree.get(Constants.JSON_METADATA).textValue());
+      tree.remove(Constants.JSON_METADATA);
+    } else {
+      contextURL = null;
+    }
+    if (contextURL != null) {
+      entitySet.setBaseURI(StringUtils.substringBefore(contextURL.toASCIIString(), Constants.METADATA));
+    }
+
+    if (tree.hasNonNull(Constants.JSON_COUNT)) {
+      entitySet.setCount(tree.get(Constants.JSON_COUNT).asInt());
+      tree.remove(Constants.JSON_COUNT);
+    }
+    if (tree.hasNonNull(Constants.JSON_NEXT_LINK)) {
+      entitySet.setNext(URI.create(tree.get(Constants.JSON_NEXT_LINK).textValue()));
+      tree.remove(Constants.JSON_NEXT_LINK);
+    }
+    if (tree.hasNonNull(Constants.JSON_DELTA_LINK)) {
+      entitySet.setDeltaLink(URI.create(tree.get(Constants.JSON_DELTA_LINK).textValue()));
+      tree.remove(Constants.JSON_DELTA_LINK);
+    }
+  }
+
+  @Override
+  public Entity entity(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException {
+    try {
+      JsonParser parser = new JsonFactory(new ObjectMapper()).createParser(stream);
+      final ObjectNode tree = parser.getCodec().readTree(parser);
+
+      return consumeEntityNode(edmEntityType, tree);
+
+    } catch (JsonParseException e) {
+      throw new DeserializerException("An JsonParseException occourred", e,
+          DeserializerException.MessageKeys.JSON_SYNTAX_EXCEPTION);
+    } catch (IOException e) {
+      throw new DeserializerException("An IOException occourred", e, DeserializerException.MessageKeys.IO_EXCEPTION);
+    }
+
+  }
+
+  private Entity consumeEntityNode(EdmEntityType edmEntityType, final ObjectNode tree) throws DeserializerException {
+    EntityImpl entity = new EntityImpl();
+    entity.setType(edmEntityType.getFullQualifiedName().getFullQualifiedNameAsString());
+
+    // Check and consume all Properties
+    List<String> propertyNames = edmEntityType.getPropertyNames();
+    for (String propertyName : propertyNames) {
+      JsonNode jsonNode = tree.get(propertyName);
+      if (jsonNode != null) {
+        EdmProperty edmProperty = (EdmProperty) edmEntityType.getProperty(propertyName);
+        if (jsonNode.isNull() == true && edmProperty.isNullable() != null
+            && edmProperty.isNullable().booleanValue() == false) {
+          throw new DeserializerException("Property: " + propertyName + " must not be null.",
+              DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, propertyName);
+        }
+        Property property = consumePropertyNode(edmProperty, jsonNode);
+        entity.addProperty(property);
+        tree.remove(propertyName);
+      }
+    }
+
+    // Check and consume all expanded Navigation Properties
+    List<String> navigationPropertyNames = edmEntityType.getNavigationPropertyNames();
+    for (String navigationPropertyName : navigationPropertyNames) {
+      // read expanded navigation property
+      JsonNode jsonNode = tree.get(navigationPropertyName);
+      if (jsonNode != null) {
+        EdmNavigationProperty edmNavigationProperty = edmEntityType.getNavigationProperty(navigationPropertyName);
+        if (jsonNode.isNull() == true && edmNavigationProperty.isNullable() != null
+            && edmNavigationProperty.isNullable().booleanValue() == false) {
+          throw new DeserializerException("Property: " + navigationPropertyName + " must not be null.",
+              DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, navigationPropertyName);
+        }
+
+        LinkImpl link = new LinkImpl();
+        link.setTitle(navigationPropertyName);
+        if (jsonNode.isArray() && edmNavigationProperty.isCollection()) {
+          link.setType(ODataLinkType.ENTITY_SET_NAVIGATION.toString());
+          EntitySetImpl inlineEntitySet = new EntitySetImpl();
+          consumeEntitySetArray(inlineEntitySet, edmNavigationProperty.getType(), jsonNode);
+          link.setInlineEntitySet(inlineEntitySet);
+        } else if (!jsonNode.isArray() && !jsonNode.isValueNode() && !edmNavigationProperty.isCollection()) {
+          link.setType(ODataLinkType.ENTITY_NAVIGATION.toString());
+          if (!jsonNode.isNull()) {
+            Entity inlineEntity = consumeEntityNode(edmNavigationProperty.getType(), (ObjectNode) jsonNode);
+            link.setInlineEntity(inlineEntity);
+          }
+        } else {
+          throw new DeserializerException("Invalid value: " + jsonNode.getNodeType()
+              + " for expanded navigation porperty: " + navigationPropertyName,
+              DeserializerException.MessageKeys.INVALID_VALUE_FOR_NAVIGATION_PROPERTY, navigationPropertyName);
+        }
+        entity.getNavigationLinks().add(link);
+        tree.remove(navigationPropertyName);
+      }
+    }
+
+    // Check and consume all Annotations
+    consumeODataEntityAnnotations(tree, entity, edmEntityType);
+
+    final List<String> toRemove = new ArrayList<String>();
+    Iterator<Entry<String, JsonNode>> fieldsIterator = tree.fields();
+    // TODO: Add custom annotation support
+    while (fieldsIterator.hasNext()) {
+      Map.Entry<String, JsonNode> field = (Map.Entry<String, JsonNode>) fieldsIterator.next();
+      if (field.getKey().endsWith(Constants.JSON_NAVIGATION_LINK)) {
+        final Link link = new LinkImpl();
+        link.setTitle(getAnnotationName(field));
+        link.setRel(ODataServiceVersion.V40.getNamespace(ODataServiceVersion.NamespaceKey.NAVIGATION_LINK_REL)
+            + getAnnotationName(field));
+
+        if (field.getValue().isValueNode()) {
+          link.setHref(field.getValue().textValue());
+          link.setType(ODataLinkType.ENTITY_NAVIGATION.toString());
+        }
+
+        entity.getNavigationLinks().add(link);
+        toRemove.add(field.getKey());
+      } else if (field.getKey().endsWith(Constants.JSON_ASSOCIATION_LINK)) {
+        final LinkImpl link = new LinkImpl();
+        link.setTitle(getAnnotationName(field));
+        link.setRel(ODataServiceVersion.V40.getNamespace(ODataServiceVersion.NamespaceKey.ASSOCIATION_LINK_REL)
+            + getAnnotationName(field));
+        link.setHref(field.getValue().textValue());
+        link.setType(ODataLinkType.ASSOCIATION.toString());
+        entity.getAssociationLinks().add(link);
+
+        toRemove.add(field.getKey());
+      }
+    }
+
+    // remove here to avoid iterator issues.
+    tree.remove(toRemove);
+
+    if (tree.size() != 0) {
+      throw new DeserializerException("Tree should be empty but still has content left.",
+          DeserializerException.MessageKeys.TREE_NOT_EMPTY);
+    }
+
+    return entity;
+  }
+
+  private String getAnnotationName(final Map.Entry<String, JsonNode> entry) {
+    return entry.getKey().substring(0, entry.getKey().indexOf('@'));
+  }
+
+  private void consumeODataEntityAnnotations(ObjectNode tree, EntityImpl entity, EdmEntityType edmEntityType) {
+    final URI contextURL;
+    if (tree.hasNonNull(Constants.JSON_CONTEXT)) {
+      contextURL = URI.create(tree.get(Constants.JSON_CONTEXT).textValue());
+      tree.remove(Constants.JSON_CONTEXT);
+    } else if (tree.hasNonNull(Constants.JSON_METADATA)) {
+      contextURL = URI.create(tree.get(Constants.JSON_METADATA).textValue());
+      tree.remove(Constants.JSON_METADATA);
+    } else {
+      contextURL = null;
+    }
+    if (contextURL != null) {
+      entity.setBaseURI(StringUtils.substringBefore(contextURL.toASCIIString(), Constants.METADATA));
+    }
+
+    if (tree.hasNonNull(Constants.JSON_ETAG)) {
+      entity.setETag(tree.get(Constants.JSON_ETAG).textValue());
+      tree.remove(Constants.JSON_ETAG);
+    }
+
+    if (tree.hasNonNull(Constants.JSON_TYPE)) {
+      entity.setType(new EdmTypeInfo.Builder().setTypeExpression(tree.get(Constants.JSON_TYPE).textValue()).build()
+          .internal());
+      tree.remove(Constants.JSON_TYPE);
+    }
+
+    if (tree.hasNonNull(Constants.JSON_ID)) {
+      entity.setId(URI.create(tree.get(Constants.JSON_ID).textValue()));
+      tree.remove(Constants.JSON_ID);
+    }
+
+    if (tree.hasNonNull(Constants.JSON_READ_LINK)) {
+      final LinkImpl link = new LinkImpl();
+      link.setRel(Constants.SELF_LINK_REL);
+      link.setHref(tree.get(Constants.JSON_READ_LINK).textValue());
+      entity.setSelfLink(link);
+
+      tree.remove(Constants.JSON_READ_LINK);
+    }
+
+    if (tree.hasNonNull(Constants.JSON_EDIT_LINK)) {
+      final LinkImpl link = new LinkImpl();
+      link.setRel(Constants.EDIT_LINK_REL);
+      link.setHref(tree.get(Constants.JSON_EDIT_LINK).textValue());
+      entity.setEditLink(link);
+
+      tree.remove(Constants.JSON_EDIT_LINK);
+    }
+
+    // TODO: Should we check if this is a media resource?
+    if (tree.hasNonNull(Constants.JSON_MEDIA_READ_LINK)) {
+      entity.setMediaContentSource(URI.create(tree.get(Constants.JSON_MEDIA_READ_LINK).textValue()));
+      tree.remove(Constants.JSON_MEDIA_READ_LINK);
+    }
+    if (tree.hasNonNull(Constants.JSON_MEDIA_EDIT_LINK)) {
+      entity.setMediaContentSource(URI.create(tree.get(Constants.JSON_MEDIA_EDIT_LINK).textValue()));
+      tree.remove(Constants.JSON_MEDIA_EDIT_LINK);
+    }
+    if (tree.hasNonNull(Constants.JSON_MEDIA_CONTENT_TYPE)) {
+      entity.setMediaContentType(tree.get(Constants.JSON_MEDIA_CONTENT_TYPE).textValue());
+      tree.remove(Constants.JSON_MEDIA_CONTENT_TYPE);
+    }
+    if (tree.hasNonNull(Constants.JSON_MEDIA_ETAG)) {
+      entity.setMediaETag(tree.get(Constants.JSON_MEDIA_ETAG).textValue());
+      tree.remove(Constants.JSON_MEDIA_ETAG);
+    }
+
+  }
+
+  private Property consumePropertyNode(EdmProperty edmProperty, JsonNode jsonNode) throws DeserializerException {
+    Property property = new PropertyImpl();
+    property.setName(edmProperty.getName());
+    property.setType(edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString());
+    if (edmProperty.isCollection()) {
+      if (!jsonNode.isArray()) {
+        throw new DeserializerException("Value for property: " + edmProperty.getName()
+            + " must be an arrat but is not.", DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY,
+            edmProperty.getName());
+      }
+      List<Object> valueArray = new ArrayList<Object>();
+      Iterator<JsonNode> iterator = jsonNode.iterator();
+      switch (edmProperty.getType().getKind()) {
+      case PRIMITIVE:
+        while (iterator.hasNext()) {
+          JsonNode arrayElement = iterator.next();
+          Object value = readPrimitiveValue(edmProperty, arrayElement);
+          valueArray.add(value);
+        }
+        property.setValue(ValueType.COLLECTION_PRIMITIVE, valueArray);
+        break;
+      case DEFINITION:
+        while (iterator.hasNext()) {
+          JsonNode arrayElement = iterator.next();
+          Object value = readTypeDefinitionValue(edmProperty, arrayElement);
+          valueArray.add(value);
+        }
+        property.setValue(ValueType.COLLECTION_PRIMITIVE, valueArray);
+      case ENUM:
+        while (iterator.hasNext()) {
+          JsonNode arrayElement = iterator.next();
+          Object value = readEnumValue(edmProperty, arrayElement);
+          valueArray.add(value);
+        }
+        property.setValue(ValueType.COLLECTION_ENUM, valueArray);
+        break;
+      case COMPLEX:
+        while (iterator.hasNext()) {
+          JsonNode arrayElement = iterator.next();
+          // read and add all complex properties
+          Object value = readComplexValue(edmProperty, arrayElement);
+          valueArray.add(value);
+          // If navigationProperties are present we have to consume them and create a LinkedComplexValue Object
+          // TODO: Complex Type Navigation Deserialization
+          // read and add all annotations
+          // TODO: read Complex Type Annotations
+          // Afterwards the node must be empty
+          if (arrayElement.size() != 0) {
+            throw new DeserializerException("Tree should be empty but still has content left.",
+                DeserializerException.MessageKeys.TREE_NOT_EMPTY);
+          }
+        }
+        property.setValue(ValueType.COLLECTION_COMPLEX, valueArray);
+        break;
+      default:
+        throw new DeserializerException("Invalid Type Kind for a property found: " + edmProperty.getType().getKind(),
+            DeserializerException.MessageKeys.INVALID_TYPE_FOR_PROPERTY, edmProperty.getName());
+      }
+
+    } else {
+      switch (edmProperty.getType().getKind()) {
+      case PRIMITIVE:
+        Object value = readPrimitiveValue(edmProperty, jsonNode);
+        property.setValue(ValueType.PRIMITIVE, value);
+        break;
+      case DEFINITION:
+        value = readTypeDefinitionValue(edmProperty, jsonNode);
+        property.setValue(ValueType.PRIMITIVE, value);
+      case ENUM:
+        value = readEnumValue(edmProperty, jsonNode);
+        property.setValue(ValueType.PRIMITIVE, value);
+        break;
+      case COMPLEX:
+        // read and add all complex properties
+        value = readComplexValue(edmProperty, jsonNode);
+        property.setValue(ValueType.COMPLEX, value);
+
+        // read and add all navigation properties
+        // TODO: Complex Type Navigation Deserialization
+        // read and add all annotations
+        // TODO: read Complex Type Annotations
+        // Afterwards the node must be empty
+        if (jsonNode.size() != 0) {
+          throw new DeserializerException("Tree should be empty but still has content left.",
+              DeserializerException.MessageKeys.TREE_NOT_EMPTY);
+        }
+        break;
+      default:
+        throw new DeserializerException("Invalid Type Kind for a property found: " + edmProperty.getType().getKind(),
+            DeserializerException.MessageKeys.INVALID_TYPE_FOR_PROPERTY, edmProperty.getName());
+      }
+    }
+    return property;
+  }
+
+  private Object readComplexValue(EdmProperty edmComplexProperty, JsonNode jsonNode) throws DeserializerException {
+    if (jsonNode.isArray() || !jsonNode.isContainerNode()) {
+      throw new DeserializerException(
+          "Inavlid value for property: " + edmComplexProperty.getName() + " must not be an array or primitive value.",
+          DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmComplexProperty.getName());
+    }
+    // Even if there are no properties defined we have to give back an empty list
+    List<Property> propertyList = new ArrayList<Property>();
+    EdmComplexType edmType = (EdmComplexType) edmComplexProperty.getType();
+    // Check and consume all Properties
+    for (String propertyName : edmType.getPropertyNames()) {
+      EdmProperty edmProperty = (EdmProperty) edmType.getProperty(propertyName);
+      JsonNode subNode = jsonNode.get(propertyName);
+      if (subNode != null) {
+        if (subNode.isNull() && edmProperty.isNullable() != null && edmProperty.isNullable().booleanValue() == false) {
+          throw new DeserializerException("Property: " + propertyName + " must not be null.",
+              DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, propertyName);
+        }
+        Property property = consumePropertyNode(edmProperty, subNode);
+        propertyList.add(property);
+        ((ObjectNode) jsonNode).remove(propertyName);
+      }
+    }
+    return propertyList;
+  }
+
+  private Object readTypeDefinitionValue(EdmProperty edmProperty, JsonNode jsonNode) throws DeserializerException {
+    if (!jsonNode.isValueNode()) {
+      throw new DeserializerException(
+          "Inavlid value for property: " + edmProperty.getName() + " must not be an object or array.",
+          DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
+    }
+    try {
+      EdmTypeDefinition edmTypeDefinition = (EdmTypeDefinition) edmProperty.getType();
+      Object value =
+          edmTypeDefinition.valueOfString(jsonNode.asText(), edmProperty.isNullable(),
+              edmTypeDefinition.getMaxLength(),
+              edmTypeDefinition.getPrecision(), edmTypeDefinition.getScale(), edmTypeDefinition.isUnicode(),
+              edmTypeDefinition.getDefaultType());
+      return value;
+    } catch (EdmPrimitiveTypeException e) {
+      throw new DeserializerException(
+          "Inavlid value: " + jsonNode.asText() + " for property: " + edmProperty.getName(), e,
+          DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
+    }
+  }
+
+  private Object readEnumValue(EdmProperty edmProperty, JsonNode jsonNode) throws DeserializerException {
+    if (!jsonNode.isValueNode()) {
+      throw new DeserializerException(
+          "Inavlid value for property: " + edmProperty.getName() + " must not be an object or array.",
+          DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
+    }
+    try {
+      EdmEnumType edmEnumType = (EdmEnumType) edmProperty.getType();
+      Object value =
+          edmEnumType
+              .valueOfString(jsonNode.asText(), edmProperty.isNullable(), edmProperty.getMaxLength(), edmProperty
+                  .getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), edmEnumType.getDefaultType());
+      return value;
+    } catch (EdmPrimitiveTypeException e) {
+      throw new DeserializerException(
+          "Inavlid value: " + jsonNode.asText() + " for property: " + edmProperty.getName(), e,
+          DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
+    }
+  }
+
+  private Object readPrimitiveValue(EdmProperty edmProperty, JsonNode jsonNode) throws DeserializerException {
+    if (!jsonNode.isValueNode()) {
+      throw new DeserializerException(
+          "Inavlid value for property: " + edmProperty.getName() + " must not be an object or array.",
+          DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
+    }
+    try {
+      EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmProperty.getType();
+      Object value =
+          edmPrimitiveType.valueOfString(jsonNode.asText(), edmProperty.isNullable(),
+              edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(),
+              edmProperty.isUnicode(), edmPrimitiveType.getDefaultType());
+      return value;
+    } catch (EdmPrimitiveTypeException e) {
+      throw new DeserializerException(
+          "Inavlid value: " + jsonNode.asText() + " for property: " + edmProperty.getName(), e,
+          DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, edmProperty.getName());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerBasicTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerBasicTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerBasicTest.java
new file mode 100644
index 0000000..f3e22ef
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerBasicTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core.deserializer.json;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.deserializer.ODataDeserializer;
+import org.junit.Test;
+
+public class ODataJsonDeserializerBasicTest {
+
+  @Test
+  public void checkSupportedJsonFormats() throws Exception {
+    ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
+    assertNotNull(deserializer);
+    deserializer = null;
+
+    deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON_NO_METADATA);
+    assertNotNull(deserializer);
+    deserializer = null;
+
+    deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON_FULL_METADATA);
+    assertNotNull(deserializer);
+    deserializer = null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/AbstractODataDeserializerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/AbstractODataDeserializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/AbstractODataDeserializerTest.java
new file mode 100644
index 0000000..185d869
--- /dev/null
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/AbstractODataDeserializerTest.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core.deserializer.json;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+
+import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.edmx.EdmxReference;
+import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
+
+public class AbstractODataDeserializerTest {
+  
+  protected static final Edm edm = OData.newInstance().createServiceMetadata(
+      new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
+  
+  protected InputStream getFileAsStream(final String filename) throws IOException {
+    InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
+    if (in == null) {
+      throw new IOException("Requested file '" + filename + "' was not found.");
+    }
+    return in;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerDeepInsertTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerDeepInsertTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerDeepInsertTest.java
new file mode 100644
index 0000000..3b90277
--- /dev/null
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerDeepInsertTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core.deserializer.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.InputStream;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.domain.ODataLinkType;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+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.junit.Test;
+
+public class ODataDeserializerDeepInsertTest extends AbstractODataDeserializerTest {
+
+  @Test
+  public void esAllPrimExpandedToOne() throws Exception {
+    EdmEntityType edmEntityType = edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"));
+    InputStream stream = getFileAsStream("EntityESAllPrimExpandedNavPropertyETTwoPrimOne.json");
+    Entity entity = OData.newInstance().createDeserializer(ODataFormat.JSON).entity(stream, edmEntityType);
+
+    Link navigationLink = entity.getNavigationLink("NavPropertyETTwoPrimOne");
+    assertNotNull(navigationLink);
+
+    assertEquals("NavPropertyETTwoPrimOne", navigationLink.getTitle());
+    assertEquals(ODataLinkType.ENTITY_NAVIGATION.toString(), navigationLink.getType());
+    assertNotNull(navigationLink.getInlineEntity());
+    assertNull(navigationLink.getInlineEntitySet());
+  }
+
+  @Test
+  public void esAllPrimExpandedToMany() throws Exception {
+    EdmEntityType edmEntityType = edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"));
+    InputStream stream = getFileAsStream("EntityESAllPrimExpandedNavPropertyETTwoPrimMany.json");
+    Entity entity = OData.newInstance().createDeserializer(ODataFormat.JSON).entity(stream, edmEntityType);
+
+    Link navigationLink = entity.getNavigationLink("NavPropertyETTwoPrimMany");
+    assertNotNull(navigationLink);
+
+    assertEquals("NavPropertyETTwoPrimMany", navigationLink.getTitle());
+    assertEquals(ODataLinkType.ENTITY_SET_NAVIGATION.toString(), navigationLink.getType());
+    assertNull(navigationLink.getInlineEntity());
+    assertNotNull(navigationLink.getInlineEntitySet());
+    assertEquals(1, navigationLink.getInlineEntitySet().getEntities().size());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerEntitySetTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerEntitySetTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerEntitySetTest.java
new file mode 100644
index 0000000..9cefff6
--- /dev/null
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataDeserializerEntitySetTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core.deserializer.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.List;
+
+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.EdmEntityType;
+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.junit.Test;
+
+public class ODataDeserializerEntitySetTest extends AbstractODataDeserializerTest {
+
+  @Test
+  public void esAllPrim() throws Exception {
+    EdmEntityType edmEntityType = edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"));
+    InputStream stream = getFileAsStream("ESAllPrim.json");
+    EntitySet entitySet = OData.newInstance().createDeserializer(ODataFormat.JSON).entitySet(stream, edmEntityType);
+    
+    assertNotNull(entitySet);
+    assertEquals(3, entitySet.getEntities().size());
+    
+    //Check first entity
+    Entity entity = entitySet.getEntities().get(0);
+    List<Property> properties = entity.getProperties();
+    assertNotNull(properties);
+    assertEquals(16, properties.size());
+
+    assertEquals(new Short((short) 32767), entity.getProperty("PropertyInt16").getValue());
+    assertEquals("First Resource - positive values", entity.getProperty("PropertyString").getValue());
+    assertEquals(new Boolean(true), entity.getProperty("PropertyBoolean").getValue());
+    assertEquals(new Short((short) 255), entity.getProperty("PropertyByte").getValue());
+    assertEquals(new Byte((byte) 127), entity.getProperty("PropertySByte").getValue());
+    assertEquals(new Integer(2147483647), entity.getProperty("PropertyInt32").getValue());
+    assertEquals(new Long(9223372036854775807l), entity.getProperty("PropertyInt64").getValue());
+    assertEquals(new Float(1.79E20), entity.getProperty("PropertySingle").getValue());
+    assertEquals(new Double(-1.79E19), entity.getProperty("PropertyDouble").getValue());
+    assertEquals(new BigDecimal(34), entity.getProperty("PropertyDecimal").getValue());
+    assertNotNull(entity.getProperty("PropertyBinary").getValue());
+    assertNotNull(entity.getProperty("PropertyDate").getValue());
+    assertNotNull(entity.getProperty("PropertyDateTimeOffset").getValue());
+    assertNotNull(entity.getProperty("PropertyDuration").getValue());
+    assertNotNull(entity.getProperty("PropertyGuid").getValue());
+    assertNotNull(entity.getProperty("PropertyTimeOfDay").getValue());
+  }
+  
+  @Test
+  public void eSCompCollComp() throws Exception {
+    EdmEntityType edmEntityType = edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETCompCollComp"));
+    InputStream stream = getFileAsStream("ESCompCollComp.json");
+    EntitySet entitySet = OData.newInstance().createDeserializer(ODataFormat.JSON).entitySet(stream, edmEntityType);
+    
+    assertNotNull(entitySet);
+    assertEquals(2, entitySet.getEntities().size());
+    
+    //Since entity deserialization is called we do not check all entities here excplicitly
+  }  
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
new file mode 100644
index 0000000..c9aad1a
--- /dev/null
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.core.deserializer.json;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.List;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.data.ValueType;
+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.deserializer.ODataDeserializer;
+import org.junit.Test;
+
+public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTest {
+
+  @Test
+  public void simpleEntityETAllPrim() throws Exception {
+    String entityString =
+        "{\"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\"}";
+    InputStream stream = new ByteArrayInputStream(entityString.getBytes());
+    ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
+    Entity entity =
+        deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim")));
+    assertNotNull(entity);
+    List<Property> properties = entity.getProperties();
+    assertNotNull(properties);
+    assertEquals(16, properties.size());
+
+    assertEquals(new Short((short) 32767), entity.getProperty("PropertyInt16").getValue());
+    assertEquals("First Resource - positive values", entity.getProperty("PropertyString").getValue());
+    assertEquals(new Boolean(true), entity.getProperty("PropertyBoolean").getValue());
+    assertEquals(new Short((short) 255), entity.getProperty("PropertyByte").getValue());
+    assertEquals(new Byte((byte) 127), entity.getProperty("PropertySByte").getValue());
+    assertEquals(new Integer(2147483647), entity.getProperty("PropertyInt32").getValue());
+    assertEquals(new Long(9223372036854775807l), entity.getProperty("PropertyInt64").getValue());
+    assertEquals(new Float(1.79E20), entity.getProperty("PropertySingle").getValue());
+    assertEquals(new Double(-1.79E19), entity.getProperty("PropertyDouble").getValue());
+    assertEquals(new BigDecimal(34), entity.getProperty("PropertyDecimal").getValue());
+    assertNotNull(entity.getProperty("PropertyBinary").getValue());
+    assertNotNull(entity.getProperty("PropertyDate").getValue());
+    assertNotNull(entity.getProperty("PropertyDateTimeOffset").getValue());
+    assertNotNull(entity.getProperty("PropertyDuration").getValue());
+    assertNotNull(entity.getProperty("PropertyGuid").getValue());
+    assertNotNull(entity.getProperty("PropertyTimeOfDay").getValue());
+  }
+
+  @Test
+  public void simpleEntityETCompAllPrim() throws Exception {
+    String entityString = "{\"PropertyInt16\":32767," +
+        "\"PropertyComp\":{" +
+        "\"PropertyString\":\"First Resource - first\"," +
+        "\"PropertyBinary\":\"ASNFZ4mrze8=\"," +
+        "\"PropertyBoolean\":true," +
+        "\"PropertyByte\":255," +
+        "\"PropertyDate\":\"2012-10-03\"," +
+        "\"PropertyDateTimeOffset\":\"2012-10-03T07:16:23.1234567Z\"," +
+        "\"PropertyDecimal\":34.27," +
+        "\"PropertySingle\":1.79E20," +
+        "\"PropertyDouble\":-1.79E19," +
+        "\"PropertyDuration\":\"PT6S\"," +
+        "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," +
+        "\"PropertyInt16\":32767," +
+        "\"PropertyInt32\":2147483647," +
+        "\"PropertyInt64\":9223372036854775807," +
+        "\"PropertySByte\":127," +
+        "\"PropertyTimeOfDay\":\"01:00:01\"}}";
+    InputStream stream = new ByteArrayInputStream(entityString.getBytes());
+    ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
+    Entity entity =
+        deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETCompAllPrim")));
+    assertNotNull(entity);
+    List<Property> properties = entity.getProperties();
+    assertNotNull(properties);
+    assertEquals(2, properties.size());
+
+    assertEquals(new Short((short) 32767), entity.getProperty("PropertyInt16").getValue());
+
+    assertNotNull(entity.getProperty("PropertyComp"));
+    assertNotNull(entity.getProperty("PropertyComp") instanceof List);
+    List<Property> complexProperties = entity.getProperty("PropertyComp").asComplex();
+    assertEquals(16, complexProperties.size());
+  }
+
+  @Test
+  public void simpleEntityETCollAllPrim() throws Exception {
+    final String entityString = "{"
+        + "\"PropertyInt16\":1,"
+        + "\"CollPropertyString\":"
+        + "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
+        + "\"CollPropertyBoolean\":[true,false,true],"
+        + "\"CollPropertyByte\":[50,200,249],"
+        + "\"CollPropertySByte\":[-120,120,126],"
+        + "\"CollPropertyInt16\":[1000,2000,30112],"
+        + "\"CollPropertyInt32\":[23232323,11223355,10000001],"
+        + "\"CollPropertyInt64\":[929292929292,333333333333,444444444444],"
+        + "\"CollPropertySingle\":[1790.0,26600.0,3210.0],"
+        + "\"CollPropertyDouble\":[-17900.0,-2.78E7,3210.0],"
+        + "\"CollPropertyDecimal\":[12,-2,1234],"
+        + "\"CollPropertyBinary\":[\"q83v\",\"ASNF\",\"VGeJ\"],"
+        + "\"CollPropertyDate\":[\"1958-12-03\",\"1999-08-05\",\"2013-06-25\"],"
+        + "\"CollPropertyDateTimeOffset\":[\"2015-08-12T03:08:34Z\",\"1970-03-28T12:11:10Z\","
+        + "\"1948-02-17T09:09:09Z\"],"
+        + "\"CollPropertyDuration\":[\"PT13S\",\"PT5H28M0S\",\"PT1H0S\"],"
+        + "\"CollPropertyGuid\":[\"ffffff67-89ab-cdef-0123-456789aaaaaa\",\"eeeeee67-89ab-cdef-0123-456789bbbbbb\","
+        + "\"cccccc67-89ab-cdef-0123-456789cccccc\"],"
+        + "\"CollPropertyTimeOfDay\":[\"04:14:13\",\"23:59:59\",\"01:12:33\"]"
+        + "}";
+    InputStream stream = new ByteArrayInputStream(entityString.getBytes());
+    ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
+    Entity entity =
+        deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETCollAllPrim")));
+    assertNotNull(entity);
+    List<Property> properties = entity.getProperties();
+    assertNotNull(properties);
+    assertEquals(17, properties.size());
+
+    // All properties need 3 entires
+    for (Property prop : properties) {
+      if (!prop.getName().equals("PropertyInt16")) {
+        assertEquals(ValueType.COLLECTION_PRIMITIVE, prop.getValueType());
+        assertTrue(prop.getValue() instanceof List);
+        List<? extends Object> asCollection = prop.asCollection();
+        assertEquals(3, asCollection.size());
+      }
+    }
+    Property property = entity.getProperty("CollPropertyBoolean");
+    List<? extends Object> asCollection = property.asCollection();
+    assertEquals(true, asCollection.get(0));
+    assertEquals(false, asCollection.get(1));
+    assertEquals(true, asCollection.get(2));
+  }
+
+  @SuppressWarnings("unchecked")
+  @Test
+  public void simpleEntityETMixPrimCollComp() throws Exception {
+    final String entityString = "{"
+        + "\"PropertyInt16\":32767,"
+        + "\"CollPropertyString\":"
+        + "[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"],"
+        + "\"PropertyComp\":{\"PropertyInt16\":111,\"PropertyString\":\"TEST A\"},"
+        + "\"CollPropertyComp\":["
+        + "{\"PropertyInt16\":123,\"PropertyString\":\"TEST 1\"},"
+        + "{\"PropertyInt16\":456,\"PropertyString\":\"TEST 2\"},"
+        + "{\"PropertyInt16\":789,\"PropertyString\":\"TEST 3\"}]}";
+
+    InputStream stream = new ByteArrayInputStream(entityString.getBytes());
+    ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
+    Entity entity =
+        deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETMixPrimCollComp")));
+    assertNotNull(entity);
+    List<Property> properties = entity.getProperties();
+    assertNotNull(properties);
+    assertEquals(4, properties.size());
+
+    Property property = entity.getProperty("CollPropertyComp");
+    assertEquals(ValueType.COLLECTION_COMPLEX, property.getValueType());
+
+    assertTrue(property.getValue() instanceof List);
+    List<? extends Object> asCollection = property.asCollection();
+    assertEquals(3, asCollection.size());
+
+    for (Object arrayElement : asCollection) {
+      assertTrue(arrayElement instanceof List);
+      List<Object> castedArrayElement = (List<Object>) arrayElement;
+      assertEquals(2, castedArrayElement.size());
+    }
+  }
+
+  @Test
+  public void simpleEntityWithContextURL() throws Exception {
+    String entityString =
+        "{\"@odata.context\": \"$metadata#ESAllPrim/$entity\"," +
+            "\"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\"}";
+    InputStream stream = new ByteArrayInputStream(entityString.getBytes());
+    ODataDeserializer deserializer = OData.newInstance().createDeserializer(ODataFormat.JSON);
+    Entity entity =
+        deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim")));
+    assertNotNull(entity);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-test/src/test/resources/ESAllPrim.json
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/resources/ESAllPrim.json b/lib/server-test/src/test/resources/ESAllPrim.json
new file mode 100644
index 0000000..75a6a22
--- /dev/null
+++ b/lib/server-test/src/test/resources/ESAllPrim.json
@@ -0,0 +1,56 @@
+{
+	"@odata.context" : "$metadata#ESAllPrim",
+	"value" : [{
+			"PropertyInt16" : 32767,
+			"PropertyString" : "First Resource - positive values",
+			"PropertyBoolean" : true,
+			"PropertyByte" : 255,
+			"PropertySByte" : 127,
+			"PropertyInt32" : 2147483647,
+			"PropertyInt64" : 9223372036854775807,
+			"PropertySingle" : 1.79000000E+20,
+			"PropertyDouble" : -1.7900000000000000E+19,
+			"PropertyDecimal" : 34,
+			"PropertyBinary" : "ASNFZ4mrze8=",
+			"PropertyDate" : "2012-12-03",
+			"PropertyDateTimeOffset" : "2012-12-03T07:16:23Z",
+			"PropertyDuration" : "P0DT0H0M6S",
+			"PropertyGuid" : "01234567-89ab-cdef-0123-456789abcdef",
+			"PropertyTimeOfDay" : "03:26:05"
+		}, {
+			"PropertyInt16" : -32768,
+			"PropertyString" : "Second Resource - negative values",
+			"PropertyBoolean" : false,
+			"PropertyByte" : 0,
+			"PropertySByte" : -128,
+			"PropertyInt32" : -2147483648,
+			"PropertyInt64" : -9223372036854775808,
+			"PropertySingle" : -1.79000000E+08,
+			"PropertyDouble" : -1.7900000000000000E+05,
+			"PropertyDecimal" : -34,
+			"PropertyBinary" : "ASNFZ4mrze8=",
+			"PropertyDate" : "2015-11-05",
+			"PropertyDateTimeOffset" : "2005-12-03T07:17:08Z",
+			"PropertyDuration" : "P0DT0H0M9S",
+			"PropertyGuid" : "76543201-23ab-cdef-0123-456789dddfff",
+			"PropertyTimeOfDay" : "23:49:14"
+		}, {
+			"PropertyInt16" : 0,
+			"PropertyString" : "",
+			"PropertyBoolean" : false,
+			"PropertyByte" : 0,
+			"PropertySByte" : 0,
+			"PropertyInt32" : 0,
+			"PropertyInt64" : 0,
+			"PropertySingle" : 0.00000000E+00,
+			"PropertyDouble" : 0.0000000000000000E+00,
+			"PropertyDecimal" : 0,
+			"PropertyBinary" : "",
+			"PropertyDate" : "1970-01-01",
+			"PropertyDateTimeOffset" : "2005-12-03T00:00:00Z",
+			"PropertyDuration" : "P0DT0H0M0S",
+			"PropertyGuid" : "76543201-23ab-cdef-0123-456789cccddd",
+			"PropertyTimeOfDay" : "00:01:01"
+		}
+	]
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-test/src/test/resources/ESCompCollComp.json
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/resources/ESCompCollComp.json b/lib/server-test/src/test/resources/ESCompCollComp.json
new file mode 100644
index 0000000..fa02338
--- /dev/null
+++ b/lib/server-test/src/test/resources/ESCompCollComp.json
@@ -0,0 +1,35 @@
+{
+	"@odata.context" : "$metadata#ESCompCollComp",
+	"value" : [{
+			"PropertyInt16" : 32767,
+			"PropertyComp" : {
+				"CollPropertyComp" : [{
+						"PropertyInt16" : 555,
+						"PropertyString" : "1 Test Complex in Complex Property"
+					}, {
+						"PropertyInt16" : 666,
+						"PropertyString" : "2 Test Complex in Complex property"
+					}, {
+						"PropertyInt16" : 777,
+						"PropertyString" : "3 Test Complex in Complex property"
+					}
+				]
+			}
+		}, {
+			"PropertyInt16" : 12345,
+			"PropertyComp" : {
+				"CollPropertyComp" : [{
+						"PropertyInt16" : 888,
+						"PropertyString" : "11 Test Complex in Complex property"
+					}, {
+						"PropertyInt16" : 999,
+						"PropertyString" : "12 Test Complex in Complex property"
+					}, {
+						"PropertyInt16" : 0,
+						"PropertyString" : "13 Test Complex in Complex property"
+					}
+				]
+			}
+		}
+	]
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-test/src/test/resources/EntityESAllPrimExpandedNavPropertyETTwoPrimMany.json
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/resources/EntityESAllPrimExpandedNavPropertyETTwoPrimMany.json b/lib/server-test/src/test/resources/EntityESAllPrimExpandedNavPropertyETTwoPrimMany.json
new file mode 100644
index 0000000..b15788f
--- /dev/null
+++ b/lib/server-test/src/test/resources/EntityESAllPrimExpandedNavPropertyETTwoPrimMany.json
@@ -0,0 +1,24 @@
+{
+	"@odata.context" : "$metadata#ESAllPrim/$entity",
+	"PropertyInt16" : 32767,
+	"PropertyString" : "First Resource - positive values",
+	"PropertyBoolean" : true,
+	"PropertyByte" : 255,
+	"PropertySByte" : 127,
+	"PropertyInt32" : 2147483647,
+	"PropertyInt64" : 9223372036854775807,
+	"PropertySingle" : 1.79000000E+20,
+	"PropertyDouble" : -1.7900000000000000E+19,
+	"PropertyDecimal" : 34,
+	"PropertyBinary" : "ASNFZ4mrze8=",
+	"PropertyDate" : "2012-12-03",
+	"PropertyDateTimeOffset" : "2012-12-03T07:16:23Z",
+	"PropertyDuration" : "P0DT0H0M6S",
+	"PropertyGuid" : "01234567-89ab-cdef-0123-456789abcdef",
+	"PropertyTimeOfDay" : "03:26:05",
+	"NavPropertyETTwoPrimMany" : [{
+			"PropertyInt16" : -365,
+			"PropertyString" : "Test String2"
+		}
+	]
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2ac6ba18/lib/server-test/src/test/resources/EntityESAllPrimExpandedNavPropertyETTwoPrimOne.json
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/resources/EntityESAllPrimExpandedNavPropertyETTwoPrimOne.json b/lib/server-test/src/test/resources/EntityESAllPrimExpandedNavPropertyETTwoPrimOne.json
new file mode 100644
index 0000000..a68a554
--- /dev/null
+++ b/lib/server-test/src/test/resources/EntityESAllPrimExpandedNavPropertyETTwoPrimOne.json
@@ -0,0 +1,23 @@
+{
+	"@odata.context" : "$metadata#ESAllPrim/$entity",
+	"PropertyInt16" : 32767,
+	"PropertyString" : "First Resource - positive values",
+	"PropertyBoolean" : true,
+	"PropertyByte" : 255,
+	"PropertySByte" : 127,
+	"PropertyInt32" : 2147483647,
+	"PropertyInt64" : 9223372036854775807,
+	"PropertySingle" : 1.79000000E+20,
+	"PropertyDouble" : -1.7900000000000000E+19,
+	"PropertyDecimal" : 34,
+	"PropertyBinary" : "ASNFZ4mrze8=",
+	"PropertyDate" : "2012-12-03",
+	"PropertyDateTimeOffset" : "2012-12-03T07:16:23Z",
+	"PropertyDuration" : "P0DT0H0M6S",
+	"PropertyGuid" : "01234567-89ab-cdef-0123-456789abcdef",
+	"PropertyTimeOfDay" : "03:26:05",
+	"NavPropertyETTwoPrimOne" : {
+		"PropertyInt16" : 32767,
+		"PropertyString" : "Test String4"
+	}
+}