This is an automated email from the ASF dual-hosted git repository.

ramyav pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/olingo-odata4.git


The following commit(s) were added to refs/heads/master by this push:
     new 6f8b90b  [OLINGO-1485]Server side support for instance annotations
6f8b90b is described below

commit 6f8b90bccdbd18a2914f2351d799b860a498d797
Author: ramya vasanth <[email protected]>
AuthorDate: Fri Oct 9 14:05:14 2020 +0530

    [OLINGO-1485]Server side support for instance annotations
---
 .../deserializer/json/ODataJsonDeserializer.java   |  28 ++
 .../ODataJsonInstanceAnnotationDeserializer.java   | 234 +++++++++++++++++
 .../ODataJsonInstanceAnnotationSerializer.java     | 230 +++++++++++++++++
 .../core/serializer/json/ODataJsonSerializer.java  |  24 +-
 .../json/ODataDeserializerDeepInsertTest.java      |  30 ++-
 .../json/ODataJsonDeserializerEntityTest.java      |  10 +-
 ...sonDeserializerWithInstanceAnnotationsTest.java | 271 ++++++++++++++++++++
 ...aJsonSerializerWithInstanceAnnotationsTest.java | 285 +++++++++++++++++++++
 8 files changed, 1088 insertions(+), 24 deletions(-)

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
index 9b4fc8e..babc5a0 100644
--- 
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
@@ -39,6 +39,7 @@ import org.apache.olingo.commons.api.Constants;
 import org.apache.olingo.commons.api.IConstants;
 import org.apache.olingo.commons.api.constants.Constantsv00;
 import org.apache.olingo.commons.api.constants.Constantsv01;
+import org.apache.olingo.commons.api.data.Annotation;
 import org.apache.olingo.commons.api.data.ComplexValue;
 import org.apache.olingo.commons.api.data.DeletedEntity;
 import org.apache.olingo.commons.api.data.DeletedEntity.Reason;
@@ -118,6 +119,7 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
   private final boolean isIEEE754Compatible;
   private ServiceMetadata serviceMetadata;
   private IConstants constants;
+  private ODataJsonInstanceAnnotationDeserializer instanceAnnotDeserializer;
 
   public ODataJsonDeserializer(final ContentType contentType) {
     this(contentType, null, new Constantsv00());
@@ -127,17 +129,20 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
     isIEEE754Compatible = 
ContentTypeHelper.isODataIEEE754Compatible(contentType);
     this.serviceMetadata = serviceMetadata;
     this.constants = new Constantsv00();
+    instanceAnnotDeserializer = new ODataJsonInstanceAnnotationDeserializer();
   }
 
   public ODataJsonDeserializer(ContentType contentType, ServiceMetadata 
serviceMetadata, IConstants constants) {
     isIEEE754Compatible = 
ContentTypeHelper.isODataIEEE754Compatible(contentType);
     this.serviceMetadata = serviceMetadata;
     this.constants = constants;
+    instanceAnnotDeserializer = new ODataJsonInstanceAnnotationDeserializer();
   }
 
   public ODataJsonDeserializer(ContentType contentType, IConstants constants) {
     isIEEE754Compatible = 
ContentTypeHelper.isODataIEEE754Compatible(contentType);
     this.constants = constants;
+    instanceAnnotDeserializer = new ODataJsonInstanceAnnotationDeserializer();
   }
 
   @Override
@@ -451,6 +456,29 @@ public class ODataJsonDeserializer implements 
ODataDeserializer {
         Link bindingLink = consumeBindingLink(field.getKey(), 
field.getValue(), edmEntityType);
         entity.getNavigationBindings().add(bindingLink);
         toRemove.add(field.getKey());
+      } else if (!field.getKey().contains(ODATA_CONTROL_INFORMATION_PREFIX) && 
+                 field.getKey().contains(ODATA_ANNOTATION_MARKER) &&
+                 
field.getKey().substring(field.getKey().indexOf(ODATA_ANNOTATION_MARKER))
+                 .contains(".")) {
+       // Instance annotations start with @ sign followed by 
+          // alias or namespace 
+          // followed by a dot and then term name
+         String[] keySplit = field.getKey().split(ODATA_ANNOTATION_MARKER);
+         String termName = keySplit[1];
+         Annotation annotation = 
instanceAnnotDeserializer.consumeInstanceAnnotation(termName, field.getValue());
+         // If keySplit has a value at zeroth index then instance annotation 
is specified like 
+         // propertyName@Term
+         if (!keySplit[0].isEmpty()) {
+                 if (edmEntityType.getPropertyNames().contains(keySplit[0])) {
+                         
entity.getProperty(keySplit[0]).getAnnotations().add(annotation);
+                 } else if 
(edmEntityType.getNavigationPropertyNames().contains(keySplit[0])) {
+                         Link link = entity.getNavigationLink(keySplit[0]);
+                         link.getAnnotations().add(annotation);
+                 }
+         } else {
+                 entity.getAnnotations().add(annotation);
+         }
+         toRemove.add(field.getKey());
       }
     }
     // remove here to avoid iterator issues.
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonInstanceAnnotationDeserializer.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonInstanceAnnotationDeserializer.java
new file mode 100644
index 0000000..0ac5251
--- /dev/null
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonInstanceAnnotationDeserializer.java
@@ -0,0 +1,234 @@
+/*
+ * 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.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.AbstractMap.SimpleEntry;
+
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.Annotation;
+import org.apache.olingo.commons.api.data.ComplexValue;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.data.PropertyType;
+import org.apache.olingo.commons.api.data.Valuable;
+import org.apache.olingo.commons.api.data.ValueType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.geo.Geospatial;
+import org.apache.olingo.commons.core.edm.EdmTypeInfo;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class ODataJsonInstanceAnnotationDeserializer {
+
+       private static final String ODATA_CONTROL_INFORMATION_PREFIX = 
"@odata.";
+       
+       /**
+        * Consume the instance annotation of an entity or a property
+        * @param key String
+        * @param value JsonNode
+        * @return Annotation of an entity
+        * @throws DeserializerException
+        */
+       public Annotation consumeInstanceAnnotation(String key, JsonNode value) 
+                       throws DeserializerException {
+               Annotation annotation = new Annotation();
+               annotation.setTerm(key);
+               try {
+                       value(annotation, value);
+               } catch (EdmPrimitiveTypeException | IOException e) {
+                       throw new DeserializerException("Property: " + key,
+                                       
DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, key);
+               }
+               return annotation;
+       }
+
+       private void value(final Valuable valuable, final JsonNode node) 
+                       throws IOException, EdmPrimitiveTypeException {
+
+               EdmTypeInfo typeInfo = null;
+
+               final Map.Entry<PropertyType, EdmTypeInfo> guessed = 
guessPropertyType(node);
+               if (typeInfo == null) {
+                       typeInfo = guessed.getValue();
+               }
+
+               final PropertyType propType = typeInfo == null ? 
guessed.getKey()
+                               : typeInfo.isCollection() ? 
PropertyType.COLLECTION
+                               : typeInfo.isPrimitiveType() ? 
PropertyType.PRIMITIVE
+                               : node.isValueNode() ? PropertyType.ENUM : 
PropertyType.COMPLEX;
+
+               switch (propType) {
+               case COLLECTION:
+                       fromCollection(valuable, node.elements(), typeInfo);
+                       break;
+
+               case COMPLEX:
+                       if (node.has(Constants.JSON_TYPE)) {
+                               
valuable.setType(node.get(Constants.JSON_TYPE).asText());
+                               ((ObjectNode) node).remove(Constants.JSON_TYPE);
+                       }
+                       final Object value = fromComplex((ObjectNode) node);
+                       if (value instanceof ComplexValue) {
+                               ((ComplexValue) 
value).setTypeName(valuable.getType());
+                       }
+                       valuable.setValue(ValueType.COMPLEX, value);
+                       break;
+
+               case ENUM:
+                       if (!node.isNull()) {
+                               valuable.setValue(ValueType.ENUM, 
node.asText());
+                       }
+                       break;
+
+               case PRIMITIVE:
+                       if (valuable.getType() == null && typeInfo != null) {
+                               
valuable.setType(typeInfo.getFullQualifiedName().toString());
+                       }
+                       final Object primitiveValue = fromPrimitive(node, 
typeInfo);
+                       valuable.setValue(primitiveValue instanceof Geospatial 
? 
+                                       ValueType.GEOSPATIAL : 
ValueType.PRIMITIVE,
+                                       primitiveValue);
+                       break;
+
+               case EMPTY:
+               default:
+                       valuable.setValue(ValueType.PRIMITIVE, "");
+               }
+       }
+
+       private Object fromPrimitive(final JsonNode node, final EdmTypeInfo 
typeInfo) 
+                       throws EdmPrimitiveTypeException {
+               return node.isNull() ? null
+                               : typeInfo == null ? node.asText()
+                               : ((EdmPrimitiveType) 
typeInfo.getType()).valueOfString(node.asText(), true, null,
+                               Constants.DEFAULT_PRECISION, 
Constants.DEFAULT_SCALE, true,
+                               ((EdmPrimitiveType) 
typeInfo.getType()).getDefaultType());
+       }
+
+       private Object fromComplex(final ObjectNode node) throws IOException, 
EdmPrimitiveTypeException {
+
+               final ComplexValue complexValue = new ComplexValue();
+               final Set<String> toRemove = new HashSet<>();
+               for (final Iterator<Map.Entry<String, JsonNode>> itor = 
node.fields(); itor.hasNext();) {
+                       final Map.Entry<String, JsonNode> field = itor.next();
+                       if 
(field.getKey().contains(ODATA_CONTROL_INFORMATION_PREFIX)) {
+                               toRemove.add(field.getKey());
+                       } else {
+                               Property property = new Property();
+                               property.setName(field.getKey());
+                               value(property, field.getValue());
+                               complexValue.getValue().add(property);
+                       }
+               }
+               node.remove(toRemove);
+               return complexValue;
+       }
+
+       private void fromCollection(final Valuable valuable, final 
Iterator<JsonNode> nodeItor, 
+                       final EdmTypeInfo typeInfo)
+                       throws IOException, EdmPrimitiveTypeException {
+
+               final List<Object> values = new ArrayList<>();
+               ValueType valueType = ValueType.COLLECTION_PRIMITIVE;
+
+               final EdmTypeInfo type = typeInfo == null ? null
+                               : new EdmTypeInfo.Builder().setTypeExpression(
+                                               
typeInfo.getFullQualifiedName().toString()).build();
+
+               while (nodeItor.hasNext()) {
+                       final JsonNode child = nodeItor.next();
+
+                       if (child.isValueNode()) {
+                               if (typeInfo == null || 
typeInfo.isPrimitiveType()) {
+                                       final Object value = 
fromPrimitive(child, type);
+                                       valueType = value instanceof Geospatial 
? ValueType.COLLECTION_GEOSPATIAL
+                                                       : 
ValueType.COLLECTION_PRIMITIVE;
+                                       values.add(value);
+                               } else {
+                                       valueType = ValueType.COLLECTION_ENUM;
+                                       values.add(child.asText());
+                               }
+                       } else if (child.isContainerNode()) {
+                               EdmTypeInfo childType = null;
+                               if (child.has(Constants.JSON_TYPE)) {
+                                       String typeName = 
child.get(Constants.JSON_TYPE).asText();
+                                       childType = typeName == null ? null : 
new EdmTypeInfo.Builder()
+                                                       
.setTypeExpression(typeName).build();
+                                       ((ObjectNode) 
child).remove(Constants.JSON_TYPE);
+                               }
+                               final Object value = fromComplex((ObjectNode) 
child);
+                               if (childType != null) {
+                                       ((ComplexValue) 
value).setTypeName(childType.external());
+                               }
+                               valueType = ValueType.COLLECTION_COMPLEX;
+                               values.add(value);
+                       }
+               }
+               valuable.setValue(valueType, values);
+       }
+
+       private Map.Entry<PropertyType, EdmTypeInfo> guessPropertyType(final 
JsonNode node) {
+               PropertyType type;
+               String typeExpression = null;
+
+               if (node.isValueNode() || node.isNull()) {
+                       type = PropertyType.PRIMITIVE;
+                       typeExpression = 
guessPrimitiveTypeKind(node).getFullQualifiedName().toString();
+               } else if (node.isArray()) {
+                       type = PropertyType.COLLECTION;
+                       if (node.has(0) && node.get(0).isValueNode()) {
+                               typeExpression = "Collection(" + 
guessPrimitiveTypeKind(node.get(0)) + ')';
+                       }
+               } else if (node.isObject()) {
+                       if (node.has(Constants.ATTR_TYPE)) {
+                               type = PropertyType.PRIMITIVE;
+                               typeExpression = "Edm.Geography" + 
node.get(Constants.ATTR_TYPE).asText();
+                       } else {
+                               type = PropertyType.COMPLEX;
+                       }
+               } else {
+                       type = PropertyType.EMPTY;
+               }
+
+               final EdmTypeInfo typeInfo = typeExpression == null ? null
+                               : new 
EdmTypeInfo.Builder().setTypeExpression(typeExpression).build();
+               return new SimpleEntry<>(type, typeInfo);
+       }
+
+       private EdmPrimitiveTypeKind guessPrimitiveTypeKind(final JsonNode 
node) {
+               return node.isShort() ? EdmPrimitiveTypeKind.Int16
+                               : node.isInt() ? EdmPrimitiveTypeKind.Int32
+                               : node.isLong() ? EdmPrimitiveTypeKind.Int64
+                               : node.isBoolean() ? 
EdmPrimitiveTypeKind.Boolean
+                               : node.isFloat() ? EdmPrimitiveTypeKind.Single
+                               : node.isDouble() ? EdmPrimitiveTypeKind.Double
+                               : node.isBigDecimal() ? 
EdmPrimitiveTypeKind.Decimal
+                               : EdmPrimitiveTypeKind.String;
+       }
+}
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonInstanceAnnotationSerializer.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonInstanceAnnotationSerializer.java
new file mode 100644
index 0000000..d197f99
--- /dev/null
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonInstanceAnnotationSerializer.java
@@ -0,0 +1,230 @@
+/*
+ * 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.serializer.json;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.IConstants;
+import org.apache.olingo.commons.api.data.Annotation;
+import org.apache.olingo.commons.api.data.ComplexValue;
+import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.data.Valuable;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.format.ContentType;
+import 
org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+public class ODataJsonInstanceAnnotationSerializer {
+
+       private final boolean isODataMetadataNone;
+       private final boolean isODataMetadataFull;
+       private IConstants constants;
+       private final boolean isIEEE754Compatible;
+
+       public ODataJsonInstanceAnnotationSerializer(final ContentType 
contentType, final IConstants constants) {
+               isIEEE754Compatible = 
ContentTypeHelper.isODataIEEE754Compatible(contentType);
+               isODataMetadataNone = 
ContentTypeHelper.isODataMetadataNone(contentType);
+               isODataMetadataFull = 
ContentTypeHelper.isODataMetadataFull(contentType);
+               this.constants = constants;
+       }
+
+       /**
+        * Write the instance annotation of an entity
+        * @param annotations List of annotations
+        * @param json JsonGenerator
+        * @throws IOException 
+        * @throws SerializerException
+        * @throws DecoderException
+        */
+       public void writeInstanceAnnotationsOnEntity(final List<Annotation> 
annotations, final JsonGenerator json)
+                       throws IOException, SerializerException, 
DecoderException {
+               for (Annotation annotation : annotations) {
+                       if (isODataMetadataFull) {
+                               json.writeStringField(constants.getType(), "#" 
+ annotation.getType());
+                       }
+                       json.writeFieldName("@" + annotation.getTerm());
+                       writeInstanceAnnotation(json, annotation, "");
+               }
+       }
+
+       /**
+        * Write instance annotation of a property
+        * @param edmProperty EdmProperty
+        * @param property Property
+        * @param json JsonGenerator
+        * @throws IOException
+        * @throws SerializerException
+        * @throws DecoderException
+        */
+       public void writeInstanceAnnotationsOnProperties(final EdmProperty 
edmProperty, final Property property,
+                       final JsonGenerator json) throws IOException, 
SerializerException, DecoderException {
+               if (property != null) {
+                       for (Annotation annotation : property.getAnnotations()) 
{
+                               json.writeFieldName(edmProperty.getName() + "@" 
+ annotation.getTerm());
+                               writeInstanceAnnotation(json, annotation, "");
+                       }
+               }
+       }
+
+       @SuppressWarnings({ "unchecked", "rawtypes" })
+       private void writeInstanceAnnotation(final JsonGenerator json, Valuable 
annotation, String name)
+                       throws IOException, SerializerException, 
DecoderException {
+               try {
+                       switch (annotation.getValueType()) {
+                       case PRIMITIVE:
+                               if (isODataMetadataFull && name.length() > 0) {
+                                       json.writeStringField(name + 
constants.getType(), "#" + annotation.getType());
+                               }
+                               if (name.length() > 0) {
+                                       json.writeFieldName(name);
+                               }
+                               writeInstanceAnnotOnPrimitiveProperty(json, 
annotation, annotation.getValue());
+                               break;
+                       case COLLECTION_PRIMITIVE:
+                               if (isODataMetadataFull && name.length() > 0) {
+                                       json.writeStringField(name + 
constants.getType(), 
+                                                       "#Collection(" + 
annotation.getType() + ")");
+                               }
+                               if (name.length() > 0) {
+                                       json.writeFieldName(name);
+                               }
+                               json.writeStartArray();
+                               List list = annotation.asCollection();
+                               for (Object value : list) {
+                                       
writeInstanceAnnotOnPrimitiveProperty(json, annotation, value);
+                               }
+                               json.writeEndArray();
+                               break;
+                       case COMPLEX:
+                               if (isODataMetadataFull && name.length() > 0) {
+                                       json.writeStringField(name + 
constants.getType(), "#" + annotation.getType());
+                               }
+                               if (name.length() > 0) {
+                                       json.writeFieldName(name);
+                               }
+                               ComplexValue complexValue = 
annotation.asComplex();
+                               writeInstanceAnnotOnComplexProperty(json, 
annotation, complexValue);
+                               break;
+                       case COLLECTION_COMPLEX:
+                               if (isODataMetadataFull && name.length() > 0) {
+                                       json.writeStringField(name + 
constants.getType(), 
+                                                       "#Collection(" + 
annotation.getType() + ")");
+                               }
+                               if (name.length() > 0) {
+                                       json.writeFieldName(name);
+                               }
+                               json.writeStartArray();
+                               List<ComplexValue> complexValues = 
(List<ComplexValue>) annotation.asCollection();
+                               for (ComplexValue complxValue : complexValues) {
+                                       
writeInstanceAnnotOnComplexProperty(json, annotation, complxValue);
+                               }
+                               json.writeEndArray();
+                               break;
+                       default:
+                       }
+               } catch (final EdmPrimitiveTypeException e) {
+                       throw new SerializerException("Wrong value for instance 
annotation!", e,
+                                       
SerializerException.MessageKeys.WRONG_PROPERTY_VALUE, 
+                                       ((Annotation) annotation).getTerm(),
+                                       annotation.getValue().toString());
+               }
+       }
+
+       private void writeInstanceAnnotOnComplexProperty(final JsonGenerator 
json, Valuable annotation,
+                       ComplexValue complexValue) throws IOException, 
SerializerException, DecoderException {
+               json.writeStartObject();
+               if (isODataMetadataFull) {
+                       json.writeStringField(constants.getType(), "#" + 
complexValue.getTypeName());
+               }
+               List<Property> properties = complexValue.getValue();
+               for (Property prop : properties) {
+                       writeInstanceAnnotation(json, prop, prop.getName());
+               }
+               json.writeEndObject();
+       }
+
+       private void writeInstanceAnnotOnPrimitiveProperty(final JsonGenerator 
json, Valuable annotation, Object value)
+                       throws IOException, EdmPrimitiveTypeException {
+               writePrimitiveValue("",
+                               EdmPrimitiveTypeFactory.getInstance(
+                                               
EdmPrimitiveTypeKind.getByName(annotation.getType())), value, null,
+                               null, null, null, true, json);
+       }
+
+       protected void writePrimitiveValue(final String name, final 
EdmPrimitiveType type, final Object primitiveValue,
+                       final Boolean isNullable, final Integer maxLength, 
final Integer precision, final Integer scale,
+                       final Boolean isUnicode, final JsonGenerator json) 
+                                       throws EdmPrimitiveTypeException, 
IOException {
+               final String value = type.valueToString(
+                               primitiveValue, isNullable, maxLength, 
precision, scale, isUnicode);
+               if (value == null) {
+                       json.writeNull();
+               } else if (type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean)) {
+                       json.writeBoolean(Boolean.parseBoolean(value));
+               } else if (type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Byte)
+                               || type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Double)
+                               || type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int16)
+                               || type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int32)
+                               || type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.SByte)
+                               || type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Single)
+                               || (type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)
+                               || type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64))
+                                               && !isIEEE754Compatible) {
+                       json.writeNumber(value);
+               } else if (type == 
EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Stream)) {
+                       if (primitiveValue instanceof Link) {
+                               Link stream = (Link) primitiveValue;
+                               if (!isODataMetadataNone) {
+                                       if (stream.getMediaETag() != null) {
+                                               json.writeStringField(name + 
constants.getMediaEtag(), 
+                                                               
stream.getMediaETag());
+                                       }
+                                       if (stream.getType() != null) {
+                                               json.writeStringField(name + 
constants.getMediaContentType(), 
+                                                               
stream.getType());
+                                       }
+                               }
+                               if (isODataMetadataFull) {
+                                       if (stream.getRel() != null && 
+                                                       
stream.getRel().equals(Constants.NS_MEDIA_READ_LINK_REL)) {
+                                               json.writeStringField(name + 
constants.getMediaReadLink(), 
+                                                               
stream.getHref());
+                                       }
+                                       if (stream.getRel() == null || 
+                                                       
stream.getRel().equals(Constants.NS_MEDIA_EDIT_LINK_REL)) {
+                                               json.writeStringField(name + 
constants.getMediaEditLink(), 
+                                                               
stream.getHref());
+                                       }
+                               }
+                       }
+               } else {
+                       json.writeString(value);
+               }
+       }
+}
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
index e9fdfd7..ec75da0 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
@@ -115,12 +115,14 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
   private final boolean isODataMetadataNone;
   private final boolean isODataMetadataFull;
   private IConstants constants;
+  private ODataJsonInstanceAnnotationSerializer instanceAnnotSerializer;
 
   public ODataJsonSerializer(final ContentType contentType, final IConstants 
constants) {
     isIEEE754Compatible = 
ContentTypeHelper.isODataIEEE754Compatible(contentType);
     isODataMetadataNone = ContentTypeHelper.isODataMetadataNone(contentType);
     isODataMetadataFull = ContentTypeHelper.isODataMetadataFull(contentType);
     this.constants = constants;
+    instanceAnnotSerializer = new 
ODataJsonInstanceAnnotationSerializer(contentType, constants);
   }
 
   public ODataJsonSerializer(final ContentType contentType) {
@@ -128,6 +130,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
     isODataMetadataNone = ContentTypeHelper.isODataMetadataNone(contentType);
     isODataMetadataFull = ContentTypeHelper.isODataMetadataFull(contentType);
     this.constants = new Constantsv00();
+    instanceAnnotSerializer = new 
ODataJsonInstanceAnnotationSerializer(contentType, constants);
   }
 
   @Override
@@ -431,7 +434,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
             json.writeStringField(constants.getEditLink(), 
entity.getEditLink().getHref());
           }
         }
-        
+        
instanceAnnotSerializer.writeInstanceAnnotationsOnEntity(entity.getAnnotations(),
 json);        
         writeProperties(metadata, resolvedType, entity.getProperties(), 
select, json, entity, expand);
         writeNavigationProperties(metadata, resolvedType, entity, expand, 
toDepth, ancestors, name, json);
         writeOperations(entity.getOperations(), json);      
@@ -507,7 +510,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
   protected void writeProperties(final ServiceMetadata metadata, final 
EdmStructuredType type,
       final List<Property> properties,
       final SelectOption select, final JsonGenerator json, Linked linked, 
ExpandOption expand)
-      throws IOException, SerializerException {
+      throws IOException, SerializerException, DecoderException {
     final boolean all = ExpandSelectHelper.isAll(select);
     final Set<String> selected = all ? new HashSet<>() :
         ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems());
@@ -679,7 +682,9 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
       final EdmProperty edmProperty, final Property property,
       final Set<List<String>> selectedPaths, final JsonGenerator json, 
       Set<List<String>> expandedPaths, Linked linked, ExpandOption expand)
-      throws IOException, SerializerException {
+      throws IOException, SerializerException, DecoderException  {
+       
+       
instanceAnnotSerializer.writeInstanceAnnotationsOnProperties(edmProperty, 
property, json);
     boolean isStreamProperty = isStreamProperty(edmProperty);
     writePropertyType(edmProperty, json);
     if (!isStreamProperty) {
@@ -745,7 +750,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
   private void writePropertyValue(final ServiceMetadata metadata, final 
EdmProperty edmProperty,
       final Property property, final Set<List<String>> selectedPaths, final 
JsonGenerator json, 
       Set<List<String>> expandedPaths, Linked linked, ExpandOption expand)
-      throws IOException, SerializerException {
+      throws IOException, SerializerException, DecoderException {
     final EdmType type = edmProperty.getType();
     try {
       if (edmProperty.isPrimitive()
@@ -790,7 +795,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
   private void writeComplex(final ServiceMetadata metadata, final 
EdmComplexType type,
       final Property property, final Set<List<String>> selectedPaths, final 
JsonGenerator json, 
       Set<List<String>> expandedPaths, Linked linked, ExpandOption expand) 
-          throws IOException, SerializerException{
+          throws IOException, SerializerException, DecoderException{
         json.writeStartObject();        
         String derivedName = property.getType();
         EdmComplexType resolvedType = null;
@@ -864,7 +869,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
       final Property property,
       final Set<List<String>> selectedPaths, final JsonGenerator json, 
       Set<List<String>> expandedPaths, Linked linked, ExpandOption expand)
-      throws IOException, SerializerException {
+      throws IOException, SerializerException, DecoderException {
     json.writeStartArray();
     EdmComplexType derivedType = type;
     Set<List<String>> expandedPaths1 = expandedPaths != null && 
!expandedPaths.isEmpty() ? 
@@ -1063,7 +1068,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
       final EdmComplexType type, final List<Property> properties,
       final Set<List<String>> selectedPaths, final JsonGenerator json, 
       Set<List<String>> expandedPaths, Linked linked, ExpandOption expand, 
String complexPropName)
-      throws IOException, SerializerException {
+      throws IOException, SerializerException, DecoderException {
 
     if (null != expandedPaths) {
       for(List<String> paths : expandedPaths) {
@@ -1237,7 +1242,8 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
 
   @Override
   public SerializerResult complexCollection(final ServiceMetadata metadata, 
final EdmComplexType type,
-      final Property property, final ComplexSerializerOptions options) throws 
SerializerException {
+      final Property property, final ComplexSerializerOptions options) 
+                 throws SerializerException {
     OutputStream outputStream = null;
     SerializerException cachedException = null;
     
@@ -1270,7 +1276,7 @@ public class ODataJsonSerializer extends 
AbstractODataSerializer {
 
       json.close();
       return 
SerializerResultImpl.with().content(buffer.getInputStream()).build();
-    } catch (final IOException e) {
+    } catch (final IOException | DecoderException e) {
       cachedException =
           new SerializerException(IO_EXCEPTION_TEXT, e, 
SerializerException.MessageKeys.IO_EXCEPTION);
       throw cachedException;
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
index e684c0f..d673af5 100644
--- 
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
@@ -21,13 +21,15 @@ 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 static org.junit.Assert.fail;
 
 import java.io.IOException;
+import java.util.List;
 
 import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.Annotation;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.data.ValueType;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.server.api.deserializer.DeserializerException;
 import org.apache.olingo.server.api.deserializer.DeserializerResult;
@@ -126,22 +128,24 @@ public class ODataDeserializerDeepInsertTest extends 
AbstractODataDeserializerTe
 
   @Test
   public void esAllPrimExpandedToOneWithCustomAnnotations() throws Exception {
-    try {
-      
deserialize("EntityESAllPrimExpandedNavPropertyETTwoPrimOneWithCustomAnnotations.json");
-      fail("Expected exception not thrown.");
-    } catch (final DeserializerException e) {
-      assertEquals(DeserializerException.MessageKeys.NOT_IMPLEMENTED, 
e.getMessageKey());
-    }
+      Entity entity = 
deserialize("EntityESAllPrimExpandedNavPropertyETTwoPrimOneWithCustomAnnotations.json");
+      assertNotNull(entity);
+         List<Annotation> annotations = 
entity.getNavigationLink("NavPropertyETTwoPrimOne").getAnnotations();
+         assertEquals(1, annotations.size());
+         assertEquals("custom.annotation", annotations.get(0).getTerm());
+         assertEquals("customValue", annotations.get(0).getValue());
+         assertEquals(ValueType.PRIMITIVE, annotations.get(0).getValueType());
   }
 
   @Test
   public void esAllPrimExpandedToManyWithCustomAnnotations() throws Exception {
-    try {
-      
deserialize("EntityESAllPrimExpandedNavPropertyETTwoPrimManyWithCustomAnnotations.json");
-      fail("Expected exception not thrown.");
-    } catch (final DeserializerException e) {
-      assertEquals(DeserializerException.MessageKeys.NOT_IMPLEMENTED, 
e.getMessageKey());
-    }
+         Entity entity = 
deserialize("EntityESAllPrimExpandedNavPropertyETTwoPrimManyWithCustomAnnotations.json");
+         assertNotNull(entity);
+         List<Annotation> annotations = 
entity.getNavigationLink("NavPropertyETTwoPrimMany").getAnnotations();
+         assertEquals(1, annotations.size());
+         assertEquals("custom.annotation", annotations.get(0).getTerm());
+         assertEquals("customValue", annotations.get(0).getValue());
+         assertEquals(ValueType.PRIMITIVE, annotations.get(0).getValueType());
   }
 
   @Test
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
index 25ce502..9de9b10 100644
--- 
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
@@ -37,6 +37,7 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.Annotation;
 import org.apache.olingo.commons.api.data.ComplexValue;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.Link;
@@ -1269,8 +1270,13 @@ public class ODataJsonDeserializerEntityTest extends 
AbstractODataDeserializerTe
         + "{\"PropertyInt16\":123,\"PropertyString\":\"TEST 1\"},"
         + "{\"PropertyInt16\":456,\"PropertyString\":\"TEST 2\"},"
         + "{\"PropertyInt16\":789,\"PropertyString\":\"TEST 3\"}]}";
-    expectException(entityString, "ETMixPrimCollComp",
-        DeserializerException.MessageKeys.NOT_IMPLEMENTED);
+    Entity entity = deserialize(entityString, "ETMixPrimCollComp", 
ContentType.APPLICATION_JSON);
+    assertNotNull(entity);
+    List<Annotation> annotations = 
entity.getProperty("CollPropertyString").getAnnotations();
+    assertEquals(1, annotations.size());
+    assertEquals("custom.annotation", annotations.get(0).getTerm());
+    assertEquals(12, annotations.get(0).getValue());
+    assertEquals(ValueType.PRIMITIVE, annotations.get(0).getValueType());
   }
 
   @Test
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerWithInstanceAnnotationsTest.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerWithInstanceAnnotationsTest.java
new file mode 100644
index 0000000..ab4b2eb
--- /dev/null
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerWithInstanceAnnotationsTest.java
@@ -0,0 +1,271 @@
+/*
+ * 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.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.commons.api.data.Annotation;
+import org.apache.olingo.commons.api.data.ComplexValue;
+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.EdmEntityType;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.deserializer.DeserializerResult;
+import 
org.apache.olingo.server.core.deserializer.AbstractODataDeserializerTest;
+import org.junit.Test;
+
+public class ODataJsonDeserializerWithInstanceAnnotationsTest extends 
AbstractODataDeserializerTest {
+
+  private static final ContentType CONTENT_TYPE_JSON_IEEE754Compatible =
+      ContentType.create(ContentType.JSON, 
ContentType.PARAMETER_IEEE754_COMPATIBLE, "true");
+  private static final OData odata = OData.newInstance();
+
+  @Test
+  public void instanceAnnotOnEntity() throws Exception {
+         final String entityString = "{"
+                       + "\"@context\":\"$metadata#ESAllPrim/$entity\","
+                       + "\"@metadataEtag\":\"W/\\\"metadataETag\\\"\","
+                       + "\"@com.contoso.display.highlight\":true,"
+                       + "\"@com.contoso.PersonalInfo.PhoneNumbers\":"
+                       + "[\"(203)555-1718\",\"(203)555-1719\"],"
+                       + "\"PropertyInt16\":32767,"
+                       + "\"NavPropertyETTwoPrimOne@bind\": \"ETTwoPrim(1)\","
+                       + "\"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\""
+                       + "}";
+  final Entity entity = deserializeWithResultWithConstantV401(
+               new ByteArrayInputStream(entityString.getBytes()), 
+               "ETAllPrim", ContentType.APPLICATION_JSON).getEntity();
+    assertNotNull(entity);
+    List<Annotation> annotations = entity.getAnnotations();
+    assertEquals(2, annotations.size());
+    assertEquals("com.contoso.display.highlight", 
annotations.get(0).getTerm());
+    assertTrue((Boolean)annotations.get(0).getValue());
+    assertEquals(ValueType.PRIMITIVE, annotations.get(0).getValueType());
+    assertEquals("com.contoso.PersonalInfo.PhoneNumbers", 
annotations.get(1).getTerm());
+    assertEquals(ValueType.COLLECTION_PRIMITIVE, 
annotations.get(1).getValueType());
+    assertEquals(2, annotations.get(1).asCollection().size());
+    assertEquals(1, entity.getNavigationBindings().size());
+    assertEquals("NavPropertyETTwoPrimOne", entity
+               .getNavigationBinding("NavPropertyETTwoPrimOne").getTitle());
+  }
+  
+  @Test
+  public void instanceAnnotOnEntityProperty() throws Exception {
+         final String entityString = "{"
+                               +       
"\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
+                               +       
"\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+                               +       
"\"@odata.type\":\"#olingo.odata.test1.ETAllPrim\","
+                               +       "\"@odata.id\":\"ESAllPrim(32767)\","
+                               +       
"\"[email protected]\":\"#Int16\","
+                               +       "\"PropertyInt16\":32767,"
+                               +       
"\"[email protected]\":{"
+                               +               
"\"@odata.type\":\"#com.contoso.display.styleType\","
+                               +               
"\"[email protected]\":\"#Boolean\","
+                               +               "\"title\":true,"
+                               +               
"\"[email protected]\":\"#Int16\","
+                               +               "\"Order\":1"
+                               +       "},"
+                               +       "\"PropertyString\":\"First Resource - 
positive values\","
+                               +       "\"PropertyBoolean\":true,"
+                               +       "\"[email protected]\":\"#Byte\","
+                               +       "\"PropertyByte\":255,"
+                               +       
"\"[email protected]\":\"#SByte\","
+                               +       "\"PropertySByte\":127,"
+                               +       
"\"[email protected]\":\"#Int32\","
+                               +       "\"PropertyInt32\":2147483647,"
+                               +       
"\"[email protected]\":\"#Int64\","
+                               +       "\"PropertyInt64\":9223372036854775807,"
+                               +       
"\"[email protected]\":\"#Single\","
+                               +       "\"PropertySingle\":1.79E20,"
+                               +       "\"PropertyDouble\":-1.79E19,"
+                               +       
"\"[email protected]\":\"#Decimal\","
+                               +       "\"PropertyDecimal\":34,"
+                               +       
"\"[email protected]\":\"#Binary\","
+                               +       "\"PropertyBinary\":\"ASNFZ4mrze8=\","
+                               +       "\"[email protected]\":\"#Date\","
+                               +       "\"PropertyDate\":\"2012-12-03\","
+                               +       
"\"[email protected]\":\"#DateTimeOffset\","
+                               +       
"\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\","
+                               +       
"\"[email protected]\":\"#Duration\","
+                               +       "\"PropertyDuration\":\"PT6S\","
+                               +       "\"[email protected]\":\"#Guid\","
+                               +       
"\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\","
+                               +       
"\"[email protected]\":\"#TimeOfDay\","
+                               +       "\"PropertyTimeOfDay\":\"03:26:05\","
+                               +       
"\"[email protected]\":\"ESTwoPrim(32767)\","
+                               +       
"\"[email protected]\":"
+                               + 
"\"ESAllPrim(32767)/NavPropertyETTwoPrimMany\""
+                               +"}";
+    final Entity entity = deserialize(entityString, "ETAllPrim");
+    assertNotNull(entity);
+    Property property = entity.getProperties().get(1);
+    List<Annotation> annotations = property.getAnnotations();
+    assertEquals(1, annotations.size());
+    assertEquals("com.contoso.display.style", annotations.get(0).getTerm());
+    assertEquals(ValueType.COMPLEX, annotations.get(0).getValueType());
+    ComplexValue value = annotations.get(0).asComplex();
+    assertEquals("#com.contoso.display.styleType", value.getTypeName());
+    List<Property> complxProperties = value.getValue();
+    assertEquals(2, complxProperties.size());
+    assertEquals("title", complxProperties.get(0).getName());
+    assertTrue((Boolean)complxProperties.get(0).getValue());
+    assertEquals("Order", complxProperties.get(1).getName());
+    assertEquals(1, complxProperties.get(1).getValue());
+  }
+  
+  @Test
+  public void instanceAnnotOnComplexProperty() throws Exception {
+         final String entityString = "{"
+                       +       
"\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\","
+                       +       
"\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+                       +       
"\"@odata.type\":\"#olingo.odata.test1.ETMixPrimCollComp\","
+                       +       "\"@odata.id\":\"ESMixPrimCollComp(32767)\","
+                       +       "\"[email protected]\":\"#Int16\","
+                       +       "\"PropertyInt16\":32767,"
+                       +       
"\"[email protected]\":\"#Collection(String)\","
+                       +       
"\"CollPropertyString\":[\"[email protected]\","
+                       + 
"\"[email protected]\",\"[email protected]\"],"
+                       +       "\"[email protected]\":{"
+                       +               
"\"@odata.type\":\"#com.contoso.display.styleType\","
+                       +               "\"[email protected]\":\"#Boolean\","
+                       +               "\"title\":true,"
+                       +               
"\"[email protected]\":\"#Collection(Order)\","
+                       +               "\"Order\":[{"
+                       +                       
"\"@odata.type\":\"#com.contoso.display.orderDetails\""
+                       +               "},{"
+                       +                       
"\"@odata.type\":\"#com.contoso.display.orderDetails\","
+                       +                       
"\"[email protected]\":\"#String\","
+                       +                       "\"name\":\"Cars\","
+                       +                       
"\"[email protected]\":\"#String\","
+                       +                       "\"brand\":\"BMW\""
+                       +               "}]"
+                       +       "},"
+                       +       "\"PropertyComp\":{"
+                       +               
"\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+                       +               
"\"[email protected]\":\"#Int16\","
+                       +               "\"PropertyInt16\":111,"
+                       +               "\"PropertyString\":\"TEST A\","
+                       +               
"\"[email protected]\":"
+                       + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='1')\""
+                       +       "},"
+                       +       
"\"[email protected]\":\"#Collection(olingo.odata.test1.CTTwoPrim)\","
+                       +       "\"CollPropertyComp\":[{"
+                       +               
"\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+                       +               
"\"[email protected]\":\"#Int16\","
+                       +               "\"PropertyInt16\":123,"
+                       +               "\"PropertyString\":\"TEST 1\","
+                       +               
"\"[email protected]\":"
+                       + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\""
+                       +       "},{"
+                       +               
"\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+                       +               
"\"[email protected]\":\"#Int16\","
+                       +               "\"PropertyInt16\":456,"
+                       +               "\"PropertyString\":\"TEST 2\","
+                       +               
"\"[email protected]\":"
+                       + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\""
+                       +       "},{"
+                       +               
"\"@odata.type\":\"#olingo.odata.test1.CTBase\","
+                       +               
"\"[email protected]\":\"#Int16\","
+                       +               "\"PropertyInt16\":789,"
+                       +               "\"PropertyString\":\"TEST 3\","
+                       +               "\"AdditionalPropString\":\"ADD TEST\","
+                       +               
"\"[email protected]\":"
+                       + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\""
+                       +       "}]"
+                       +"}";
+    final Entity entity = deserialize(entityString, "ETMixPrimCollComp");
+    assertNotNull(entity);
+    Property property = entity.getProperties().get(2);
+    List<Annotation> annotations = property.getAnnotations();
+    assertEquals(1, annotations.size());
+    assertEquals("com.contoso.display.style", annotations.get(0).getTerm());
+    assertEquals(ValueType.COMPLEX, annotations.get(0).getValueType());
+    ComplexValue value = annotations.get(0).asComplex();
+    assertEquals("#com.contoso.display.styleType", value.getTypeName());
+    List<Property> complxProperties = value.getValue();
+    assertEquals(2, complxProperties.size());
+    assertEquals("title", complxProperties.get(0).getName());
+    assertTrue((Boolean)complxProperties.get(0).getValue());
+    assertEquals("Order", complxProperties.get(1).getName());
+    assertEquals(ValueType.COLLECTION_COMPLEX, 
complxProperties.get(1).getValueType());
+    assertEquals(2, complxProperties.get(1).asCollection().size());
+  }
+  
+  protected static DeserializerResult 
deserializeWithResultWithConstantV401(final InputStream stream, 
+                 final String entityTypeName, final ContentType contentType) 
+                                 throws DeserializerException {
+    final EdmEntityType entityType = edm.getEntityType(new 
FullQualifiedName(NAMESPACE, entityTypeName));
+    List<String> odataVersions = new ArrayList<>();
+    odataVersions.add("4.01");
+    return odata.createDeserializer(contentType, metadata, 
odataVersions).entity(stream, entityType);
+  }
+  
+  protected static Entity deserialize(final InputStream stream, final String 
entityTypeName,
+             final ContentType contentType) throws DeserializerException {
+           return deserializeWithResult(stream, entityTypeName, 
contentType).getEntity();
+         }
+
+  protected static DeserializerResult deserializeWithResult(final InputStream 
stream, 
+                 final String entityTypeName, final ContentType contentType) 
+                                 throws DeserializerException {
+    final EdmEntityType entityType = edm.getEntityType(new 
FullQualifiedName(NAMESPACE, entityTypeName));
+    return deserializeWithResult(stream, entityType, contentType);
+  }
+
+  protected static DeserializerResult deserializeWithResult(final InputStream 
stream, 
+                 final EdmEntityType entityType, final ContentType 
contentType) 
+                                 throws DeserializerException {
+    return odata.createDeserializer(contentType, metadata).entity(stream, 
entityType);
+  }
+
+  private static Entity deserialize(final String entityString, final String 
entityTypeName,
+      final ContentType contentType) throws DeserializerException {
+    return deserialize(new ByteArrayInputStream(entityString.getBytes()), 
entityTypeName, contentType);
+  }
+
+  protected static Entity deserialize(final String entityString, final String 
entityTypeName)
+      throws DeserializerException {
+    return deserialize(entityString, entityTypeName, ContentType.JSON);
+  }
+}
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerWithInstanceAnnotationsTest.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerWithInstanceAnnotationsTest.java
new file mode 100644
index 0000000..11c650a
--- /dev/null
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerWithInstanceAnnotationsTest.java
@@ -0,0 +1,285 @@
+/*
+ * 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.serializer.json;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.commons.api.data.Annotation;
+import org.apache.olingo.commons.api.data.ComplexValue;
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.ContextURL.Suffix;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.data.ValueType;
+import org.apache.olingo.commons.api.edm.EdmEntityContainer;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edmx.EdmxReference;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.uri.UriHelper;
+import org.apache.olingo.server.tecsvc.MetadataETagSupport;
+import org.apache.olingo.server.tecsvc.data.DataProvider;
+import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ODataJsonSerializerWithInstanceAnnotationsTest {
+  private static final OData odata = OData.newInstance();
+  private static final ServiceMetadata metadata = odata.createServiceMetadata(
+      new EdmTechProvider(), Collections.<EdmxReference> emptyList(), new 
MetadataETagSupport("W/\"metadataETag\""));
+  private static final EdmEntityContainer entityContainer = 
metadata.getEdm().getEntityContainer();
+  private final DataProvider data = new DataProvider(odata, metadata.getEdm());
+  private final ODataSerializer serializer = new 
ODataJsonSerializer(ContentType.JSON);
+  private final ODataSerializer serializerNoMetadata = new 
ODataJsonSerializer(ContentType.JSON_NO_METADATA);
+  private final ODataSerializer serializerFullMetadata = new 
ODataJsonSerializer(ContentType.JSON_FULL_METADATA);
+  private final ODataSerializer serializerIEEECompatible =
+      new ODataJsonSerializer(ContentType.create(ContentType.JSON, 
ContentType.PARAMETER_IEEE754_COMPATIBLE, "true"));
+  private final UriHelper helper = odata.createUriHelper();
+  
+  @Test
+  public void entityWithInstanceAnnotations() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESAllPrim");
+    final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    Annotation annotation = new Annotation();
+    annotation.setTerm("com.contoso.display.highlight");
+    annotation.setType("Boolean");
+    annotation.setValue(ValueType.PRIMITIVE, true);
+    entity.getAnnotations().add(annotation);
+    annotation = new Annotation();
+    annotation.setTerm("com.contoso.PersonalInfo.PhoneNumbers");
+    annotation.setType("String");
+    annotation.setValue(ValueType.COLLECTION_PRIMITIVE, 
Arrays.asList("(203)555-1718", "(203)555-1719"));
+    entity.getAnnotations().add(annotation);
+    InputStream result = serializer.entity(metadata, 
edmEntitySet.getEntityType(), entity,
+        EntitySerializerOptions.with()
+            
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build()).getContent();
+    final String resultString = IOUtils.toString(result);
+    final String expectedResult = "{"
+        + "\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
+        + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+        + "\"@com.contoso.display.highlight\":true,"
+        + "\"@com.contoso.PersonalInfo.PhoneNumbers\":"
+        + "[\"(203)555-1718\",\"(203)555-1719\"],"
+        + "\"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\""
+        + "}";
+    Assert.assertEquals(expectedResult, resultString);
+  }
+  
+  @Test
+  public void entityPropertyWithInstanceAnnotations() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESAllPrim");
+    final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    Annotation annotation = new Annotation();
+    annotation.setTerm("com.contoso.display.style");
+    annotation.setType("com.contoso.display.styleType");
+    List<Property> properties = new ArrayList<>();
+    properties.add(new Property("Boolean", "title", ValueType.PRIMITIVE, 
true));
+    properties.add(new Property("Int16", "Order", ValueType.PRIMITIVE, 1));
+    ComplexValue complexValue = new ComplexValue();
+    complexValue.setTypeName("com.contoso.display.styleType");
+    complexValue.getValue().addAll(properties);
+    annotation.setValue(ValueType.COMPLEX, complexValue);
+    
+    Property property = entity.getProperty("PropertyString");
+    property.getAnnotations().add(annotation);
+    
+    InputStream result = serializerFullMetadata.entity(metadata, 
edmEntitySet.getEntityType(), entity,
+        EntitySerializerOptions.with()
+            
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build()).getContent();
+    final String resultString = IOUtils.toString(result);
+    final String expectedResult = "{"
+       +       "\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
+       +       "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+       +       "\"@odata.type\":\"#olingo.odata.test1.ETAllPrim\","
+       +       "\"@odata.id\":\"ESAllPrim(32767)\","
+       +       "\"[email protected]\":\"#Int16\","
+       +       "\"PropertyInt16\":32767,"
+       +       "\"[email protected]\":{"
+       +               "\"@odata.type\":\"#com.contoso.display.styleType\","
+       +               "\"[email protected]\":\"#Boolean\","
+       +               "\"title\":true,"
+       +               "\"[email protected]\":\"#Int16\","
+       +               "\"Order\":1"
+       +       "},"
+       +       "\"PropertyString\":\"First Resource - positive values\","
+       +       "\"PropertyBoolean\":true,"
+       +       "\"[email protected]\":\"#Byte\","
+       +       "\"PropertyByte\":255,"
+       +       "\"[email protected]\":\"#SByte\","
+       +       "\"PropertySByte\":127,"
+       +       "\"[email protected]\":\"#Int32\","
+       +       "\"PropertyInt32\":2147483647,"
+       +       "\"[email protected]\":\"#Int64\","
+       +       "\"PropertyInt64\":9223372036854775807,"
+       +       "\"[email protected]\":\"#Single\","
+       +       "\"PropertySingle\":1.79E20,"
+       +       "\"PropertyDouble\":-1.79E19,"
+       +       "\"[email protected]\":\"#Decimal\","
+       +       "\"PropertyDecimal\":34,"
+       +       "\"[email protected]\":\"#Binary\","
+       +       "\"PropertyBinary\":\"ASNFZ4mrze8=\","
+       +       "\"[email protected]\":\"#Date\","
+       +       "\"PropertyDate\":\"2012-12-03\","
+       +       "\"[email protected]\":\"#DateTimeOffset\","
+       +       "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\","
+       +       "\"[email protected]\":\"#Duration\","
+       +       "\"PropertyDuration\":\"PT6S\","
+       +       "\"[email protected]\":\"#Guid\","
+       +       "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\","
+       +       "\"[email protected]\":\"#TimeOfDay\","
+       +       "\"PropertyTimeOfDay\":\"03:26:05\","
+       +       
"\"[email protected]\":\"ESTwoPrim(32767)\","
+       +       
"\"[email protected]\":\"ESAllPrim(32767)/NavPropertyETTwoPrimMany\","
+       +       "\"#olingo.odata.test1.BAETAllPrimRT\":{"
+       +               "\"title\":\"olingo.odata.test1.BAETAllPrimRT\","
+       +               
"\"target\":\"ESAllPrim(32767)/olingo.odata.test1.BAETAllPrimRT\""
+       +       "}"
+       +"}";
+    Assert.assertEquals(expectedResult, resultString);
+  }
+  
+  @Test
+  public void entityComplexPropertyWithInstanceAnnotations() throws Exception {
+    final EdmEntitySet edmEntitySet = 
entityContainer.getEntitySet("ESMixPrimCollComp");
+    final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    Annotation annotation = new Annotation();
+    annotation.setTerm("com.contoso.display.style");
+    annotation.setType("com.contoso.display.styleType");
+    List<Property> properties = new ArrayList<>();
+    properties.add(new Property("Boolean", "title", ValueType.PRIMITIVE, 
true));
+    
+    List<ComplexValue> complexValues = new ArrayList<>();
+    ComplexValue orderComplexValue = new ComplexValue();
+    orderComplexValue.setTypeName("com.contoso.display.orderDetails");
+    complexValues.add(orderComplexValue);
+    
+    orderComplexValue = new ComplexValue();
+    orderComplexValue.setTypeName("com.contoso.display.orderDetails");
+    List<Property> orderProperties = new ArrayList<>();
+    orderProperties.add(new Property("String", "name", ValueType.PRIMITIVE, 
"Cars"));
+    orderProperties.add(new Property("String", "brand", ValueType.PRIMITIVE, 
"BMW"));
+    orderComplexValue.getValue().addAll(orderProperties);
+    complexValues.add(orderComplexValue);
+    properties.add(new Property("Order", "Order", 
ValueType.COLLECTION_COMPLEX, complexValues));
+    
+    
+    ComplexValue complexValue = new ComplexValue();
+    complexValue.setTypeName("com.contoso.display.styleType");
+    complexValue.getValue().addAll(properties);
+    annotation.setValue(ValueType.COMPLEX, complexValue);
+    
+    Property property = entity.getProperty("PropertyComp");
+    property.getAnnotations().add(annotation);
+    
+    InputStream result = serializerFullMetadata.entity(metadata, 
edmEntitySet.getEntityType(), entity,
+        EntitySerializerOptions.with()
+            
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
+            .build()).getContent();
+    final String resultString = IOUtils.toString(result);
+    final String expectedResult = "{"
+               +       
"\"@odata.context\":\"$metadata#ESMixPrimCollComp/$entity\","
+               +       "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
+               +       
"\"@odata.type\":\"#olingo.odata.test1.ETMixPrimCollComp\","
+               +       "\"@odata.id\":\"ESMixPrimCollComp(32767)\","
+               +       "\"[email protected]\":\"#Int16\","
+               +       "\"PropertyInt16\":32767,"
+               +       
"\"[email protected]\":\"#Collection(String)\","
+               +       "\"CollPropertyString\":[\"[email protected]\","
+               + 
"\"[email protected]\",\"[email protected]\"],"
+               +       "\"[email protected]\":{"
+               +               
"\"@odata.type\":\"#com.contoso.display.styleType\","
+               +               "\"[email protected]\":\"#Boolean\","
+               +               "\"title\":true,"
+               +               "\"[email protected]\":\"#Collection(Order)\","
+               +               "\"Order\":[{"
+               +                       
"\"@odata.type\":\"#com.contoso.display.orderDetails\""
+               +               "},{"
+               +                       
"\"@odata.type\":\"#com.contoso.display.orderDetails\","
+               +                       "\"[email protected]\":\"#String\","
+               +                       "\"name\":\"Cars\","
+               +                       "\"[email protected]\":\"#String\","
+               +                       "\"brand\":\"BMW\""
+               +               "}]"
+               +       "},"
+               +       "\"PropertyComp\":{"
+               +               
"\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+               +               "\"[email protected]\":\"#Int16\","
+               +               "\"PropertyInt16\":111,"
+               +               "\"PropertyString\":\"TEST A\","
+               +               
"\"[email protected]\":"
+               + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='1')\""
+               +       "},"
+               +       
"\"[email protected]\":\"#Collection(olingo.odata.test1.CTTwoPrim)\","
+               +       "\"CollPropertyComp\":[{"
+               +               
"\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+               +               "\"[email protected]\":\"#Int16\","
+               +               "\"PropertyInt16\":123,"
+               +               "\"PropertyString\":\"TEST 1\","
+               +               
"\"[email protected]\":"
+               + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\""
+               +       "},{"
+               +               
"\"@odata.type\":\"#olingo.odata.test1.CTTwoPrim\","
+               +               "\"[email protected]\":\"#Int16\","
+               +               "\"PropertyInt16\":456,"
+               +               "\"PropertyString\":\"TEST 2\","
+               +               
"\"[email protected]\":"
+               + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\""
+               +       "},{"
+               +               
"\"@odata.type\":\"#olingo.odata.test1.CTBase\","
+               +               "\"[email protected]\":\"#Int16\","
+               +               "\"PropertyInt16\":789,"
+               +               "\"PropertyString\":\"TEST 3\","
+               +               "\"AdditionalPropString\":\"ADD TEST\","
+               +               
"\"[email protected]\":"
+               + "\"ESTwoKeyNav(PropertyInt16=1,PropertyString='2')\""
+               +       "}],"
+               +       
"\"#olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\":{"
+               +               
"\"title\":\"olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\","
+               +               "\"target\":"
+               + 
"\"ESMixPrimCollComp(32767)/olingo.odata.test1.BAETMixPrimCollCompRTCTTwoPrim\""
+               +       "}"
+               +"}";
+    Assert.assertEquals(expectedResult, resultString);
+  }
+}

Reply via email to