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"
+ }
+}