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 2014/05/12 10:38:37 UTC

[02/50] [abbrv] git commit: [OLINGO-264] Instance annotations managed at binding level + test provided

[OLINGO-264] Instance annotations managed at binding level + test provided


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

Branch: refs/heads/olingo274
Commit: 8caf3fece3a42d4cf1bbf2c94840ef5be3f288f8
Parents: ec9e8ca
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Wed May 7 12:39:16 2014 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Wed May 7 12:39:16 2014 +0200

----------------------------------------------------------------------
 .../client/core/op/AbstractODataBinder.java     |  66 ++++---
 .../client/core/op/impl/v3/ODataBinderImpl.java |   8 +-
 .../client/core/op/impl/v4/ODataBinderImpl.java | 175 +++++++++++++++----
 .../olingo/client/core/v4/EntityTest.java       |  77 ++++++--
 .../apache/olingo/commons/api/data/Linked.java  |  16 ++
 .../commons/api/domain/v4/ODataAnnotation.java  |  75 +-------
 .../commons/api/domain/v4/ODataProperty.java    |  39 +----
 .../commons/api/domain/v4/ODataValuable.java    | 104 +++++++++++
 .../commons/core/data/AbstractEntity.java       |  22 +++
 .../core/data/LinkedComplexValueImpl.java       |  22 +++
 .../core/domain/AbstractODataProperty.java      |   9 -
 .../core/domain/v4/ODataAnnotationImpl.java     | 102 +++++++++++
 .../core/domain/v4/ODataPropertyImpl.java       |  28 +--
 .../core/domain/v4/ODataValuableImpl.java       | 120 +++++++++++++
 14 files changed, 644 insertions(+), 219 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/client-core/src/main/java/org/apache/olingo/client/core/op/AbstractODataBinder.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/AbstractODataBinder.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/AbstractODataBinder.java
index c54b9e7..397ae95 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/AbstractODataBinder.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/AbstractODataBinder.java
@@ -36,6 +36,7 @@ import org.apache.olingo.commons.api.data.Link;
 import org.apache.olingo.commons.api.data.Linked;
 import org.apache.olingo.commons.api.data.Property;
 import org.apache.olingo.commons.api.data.ResWrap;
+import org.apache.olingo.commons.api.data.Valuable;
 import org.apache.olingo.commons.api.data.Value;
 import org.apache.olingo.commons.api.domain.CommonODataEntity;
 import org.apache.olingo.commons.api.domain.CommonODataEntitySet;
@@ -441,12 +442,13 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
     return entity;
   }
 
-  protected EdmTypeInfo buildTypeInfo(final ResWrap<Property> resource) {
+  protected EdmTypeInfo buildTypeInfo(final ContextURL contextURL, final String metadataETag,
+          final String propertyName, final String propertyType) {
+
     FullQualifiedName typeName = null;
-    final EdmType entityType = findEntityType(resource.getContextURL(), resource.getMetadataETag());
+    final EdmType entityType = findEntityType(contextURL, metadataETag);
     if (entityType instanceof EdmStructuredType) {
-      final EdmProperty edmProperty = ((EdmStructuredType) entityType).
-              getStructuralProperty(resource.getPayload().getName());
+      final EdmProperty edmProperty = ((EdmStructuredType) entityType).getStructuralProperty(propertyName);
       if (edmProperty != null) {
         typeName = edmProperty.getType().getFullQualifiedName();
       }
@@ -454,8 +456,8 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
 
     EdmTypeInfo typeInfo = null;
     if (typeName == null) {
-      if (resource.getPayload().getType() != null) {
-        typeInfo = new EdmTypeInfo.Builder().setTypeExpression(resource.getPayload().getType()).build();
+      if (propertyType != null) {
+        typeInfo = new EdmTypeInfo.Builder().setTypeExpression(propertyType).build();
       }
     } else {
       typeInfo = new EdmTypeInfo.Builder().setTypeExpression(typeName.toString()).build();
@@ -463,43 +465,37 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
     return typeInfo;
   }
 
-  protected ODataValue getODataValue(final ResWrap<Property> resource) {
-    final EdmTypeInfo typeInfo = buildTypeInfo(resource);
+  protected ODataValue getODataValue(final FullQualifiedName type,
+          final Valuable valuable, final ContextURL contextURL, final String metadataETag) {
 
     ODataValue value = null;
-    if (resource.getPayload().getValue().isPrimitive()) {
+    if (valuable.getValue().isPrimitive()) {
       value = client.getObjectFactory().newPrimitiveValueBuilder().
-              setText(resource.getPayload().getValue().asPrimitive().get()).
-              setType(typeInfo == null
+              setText(valuable.getValue().asPrimitive().get()).
+              setType(type == null
                       ? null
-                      : EdmPrimitiveTypeKind.valueOfFQN(
-                              client.getServiceVersion(), typeInfo.getFullQualifiedName().toString())).build();
-    } else if (resource.getPayload().getValue().isGeospatial()) {
+                      : EdmPrimitiveTypeKind.valueOfFQN(client.getServiceVersion(), type.toString())).build();
+    } else if (valuable.getValue().isGeospatial()) {
       value = client.getObjectFactory().newPrimitiveValueBuilder().
-              setValue(resource.getPayload().getValue().asGeospatial().get()).
-              setType(typeInfo == null
-                      || EdmPrimitiveTypeKind.Geography.getFullQualifiedName().equals(typeInfo.getFullQualifiedName())
-                      || EdmPrimitiveTypeKind.Geometry.getFullQualifiedName().equals(typeInfo.getFullQualifiedName())
-                      ? resource.getPayload().getValue().asGeospatial().get().getEdmPrimitiveTypeKind()
-                      : EdmPrimitiveTypeKind.valueOfFQN(
-                              client.getServiceVersion(), typeInfo.getFullQualifiedName().toString())).build();
-    } else if (resource.getPayload().getValue().isComplex()) {
-      value = client.getObjectFactory().newComplexValue(typeInfo == null
-              ? null : typeInfo.getFullQualifiedName().toString());
-
-      for (Property property : resource.getPayload().getValue().asComplex().get()) {
-        value.asComplex().add(getODataProperty(
-                new ResWrap<Property>(resource.getContextURL(), resource.getMetadataETag(), property)));
+              setValue(valuable.getValue().asGeospatial().get()).
+              setType(type == null
+                      || EdmPrimitiveTypeKind.Geography.getFullQualifiedName().equals(type)
+                      || EdmPrimitiveTypeKind.Geometry.getFullQualifiedName().equals(type)
+                      ? valuable.getValue().asGeospatial().get().getEdmPrimitiveTypeKind()
+                      : EdmPrimitiveTypeKind.valueOfFQN(client.getServiceVersion(), type.toString())).build();
+    } else if (valuable.getValue().isComplex()) {
+      value = client.getObjectFactory().newComplexValue(type == null ? null : type.toString());
+
+      for (Property property : valuable.getValue().asComplex().get()) {
+        value.asComplex().add(getODataProperty(new ResWrap<Property>(contextURL, metadataETag, property)));
       }
-    } else if (resource.getPayload().getValue().isCollection()) {
-      value = client.getObjectFactory().newCollectionValue(typeInfo == null
-              ? null : "Collection(" + typeInfo.getFullQualifiedName().toString() + ")");
+    } else if (valuable.getValue().isCollection()) {
+      value = client.getObjectFactory().newCollectionValue(type == null ? null : "Collection(" + type.toString() + ")");
 
-      for (Value _value : resource.getPayload().getValue().asCollection().get()) {
-        final JSONPropertyImpl fake = new JSONPropertyImpl();
+      for (Value _value : valuable.getValue().asCollection().get()) {
+        final Property fake = new JSONPropertyImpl();
         fake.setValue(_value);
-        value.asCollection().add(getODataValue(
-                new ResWrap<Property>(resource.getContextURL(), resource.getMetadataETag(), fake)));
+        value.asCollection().add(getODataValue(type, fake, contextURL, metadataETag));
       }
     }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataBinderImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataBinderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataBinderImpl.java
index c429177..246c8e1 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataBinderImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataBinderImpl.java
@@ -34,6 +34,7 @@ import org.apache.olingo.commons.api.domain.v3.ODataEntity;
 import org.apache.olingo.commons.api.domain.v3.ODataEntitySet;
 import org.apache.olingo.commons.api.domain.v3.ODataProperty;
 import org.apache.olingo.commons.core.domain.v3.ODataPropertyImpl;
+import org.apache.olingo.commons.core.edm.EdmTypeInfo;
 import org.apache.olingo.commons.core.op.ResourceFactory;
 
 public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder {
@@ -83,7 +84,12 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
 
   @Override
   public ODataProperty getODataProperty(final ResWrap<Property> property) {
-    return new ODataPropertyImpl(property.getPayload().getName(), getODataValue(property));
+    final EdmTypeInfo typeInfo = buildTypeInfo(property.getContextURL(), property.getMetadataETag(),
+            property.getPayload().getName(), property.getPayload().getType());
+
+    return new ODataPropertyImpl(property.getPayload().getName(),
+            getODataValue(typeInfo == null ? null : typeInfo.getFullQualifiedName(),
+                    property.getPayload(), property.getContextURL(), property.getMetadataETag()));
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java
index 65b59e8..4bcec5a 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java
@@ -26,29 +26,49 @@ import org.apache.olingo.client.api.v4.EdmEnabledODataClient;
 import org.apache.olingo.client.api.v4.ODataClient;
 import org.apache.olingo.client.core.op.AbstractODataBinder;
 import org.apache.olingo.client.core.uri.URIUtils;
+import org.apache.olingo.commons.api.data.Annotatable;
+import org.apache.olingo.commons.api.data.Annotation;
+import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.DeletedEntity;
 import org.apache.olingo.commons.api.data.Delta;
 import org.apache.olingo.commons.api.data.DeltaLink;
 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.Linked;
 import org.apache.olingo.commons.api.data.LinkedComplexValue;
 import org.apache.olingo.commons.api.data.Property;
 import org.apache.olingo.commons.api.data.ResWrap;
+import org.apache.olingo.commons.api.data.Valuable;
 import org.apache.olingo.commons.api.data.Value;
 import org.apache.olingo.commons.api.domain.CommonODataEntity;
 import org.apache.olingo.commons.api.domain.CommonODataEntitySet;
 import org.apache.olingo.commons.api.domain.CommonODataProperty;
+import org.apache.olingo.commons.api.domain.ODataInlineEntity;
+import org.apache.olingo.commons.api.domain.ODataInlineEntitySet;
+import org.apache.olingo.commons.api.domain.ODataLinked;
 import org.apache.olingo.commons.api.domain.ODataServiceDocument;
 import org.apache.olingo.commons.api.domain.ODataValue;
+import org.apache.olingo.commons.api.domain.v4.ODataAnnotatatable;
+import org.apache.olingo.commons.api.domain.v4.ODataAnnotation;
 import org.apache.olingo.commons.api.domain.v4.ODataDeletedEntity.Reason;
 import org.apache.olingo.commons.api.domain.v4.ODataDelta;
+import org.apache.olingo.commons.api.domain.v4.ODataDeltaLink;
 import org.apache.olingo.commons.api.domain.v4.ODataEntity;
 import org.apache.olingo.commons.api.domain.v4.ODataEntitySet;
+import org.apache.olingo.commons.api.domain.v4.ODataLink;
 import org.apache.olingo.commons.api.domain.v4.ODataLinkedComplexValue;
 import org.apache.olingo.commons.api.domain.v4.ODataProperty;
+import org.apache.olingo.commons.api.domain.v4.ODataValuable;
 import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmEnumType;
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+import org.apache.olingo.commons.api.edm.EdmTerm;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.core.data.AnnotationImpl;
 import org.apache.olingo.commons.core.data.EnumValueImpl;
 import org.apache.olingo.commons.core.data.LinkedComplexValueImpl;
+import org.apache.olingo.commons.core.domain.v4.ODataAnnotationImpl;
 import org.apache.olingo.commons.core.domain.v4.ODataDeletedEntityImpl;
 import org.apache.olingo.commons.core.domain.v4.ODataDeltaLinkImpl;
 import org.apache.olingo.commons.core.domain.v4.ODataPropertyImpl;
@@ -96,17 +116,60 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
     return serviceDocument;
   }
 
+  private void updateValuable(final Valuable propertyResource, final ODataValuable odataValuable,
+          final Class<? extends Entity> reference) {
+
+    propertyResource.setValue(getValue(odataValuable.getValue(), reference));
+
+    if (odataValuable.hasPrimitiveValue()) {
+      propertyResource.setType(odataValuable.getPrimitiveValue().getTypeName());
+    } else if (odataValuable.hasEnumValue()) {
+      propertyResource.setType(odataValuable.getEnumValue().getTypeName());
+    } else if (odataValuable.hasComplexValue()) {
+      propertyResource.setType(odataValuable.getComplexValue().getTypeName());
+    } else if (odataValuable.hasCollectionValue()) {
+      propertyResource.setType(odataValuable.getCollectionValue().getTypeName());
+    }
+  }
+
+  private void annotations(final ODataAnnotatatable odataAnnotatable, final Annotatable annotatable,
+          final Class<? extends Entity> reference) {
+
+    for (ODataAnnotation odataAnnotation : odataAnnotatable.getAnnotations()) {
+      final Annotation annotation = new AnnotationImpl();
+
+      annotation.setTerm(odataAnnotation.getTerm());
+      updateValuable(annotation, odataAnnotation, reference);
+
+      annotatable.getAnnotations().add(annotation);
+    }
+  }
+
   @Override
   public EntitySet getEntitySet(final CommonODataEntitySet odataEntitySet, final Class<? extends EntitySet> reference) {
     final EntitySet entitySet = super.getEntitySet(odataEntitySet, reference);
     entitySet.setDeltaLink(((ODataEntitySet) odataEntitySet).getDeltaLink());
+    annotations((ODataEntitySet) odataEntitySet, entitySet, ResourceFactory.entityClassForEntitySet(reference));
     return entitySet;
   }
 
   @Override
+  protected void links(final ODataLinked odataLinked, final Linked linked, Class<? extends Entity> reference) {
+    super.links(odataLinked, linked, reference);
+
+    for (Link link : linked.getNavigationLinks()) {
+      final org.apache.olingo.commons.api.domain.ODataLink odataLink = odataLinked.getNavigationLink(link.getTitle());
+      if (!(odataLink instanceof ODataInlineEntity) && !(odataLink instanceof ODataInlineEntitySet)) {
+        annotations((ODataLink) odataLink, link, reference);
+      }
+    }
+  }
+
+  @Override
   public Entity getEntity(final CommonODataEntity odataEntity, final Class<? extends Entity> reference) {
     final Entity entity = super.getEntity(odataEntity, reference);
     entity.setId(((ODataEntity) odataEntity).getReference());
+    annotations((ODataEntity) odataEntity, entity, reference);
     return entity;
   }
 
@@ -116,17 +179,8 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
 
     final Property propertyResource = ResourceFactory.newProperty(reference);
     propertyResource.setName(_property.getName());
-    propertyResource.setValue(getValue(_property.getValue(), reference));
-
-    if (_property.hasPrimitiveValue()) {
-      propertyResource.setType(_property.getPrimitiveValue().getTypeName());
-    } else if (_property.hasEnumValue()) {
-      propertyResource.setType(_property.getEnumValue().getTypeName());
-    } else if (_property.hasComplexValue()) {
-      propertyResource.setType(_property.getComplexValue().getTypeName());
-    } else if (_property.hasCollectionValue()) {
-      propertyResource.setType(_property.getCollectionValue().getTypeName());
-    }
+    updateValuable(propertyResource, _property, reference);
+    annotations(_property, propertyResource, reference);
 
     return propertyResource;
   }
@@ -150,6 +204,7 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
 
         final ODataLinkedComplexValue linked =
                 ((org.apache.olingo.commons.api.domain.v4.ODataValue) value).asLinkedComplex();
+        annotations(linked, lcValueResource, reference);
         links(linked, lcValueResource, reference);
 
         valueResource = lcValueResource;
@@ -158,6 +213,22 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
     return valueResource;
   }
 
+  private void odataAnnotations(final Annotatable annotatable, final ODataAnnotatatable odataAnnotatable) {
+    for (Annotation annotation : annotatable.getAnnotations()) {
+      FullQualifiedName fqn = null;
+      if (client instanceof EdmEnabledODataClient) {
+        final EdmTerm term = ((EdmEnabledODataClient) client).getEdm(null).
+                getTerm(new FullQualifiedName(annotation.getTerm()));
+        if (term != null) {
+          fqn = term.getType().getFullQualifiedName();
+        }
+      }
+
+      final ODataAnnotation odataAnnotation = new ODataAnnotationImpl(annotation.getTerm(),
+              (org.apache.olingo.commons.api.domain.v4.ODataValue) getODataValue(fqn, annotation, null, null));
+    }
+  }
+
   @Override
   public ODataEntitySet getODataEntitySet(final ResWrap<EntitySet> resource) {
     final ODataEntitySet entitySet = (ODataEntitySet) super.getODataEntitySet(resource);
@@ -167,52 +238,82 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
               ? resource.getPayload().getBaseURI() : resource.getContextURL().getServiceRoot();
       entitySet.setDeltaLink(URIUtils.getURI(base, resource.getPayload().getDeltaLink()));
     }
+    odataAnnotations(resource.getPayload(), entitySet);
 
     return entitySet;
   }
 
   @Override
+  protected void odataNavigationLinks(final EdmStructuredType edmType,
+          final Linked linked, final ODataLinked odataLinked, final String metadataETag, final URI base) {
+
+    super.odataNavigationLinks(edmType, linked, odataLinked, metadataETag, base);
+    for (org.apache.olingo.commons.api.domain.ODataLink link : odataLinked.getNavigationLinks()) {
+      if (!(link instanceof ODataInlineEntity) && !(link instanceof ODataInlineEntitySet)) {
+        odataAnnotations(linked.getNavigationLink(link.getName()), (ODataAnnotatatable) link);
+      }
+    }
+  }
+
+  @Override
   public ODataEntity getODataEntity(final ResWrap<Entity> resource) {
     final ODataEntity entity = (ODataEntity) super.getODataEntity(resource);
+
     entity.setReference(resource.getPayload().getId());
+    odataAnnotations(resource.getPayload(), entity);
+
     return entity;
   }
 
   @Override
-  public ODataProperty getODataProperty(final ResWrap<Property> property) {
-    return new ODataPropertyImpl(property.getPayload().getName(), getODataValue(property));
+  public ODataProperty getODataProperty(final ResWrap<Property> resource) {
+    final EdmTypeInfo typeInfo = buildTypeInfo(resource.getContextURL(), resource.getMetadataETag(),
+            resource.getPayload().getName(), resource.getPayload().getType());
+
+    final ODataProperty property = new ODataPropertyImpl(resource.getPayload().getName(),
+            getODataValue(typeInfo == null ? null : typeInfo.getFullQualifiedName(),
+                    resource.getPayload(), resource.getContextURL(), resource.getMetadataETag()));
+    odataAnnotations(resource.getPayload(), property);
+
+    return property;
   }
 
   @Override
-  protected ODataValue getODataValue(final ResWrap<Property> resource) {
-    final EdmTypeInfo typeInfo = buildTypeInfo(resource);
+  protected ODataValue getODataValue(final FullQualifiedName type,
+          final Valuable valuable, final ContextURL contextURL, final String metadataETag) {
+
+    // fixes enum values treated as primitive when no type information is available
+    if (client instanceof EdmEnabledODataClient && type != null) {
+      final EdmEnumType edmType = ((EdmEnabledODataClient) client).getEdm(metadataETag).getEnumType(type);
+      if (valuable.getValue().isPrimitive() && edmType != null) {
+        valuable.setValue(new EnumValueImpl(valuable.getValue().asPrimitive().get()));
+      }
+    }
 
     ODataValue value;
-    if (resource.getPayload().getValue().isEnum()) {
-      value = ((ODataClient) client).getObjectFactory().newEnumValue(
-              typeInfo == null ? null : typeInfo.getFullQualifiedName().toString(),
-              resource.getPayload().getValue().asEnum().get());
-    } else if (resource.getPayload().getValue().isLinkedComplex()) {
-      final ODataLinkedComplexValue lcValue = ((ODataClient) client).getObjectFactory().
-              newLinkedComplexValue(typeInfo == null ? null : typeInfo.getFullQualifiedName().toString());
-
-      for (Property property : resource.getPayload().getValue().asComplex().get()) {
-        lcValue.add(getODataProperty(
-                new ResWrap<Property>(resource.getContextURL(), resource.getMetadataETag(), property)));
+    if (valuable.getValue().isEnum()) {
+      value = ((ODataClient) client).getObjectFactory().newEnumValue(type == null ? null : type.toString(),
+              valuable.getValue().asEnum().get());
+    } else if (valuable.getValue().isLinkedComplex()) {
+      final ODataLinkedComplexValue lcValue =
+              ((ODataClient) client).getObjectFactory().newLinkedComplexValue(type == null ? null : type.toString());
+
+      for (Property property : valuable.getValue().asComplex().get()) {
+        lcValue.add(getODataProperty(new ResWrap<Property>(contextURL, metadataETag, property)));
       }
 
       EdmComplexType edmType = null;
-      if (client instanceof EdmEnabledODataClient && typeInfo != null) {
-        edmType = ((EdmEnabledODataClient) client).getEdm(resource.getMetadataETag()).
-                getComplexType(typeInfo.getFullQualifiedName());
+      if (client instanceof EdmEnabledODataClient && type != null) {
+        edmType = ((EdmEnabledODataClient) client).getEdm(metadataETag).getComplexType(type);
       }
 
-      odataNavigationLinks(edmType, resource.getPayload().getValue().asLinkedComplex(), lcValue,
-              resource.getMetadataETag(), resource.getContextURL() == null ? null : resource.getContextURL().getURI());
+      odataNavigationLinks(edmType, valuable.getValue().asLinkedComplex(), lcValue, metadataETag,
+              contextURL == null ? null : contextURL.getURI());
+      odataAnnotations(valuable.getValue().asLinkedComplex(), lcValue);
 
       value = lcValue;
     } else {
-      value = super.getODataValue(resource);
+      value = super.getODataValue(type, valuable, contextURL, metadataETag);
     }
 
     return value;
@@ -249,20 +350,26 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
       delta.getDeletedEntities().add(impl);
     }
 
+    odataAnnotations(resource.getPayload(), delta);
+
     for (DeltaLink link : resource.getPayload().getAddedLinks()) {
-      final ODataDeltaLinkImpl impl = new ODataDeltaLinkImpl();
+      final ODataDeltaLink impl = new ODataDeltaLinkImpl();
       impl.setRelationship(link.getRelationship());
       impl.setSource(URIUtils.getURI(base, link.getSource()));
       impl.setTarget(URIUtils.getURI(base, link.getTarget()));
 
+      odataAnnotations(link, impl);
+
       delta.getAddedLinks().add(impl);
     }
     for (DeltaLink link : resource.getPayload().getDeletedLinks()) {
-      final ODataDeltaLinkImpl impl = new ODataDeltaLinkImpl();
+      final ODataDeltaLink impl = new ODataDeltaLinkImpl();
       impl.setRelationship(link.getRelationship());
       impl.setSource(URIUtils.getURI(base, link.getSource()));
       impl.setTarget(URIUtils.getURI(base, link.getTarget()));
 
+      odataAnnotations(link, impl);
+
       delta.getDeletedLinks().add(impl);
     }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/EntityTest.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/EntityTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/EntityTest.java
index 212c527..537dfcd 100644
--- a/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/EntityTest.java
+++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/EntityTest.java
@@ -33,10 +33,12 @@ import org.apache.olingo.commons.api.data.ResWrap;
 import org.apache.olingo.commons.api.domain.ODataInlineEntitySet;
 import org.apache.olingo.commons.api.domain.ODataLink;
 import org.apache.olingo.commons.api.domain.ODataLinkType;
+import org.apache.olingo.commons.api.domain.v4.ODataAnnotation;
 import org.apache.olingo.commons.api.domain.v4.ODataEntity;
 import org.apache.olingo.commons.api.domain.v4.ODataLinkedComplexValue;
 import org.apache.olingo.commons.api.domain.v4.ODataProperty;
 import org.apache.olingo.commons.api.domain.v4.ODataValue;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
 import org.apache.olingo.commons.api.format.ODataPubFormat;
 import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
 import org.apache.olingo.commons.core.edm.primitivetype.EdmDuration;
@@ -94,8 +96,8 @@ public class EntityTest extends AbstractTest {
     // operations won't get serialized
     entity.getOperations().clear();
     final ODataEntity written = getClient().getBinder().getODataEntity(
-            new ResWrap<Entity>((URI) null, null, getClient().
-            getBinder().getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
+            new ResWrap<Entity>((URI) null, null, getClient().getBinder().
+                    getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
     assertEquals(entity, written);
   }
 
@@ -130,8 +132,8 @@ public class EntityTest extends AbstractTest {
     // operations won't get serialized
     entity.getOperations().clear();
     final ODataEntity written = getClient().getBinder().getODataEntity(
-            new ResWrap<Entity>((URI) null, null, getClient().
-            getBinder().getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
+            new ResWrap<Entity>((URI) null, null, getClient().getBinder().
+                    getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
     assertEquals(entity, written);
   }
 
@@ -165,8 +167,8 @@ public class EntityTest extends AbstractTest {
     // operations won't get serialized
     entity.getOperations().clear();
     final ODataEntity written = getClient().getBinder().getODataEntity(
-            new ResWrap<Entity>((URI) null, null, getClient().
-            getBinder().getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
+            new ResWrap<Entity>((URI) null, null, getClient().getBinder().
+                    getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
     assertEquals(entity, written);
   }
 
@@ -192,8 +194,8 @@ public class EntityTest extends AbstractTest {
     assertEquals("\"8zOOKKvgOtptr4gt8IrnapX3jds=\"", entity.getMediaETag());
 
     final ODataEntity written = getClient().getBinder().getODataEntity(
-            new ResWrap<Entity>((URI) null, null, getClient().
-            getBinder().getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
+            new ResWrap<Entity>((URI) null, null, getClient().getBinder().
+                    getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
     assertEquals(entity, written);
   }
 
@@ -219,8 +221,8 @@ public class EntityTest extends AbstractTest {
     assertNotNull(editMedia);
 
     final ODataEntity written = getClient().getBinder().getODataEntity(
-            new ResWrap<Entity>((URI) null, null, getClient().
-            getBinder().getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
+            new ResWrap<Entity>((URI) null, null, getClient().getBinder().
+                    getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
     assertEquals(entity, written);
   }
 
@@ -243,8 +245,8 @@ public class EntityTest extends AbstractTest {
     assertNotNull(entity.getReference());
 
     final ODataEntity written = getClient().getBinder().getODataEntity(
-            new ResWrap<Entity>((URI) null, null, getClient().
-            getBinder().getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
+            new ResWrap<Entity>((URI) null, null, getClient().getBinder().
+                    getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
     assertEquals(entity, written);
   }
 
@@ -271,8 +273,8 @@ public class EntityTest extends AbstractTest {
     // ETag is not serialized
     entity.setETag(null);
     final ODataEntity written = getClient().getBinder().getODataEntity(
-            new ResWrap<Entity>((URI) null, null, getClient().
-            getBinder().getEntity(entity, ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
+            new ResWrap<Entity>((URI) null, null, getClient().getBinder().getEntity(entity,
+                            ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
     assertEquals(entity, written);
   }
 
@@ -285,4 +287,51 @@ public class EntityTest extends AbstractTest {
   public void jsonComplexNavigationProperties() {
     complexNavigationProperties(ODataPubFormat.JSON);
   }
+
+  private void annotated(final ODataPubFormat format) throws EdmPrimitiveTypeException {
+    final InputStream input = getClass().getResourceAsStream("annotated." + getSuffix(format));
+    final ODataEntity entity = getClient().getBinder().getODataEntity(
+            getClient().getDeserializer().toEntity(input, format));
+    assertNotNull(entity);
+
+    assertFalse(entity.getAnnotations().isEmpty());
+
+    ODataAnnotation annotation = entity.getAnnotations().get(0);
+    assertEquals("com.contoso.display.highlight", annotation.getTerm());
+    assertEquals(true, annotation.getPrimitiveValue().toCastValue(Boolean.class));
+
+    annotation = entity.getAnnotations().get(0);
+    assertEquals("com.contoso.PersonalInfo.PhoneNumbers", annotation.getTerm());
+    assertTrue(annotation.hasCollectionValue());
+
+    annotation = entity.getProperty("LastName").getAnnotations().get(0);
+    assertEquals("com.contoso.display.styleType", annotation.getTerm());
+    assertTrue(annotation.hasComplexValue());
+
+    final ODataLink orders = entity.getNavigationLink("Orders");
+    assertFalse(((org.apache.olingo.commons.api.domain.v4.ODataLink) orders).getAnnotations().isEmpty());
+
+    annotation = ((org.apache.olingo.commons.api.domain.v4.ODataLink) orders).getAnnotations().get(0);
+    assertEquals("com.contoso.display.style", annotation.getTerm());
+    assertEquals("com.contoso.display.styleType", annotation.getValue().getTypeName());
+    assertTrue(annotation.hasComplexValue());
+    assertEquals(2,
+            annotation.getValue().asLinkedComplex().get("order").getPrimitiveValue().toCastValue(Integer.class), 0);
+
+    final ODataEntity written = getClient().getBinder().getODataEntity(
+            new ResWrap<Entity>((URI) null, null, getClient().getBinder().getEntity(entity,
+                            ResourceFactory.entityClassForFormat(format == ODataPubFormat.ATOM))));
+    assertEquals(entity, written);
+  }
+
+  @Test
+  public void atomAnnotated() {
+    complexNavigationProperties(ODataPubFormat.ATOM);
+  }
+
+  @Test
+  public void jsonAnnotated() {
+    complexNavigationProperties(ODataPubFormat.JSON);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Linked.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Linked.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Linked.java
index b5c7db7..a86ef8f 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Linked.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Linked.java
@@ -23,6 +23,14 @@ import java.util.List;
 public interface Linked {
 
   /**
+   * Gets association link with given name, if available, otherwise <tt>null</tt>.
+   *
+   * @param name candidate link name
+   * @return association link with given name, if available, otherwise <tt>null</tt>
+   */
+  Link getAssociationLink(String name);
+
+  /**
    * Gets association links.
    *
    * @return association links.
@@ -30,6 +38,14 @@ public interface Linked {
   List<Link> getAssociationLinks();
 
   /**
+   * Gets navigation link with given name, if available, otherwise <tt>null</tt>.
+   *
+   * @param name candidate link name
+   * @return navigation link with given name, if available, otherwise <tt>null</tt>
+   */
+  Link getNavigationLink(String name);
+
+  /**
    * Gets navigation links.
    *
    * @return links.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataAnnotation.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataAnnotation.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataAnnotation.java
index d90ff4f..ea70546 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataAnnotation.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataAnnotation.java
@@ -18,11 +18,7 @@
  */
 package org.apache.olingo.commons.api.domain.v4;
 
-import org.apache.olingo.commons.api.domain.ODataCollectionValue;
-import org.apache.olingo.commons.api.domain.ODataComplexValue;
-import org.apache.olingo.commons.api.domain.ODataPrimitiveValue;
-
-public interface ODataAnnotation {
+public interface ODataAnnotation extends ODataValuable {
 
   /**
    * Returns annotation name.
@@ -31,73 +27,4 @@ public interface ODataAnnotation {
    */
   String getTerm();
 
-  /**
-   * Returns annotation value.
-   *
-   * @return annotation value.
-   */
-  ODataValue getValue();
-
-  /**
-   * Checks if has null value.
-   *
-   * @return 'TRUE' if has null value; 'FALSE' otherwise.
-   */
-  boolean hasNullValue();
-
-  /**
-   * Checks if has primitive value.
-   *
-   * @return 'TRUE' if has primitive value; 'FALSE' otherwise.
-   */
-  boolean hasPrimitiveValue();
-
-  /**
-   * Gets primitive value.
-   *
-   * @return primitive value if exists; null otherwise.
-   */
-  ODataPrimitiveValue getPrimitiveValue();
-
-  /**
-   * Checks if has collection value.
-   *
-   * @return 'TRUE' if has collection value; 'FALSE' otherwise.
-   */
-  boolean hasCollectionValue();
-
-  /**
-   * Gets collection value.
-   *
-   * @return collection value if exists; null otherwise.
-   */
-  ODataCollectionValue<ODataValue> getCollectionValue();
-
-  /**
-   * Checks if has complex value.
-   *
-   * @return 'TRUE' if has complex value; 'FALSE' otherwise.
-   */
-  boolean hasComplexValue();
-
-  /**
-   * Gets complex value.
-   *
-   * @return complex value if exists; null otherwise.
-   */
-  ODataComplexValue<ODataProperty> getComplexValue();
-
-  /**
-   * Checks if has enum value.
-   *
-   * @return 'TRUE' if has enum value; 'FALSE' otherwise.
-   */
-  boolean hasEnumValue();
-
-  /**
-   * Gets enum value.
-   *
-   * @return enum value if exists; null otherwise.
-   */
-  ODataEnumValue getEnumValue();
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataProperty.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataProperty.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataProperty.java
index eaff66c..09507ba 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataProperty.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataProperty.java
@@ -19,43 +19,6 @@
 package org.apache.olingo.commons.api.domain.v4;
 
 import org.apache.olingo.commons.api.domain.CommonODataProperty;
-import org.apache.olingo.commons.api.domain.ODataCollectionValue;
-import org.apache.olingo.commons.api.domain.ODataComplexValue;
 
-public interface ODataProperty extends CommonODataProperty, ODataAnnotatatable {
-
-  /**
-   * Gets collection value.
-   *
-   * @return collection value if exists; null otherwise.
-   */
-  ODataCollectionValue<ODataValue> getCollectionValue();
-
-  /**
-   * Gets complex value.
-   *
-   * @return complex value if exists; null otherwise.
-   */
-  ODataComplexValue<ODataProperty> getComplexValue();
-  
-  /**
-   * Gets complex value with link information (if available).
-   *
-   * @return complex value if exists; null otherwise.
-   */
-  ODataLinkedComplexValue getLinkedComplexValue();
-
-  /**
-   * Checks if has enum value.
-   *
-   * @return 'TRUE' if has enum value; 'FALSE' otherwise.
-   */
-  boolean hasEnumValue();
-
-  /**
-   * Gets enum value.
-   *
-   * @return enum value if exists; null otherwise.
-   */
-  ODataEnumValue getEnumValue();
+public interface ODataProperty extends CommonODataProperty, ODataAnnotatatable, ODataValuable {
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataValuable.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataValuable.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataValuable.java
new file mode 100644
index 0000000..f5b4277
--- /dev/null
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/domain/v4/ODataValuable.java
@@ -0,0 +1,104 @@
+/*
+ * 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.commons.api.domain.v4;
+
+import org.apache.olingo.commons.api.domain.ODataCollectionValue;
+import org.apache.olingo.commons.api.domain.ODataComplexValue;
+import org.apache.olingo.commons.api.domain.ODataPrimitiveValue;
+
+public interface ODataValuable {
+
+  /**
+   * Returns annotation value.
+   *
+   * @return annotation value.
+   */
+  ODataValue getValue();
+
+  /**
+   * Checks if has null value.
+   *
+   * @return 'TRUE' if has null value; 'FALSE' otherwise.
+   */
+  boolean hasNullValue();
+
+  /**
+   * Checks if has primitive value.
+   *
+   * @return 'TRUE' if has primitive value; 'FALSE' otherwise.
+   */
+  boolean hasPrimitiveValue();
+
+  /**
+   * Gets primitive value.
+   *
+   * @return primitive value if exists; null otherwise.
+   */
+  ODataPrimitiveValue getPrimitiveValue();
+
+  /**
+   * Checks if has collection value.
+   *
+   * @return 'TRUE' if has collection value; 'FALSE' otherwise.
+   */
+  boolean hasCollectionValue();
+
+  /**
+   * Gets collection value.
+   *
+   * @return collection value if exists; null otherwise.
+   */
+  ODataCollectionValue<ODataValue> getCollectionValue();
+
+  /**
+   * Checks if has complex value.
+   *
+   * @return 'TRUE' if has complex value; 'FALSE' otherwise.
+   */
+  boolean hasComplexValue();
+
+  /**
+   * Gets complex value.
+   *
+   * @return complex value if exists; null otherwise.
+   */
+  ODataComplexValue<ODataProperty> getComplexValue();
+
+  /**
+   * Gets complex value with link information (if available).
+   *
+   * @return complex value if exists; null otherwise.
+   */
+  ODataLinkedComplexValue getLinkedComplexValue();
+
+  /**
+   * Checks if has enum value.
+   *
+   * @return 'TRUE' if has enum value; 'FALSE' otherwise.
+   */
+  boolean hasEnumValue();
+
+  /**
+   * Gets enum value.
+   *
+   * @return enum value if exists; null otherwise.
+   */
+  ODataEnumValue getEnumValue();
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractEntity.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractEntity.java
index fc89504..21ada97 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractEntity.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/AbstractEntity.java
@@ -96,12 +96,34 @@ public abstract class AbstractEntity extends AbstractODataObject implements Enti
     this.editLink = editLink;
   }
 
+  private Link getOneByTitle(final String name, final List<Link> links) {
+    Link result = null;
+
+    for (Link link : links) {
+      if (name.equals(link.getTitle())) {
+        result = link;
+      }
+    }
+
+    return result;
+  }
+
+  @Override
+  public Link getAssociationLink(final String name) {
+    return getOneByTitle(name, associationLinks);
+  }
+
   @Override
   public List<Link> getAssociationLinks() {
     return associationLinks;
   }
 
   @Override
+  public Link getNavigationLink(final String name) {
+    return getOneByTitle(name, navigationLinks);
+  }
+
+  @Override
   public List<Link> getNavigationLinks() {
     return navigationLinks;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/LinkedComplexValueImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/LinkedComplexValueImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/LinkedComplexValueImpl.java
index a1bc0c8..d37741a 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/LinkedComplexValueImpl.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/LinkedComplexValueImpl.java
@@ -37,12 +37,34 @@ public class LinkedComplexValueImpl extends ComplexValueImpl implements LinkedCo
     return true;
   }
 
+  private Link getOneByTitle(final String name, final List<Link> links) {
+    Link result = null;
+
+    for (Link link : links) {
+      if (name.equals(link.getTitle())) {
+        result = link;
+      }
+    }
+
+    return result;
+  }
+
+  @Override
+  public Link getAssociationLink(final String name) {
+    return getOneByTitle(name, associationLinks);
+  }
+
   @Override
   public List<Link> getAssociationLinks() {
     return associationLinks;
   }
 
   @Override
+  public Link getNavigationLink(final String name) {
+    return getOneByTitle(name, navigationLinks);
+  }
+
+  @Override
   public List<Link> getNavigationLinks() {
     return navigationLinks;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/AbstractODataProperty.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/AbstractODataProperty.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/AbstractODataProperty.java
index 532303c..e2e2036 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/AbstractODataProperty.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/AbstractODataProperty.java
@@ -121,25 +121,16 @@ public abstract class AbstractODataProperty implements CommonODataProperty {
     return !hasNullValue() && this.value.isCollection();
   }
 
-  /**
-   * {@inheritDoc }
-   */
   @Override
   public boolean equals(final Object obj) {
     return EqualsBuilder.reflectionEquals(this, obj);
   }
 
-  /**
-   * {@inheritDoc }
-   */
   @Override
   public int hashCode() {
     return HashCodeBuilder.reflectionHashCode(this);
   }
 
-  /**
-   * {@inheritDoc }
-   */
   @Override
   public String toString() {
     return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataAnnotationImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataAnnotationImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataAnnotationImpl.java
new file mode 100644
index 0000000..0814cc0
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataAnnotationImpl.java
@@ -0,0 +1,102 @@
+/*
+ * 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.commons.core.domain.v4;
+
+import org.apache.olingo.commons.api.domain.ODataCollectionValue;
+import org.apache.olingo.commons.api.domain.ODataComplexValue;
+import org.apache.olingo.commons.api.domain.ODataPrimitiveValue;
+import org.apache.olingo.commons.api.domain.v4.ODataAnnotation;
+import org.apache.olingo.commons.api.domain.v4.ODataEnumValue;
+import org.apache.olingo.commons.api.domain.v4.ODataLinkedComplexValue;
+import org.apache.olingo.commons.api.domain.v4.ODataProperty;
+import org.apache.olingo.commons.api.domain.v4.ODataValuable;
+import org.apache.olingo.commons.api.domain.v4.ODataValue;
+
+public class ODataAnnotationImpl implements ODataAnnotation {
+
+  private final String term;
+
+  private final ODataValuable valuable;
+
+  public ODataAnnotationImpl(final String term, final ODataValue value) {
+    this.term = term;
+    this.valuable = new ODataValuableImpl(value);
+  }
+
+  @Override
+  public String getTerm() {
+    return term;
+  }
+
+  @Override
+  public ODataValue getValue() {
+    return valuable.getValue();
+  }
+
+  @Override
+  public boolean hasNullValue() {
+    return valuable.hasNullValue();
+  }
+
+  @Override
+  public boolean hasPrimitiveValue() {
+    return valuable.hasPrimitiveValue();
+  }
+
+  @Override
+  public ODataPrimitiveValue getPrimitiveValue() {
+    return valuable.getPrimitiveValue();
+  }
+
+  @Override
+  public boolean hasCollectionValue() {
+    return valuable.hasCollectionValue();
+  }
+
+  @Override
+  public ODataCollectionValue<ODataValue> getCollectionValue() {
+    return valuable.getCollectionValue();
+  }
+
+  @Override
+  public boolean hasComplexValue() {
+    return valuable.hasComplexValue();
+  }
+
+  @Override
+  public ODataComplexValue<ODataProperty> getComplexValue() {
+    return valuable.getComplexValue();
+  }
+
+  @Override
+  public ODataLinkedComplexValue getLinkedComplexValue() {
+    return valuable.getLinkedComplexValue();
+  }
+
+  @Override
+  public boolean hasEnumValue() {
+    return valuable.hasEnumValue();
+  }
+
+  @Override
+  public ODataEnumValue getEnumValue() {
+    return valuable.getEnumValue();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataPropertyImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataPropertyImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataPropertyImpl.java
index 8fa9727..35962e4 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataPropertyImpl.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataPropertyImpl.java
@@ -26,6 +26,7 @@ import org.apache.olingo.commons.api.domain.v4.ODataAnnotation;
 import org.apache.olingo.commons.api.domain.v4.ODataEnumValue;
 import org.apache.olingo.commons.api.domain.v4.ODataLinkedComplexValue;
 import org.apache.olingo.commons.api.domain.v4.ODataProperty;
+import org.apache.olingo.commons.api.domain.v4.ODataValuable;
 import org.apache.olingo.commons.api.domain.v4.ODataValue;
 import org.apache.olingo.commons.core.domain.AbstractODataProperty;
 
@@ -33,44 +34,43 @@ public class ODataPropertyImpl extends AbstractODataProperty implements ODataPro
 
   private static final long serialVersionUID = 4851331227420757747L;
 
+  private final ODataValuable valuable;
+
   private final List<ODataAnnotation> annotations = new ArrayList<ODataAnnotation>();
 
   public ODataPropertyImpl(final String name, final org.apache.olingo.commons.api.domain.ODataValue value) {
     super(name, value);
+    this.valuable = new ODataValuableImpl((ODataValue) value);
+  }
+
+  @Override
+  public ODataValue getValue() {
+    return valuable.getValue();
   }
 
   @Override
   public boolean hasEnumValue() {
-    return !hasNullValue() && getValue() instanceof org.apache.olingo.commons.api.domain.v4.ODataValue
-            && ((org.apache.olingo.commons.api.domain.v4.ODataValue) getValue()).isEnum();
+    return valuable.hasEnumValue();
   }
 
   @Override
   public ODataEnumValue getEnumValue() {
-    return hasEnumValue()
-            ? ((org.apache.olingo.commons.api.domain.v4.ODataValue) getValue()).asEnum()
-            : null;
+    return valuable.getEnumValue();
   }
 
   @Override
   public ODataComplexValue<ODataProperty> getComplexValue() {
-    return hasComplexValue()
-            ? getValue().<ODataProperty>asComplex()
-            : null;
+    return valuable.getComplexValue();
   }
 
   @Override
   public ODataLinkedComplexValue getLinkedComplexValue() {
-    return hasComplexValue() && getValue() instanceof org.apache.olingo.commons.api.domain.v4.ODataValue
-            ? ((org.apache.olingo.commons.api.domain.v4.ODataValue) getValue()).asLinkedComplex()
-            : null;
+    return valuable.getLinkedComplexValue();
   }
 
   @Override
   public ODataCollectionValue<ODataValue> getCollectionValue() {
-    return hasCollectionValue()
-            ? getValue().<ODataValue>asCollection()
-            : null;
+    return valuable.getCollectionValue();
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8caf3fec/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataValuableImpl.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataValuableImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataValuableImpl.java
new file mode 100644
index 0000000..8a08e82
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/domain/v4/ODataValuableImpl.java
@@ -0,0 +1,120 @@
+/*
+ * 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.commons.core.domain.v4;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.olingo.commons.api.domain.ODataCollectionValue;
+import org.apache.olingo.commons.api.domain.ODataComplexValue;
+import org.apache.olingo.commons.api.domain.ODataPrimitiveValue;
+import org.apache.olingo.commons.api.domain.v4.ODataEnumValue;
+import org.apache.olingo.commons.api.domain.v4.ODataLinkedComplexValue;
+import org.apache.olingo.commons.api.domain.v4.ODataProperty;
+import org.apache.olingo.commons.api.domain.v4.ODataValuable;
+import org.apache.olingo.commons.api.domain.v4.ODataValue;
+
+public class ODataValuableImpl implements ODataValuable {
+
+  private final ODataValue value;
+
+  public ODataValuableImpl(final ODataValue value) {
+    this.value = value;
+  }
+
+  @Override
+  public ODataValue getValue() {
+    return value;
+  }
+
+  @Override
+  public boolean hasNullValue() {
+    return this.value == null;
+  }
+
+  @Override
+  public boolean hasPrimitiveValue() {
+    return !hasNullValue() && this.value.isPrimitive();
+  }
+
+  @Override
+  public ODataPrimitiveValue getPrimitiveValue() {
+    return hasPrimitiveValue() ? this.value.asPrimitive() : null;
+  }
+
+  @Override
+  public boolean hasCollectionValue() {
+    return !hasNullValue() && this.value.isCollection();
+  }
+
+  @Override
+  public ODataCollectionValue<ODataValue> getCollectionValue() {
+    return hasCollectionValue()
+            ? getValue().<ODataValue>asCollection()
+            : null;
+  }
+
+  @Override
+  public boolean hasComplexValue() {
+    return !hasNullValue() && this.value.isComplex();
+  }
+
+  @Override
+  public ODataComplexValue<ODataProperty> getComplexValue() {
+    return hasComplexValue()
+            ? getValue().<ODataProperty>asComplex()
+            : null;
+  }
+
+  @Override
+  public ODataLinkedComplexValue getLinkedComplexValue() {
+    return hasComplexValue()
+            ? getValue().asLinkedComplex()
+            : null;
+  }
+
+  @Override
+  public boolean hasEnumValue() {
+    return !hasNullValue() && getValue().isEnum();
+  }
+
+  @Override
+  public ODataEnumValue getEnumValue() {
+    return hasEnumValue()
+            ? getValue().asEnum()
+            : null;
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    return EqualsBuilder.reflectionEquals(this, obj);
+  }
+
+  @Override
+  public int hashCode() {
+    return HashCodeBuilder.reflectionHashCode(this);
+  }
+
+  @Override
+  public String toString() {
+    return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
+  }
+
+}